summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Oram <dev@mitmaro.ca>2022-12-20 09:35:54 -0330
committerTim Oram <dev@mitmaro.ca>2022-12-20 10:11:25 -0330
commitfb9a1c025dec1650802fb8952844c31181f104eb (patch)
treec53f786087efc485eb9e56af52dea7d22225e87a
parent2feadd31c3c4addc3b564549b735c02bb9c10cb8 (diff)
Add spin indicator component
-rw-r--r--src/core/src/components/mod.rs2
-rw-r--r--src/core/src/components/spin_indicator/mod.rs76
2 files changed, 78 insertions, 0 deletions
diff --git a/src/core/src/components/mod.rs b/src/core/src/components/mod.rs
index 54d5837..21dd23c 100644
--- a/src/core/src/components/mod.rs
+++ b/src/core/src/components/mod.rs
@@ -4,3 +4,5 @@ pub(crate) mod edit;
pub(crate) mod help;
pub(crate) mod search_bar;
mod shared;
+#[allow(dead_code)]
+pub(crate) mod spin_indicator;
diff --git a/src/core/src/components/spin_indicator/mod.rs b/src/core/src/components/spin_indicator/mod.rs
new file mode 100644
index 0000000..e73048b
--- /dev/null
+++ b/src/core/src/components/spin_indicator/mod.rs
@@ -0,0 +1,76 @@
+use std::time::{Duration, Instant};
+
+const INDICATOR_CHARACTERS: [&str; 4] = ["-", "\\", "|", "/"];
+const ANIMATE_SPEED: Duration = Duration::from_millis(100);
+
+pub(crate) struct SpinIndicator {
+ index: u8,
+ last_refreshed_at: Instant,
+}
+
+impl SpinIndicator {
+ pub(crate) fn new() -> Self {
+ Self {
+ index: 0,
+ last_refreshed_at: Instant::now(),
+ }
+ }
+
+ pub(crate) fn refresh(&mut self) {
+ if self.last_refreshed_at.elapsed() >= ANIMATE_SPEED {
+ self.last_refreshed_at = Instant::now();
+ self.index = if self.index == 3 { 0 } else { self.index + 1 }
+ }
+ }
+
+ pub(crate) fn indicator(&self) -> String {
+ format!("({})", INDICATOR_CHARACTERS[self.index as usize])
+ }
+}
+#[cfg(test)]
+mod tests {
+ use std::ops::{Add, Sub};
+
+ const SAFE_TEST_DURATION: Duration = Duration::from_secs(60);
+
+ use super::*;
+
+ #[test]
+ fn does_not_advance_if_duration_has_not_elapsed() {
+ let mut indicator = SpinIndicator::new();
+ // this test is unlikely to finish before this elapsed time
+ indicator.last_refreshed_at = Instant::now().add(SAFE_TEST_DURATION);
+ assert_eq!(indicator.indicator(), "(-)");
+ indicator.refresh();
+ assert_eq!(indicator.indicator(), "(-)");
+ }
+
+ #[test]
+ fn does_not_advance_if_duration_has_elapsed() {
+ let mut indicator = SpinIndicator::new();
+ indicator.last_refreshed_at = Instant::now().sub(SAFE_TEST_DURATION);
+ assert_eq!(indicator.indicator(), "(-)");
+ indicator.refresh();
+ assert_eq!(indicator.indicator(), "(\\)");
+ }
+
+ const INDICATOR_CHARACTERS: [&str; 4] = ["-", "\\", "|", "/"];
+ #[test]
+ fn full_animation() {
+ let mut indicator = SpinIndicator::new();
+ indicator.last_refreshed_at = Instant::now().sub(SAFE_TEST_DURATION);
+ assert_eq!(indicator.indicator(), "(-)");
+ indicator.refresh();
+ indicator.last_refreshed_at = indicator.last_refreshed_at.sub(SAFE_TEST_DURATION);
+ assert_eq!(indicator.indicator(), "(\\)");
+ indicator.refresh();
+ indicator.last_refreshed_at = indicator.last_refreshed_at.sub(SAFE_TEST_DURATION);
+ assert_eq!(indicator.indicator(), "(|)");
+ indicator.refresh();
+ indicator.last_refreshed_at = indicator.last_refreshed_at.sub(SAFE_TEST_DURATION);
+ assert_eq!(indicator.indicator(), "(/)");
+ indicator.refresh();
+ indicator.last_refreshed_at = indicator.last_refreshed_at.sub(SAFE_TEST_DURATION);
+ assert_eq!(indicator.indicator(), "(-)");
+ }
+}