about summary refs log tree commit diff
path: root/src/components/anim
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2024-07-03 19:05:19 -0700
committerGitHub <noreply@github.com>2024-07-04 03:05:19 +0100
commit0ed99b840d8de13465f010a6434dea50c72b3f62 (patch)
tree75ebec28653a081793ca0cbca0c428a816980c6a /src/components/anim
parentaa7117edb60711a67464f7559118334185f01680 (diff)
downloadvoidsky-0ed99b840d8de13465f010a6434dea50c72b3f62.tar.zst
New user progress guides (#4716)
* Add the animated checkmark svg

* Add progress guide list and task components

* Add ProgressGuide Toast component

* Implement progress-guide controller

* Add 7 follows to the progress guide

* Wire up action captures

* Wire up progress-guide persistence

* Trigger progress guide on account creation

* Clear the progress guide from storage on complete

* Add progress guide interstitial, put behind gate

* Fix: read progress guide state from prefs

* Some defensive type checks

* Create separate toast for completion

* List tweaks

* Only show on Discover

* Spacing and progress tweaks

* Completely hide when complete

* Capture the progress guide in local state, and only render toasts while guide is active

* Fix: ensure persisted hydrates into local state

* Gate

---------

Co-authored-by: Eric Bailey <git@esb.lol>
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
Diffstat (limited to 'src/components/anim')
-rw-r--r--src/components/anim/AnimatedCheck.tsx92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/components/anim/AnimatedCheck.tsx b/src/components/anim/AnimatedCheck.tsx
new file mode 100644
index 000000000..7fdfc14cf
--- /dev/null
+++ b/src/components/anim/AnimatedCheck.tsx
@@ -0,0 +1,92 @@
+import React from 'react'
+import Animated, {
+  Easing,
+  useAnimatedProps,
+  useSharedValue,
+  withDelay,
+  withTiming,
+} from 'react-native-reanimated'
+import Svg, {Circle, Path} from 'react-native-svg'
+
+import {Props, useCommonSVGProps} from '#/components/icons/common'
+
+const AnimatedPath = Animated.createAnimatedComponent(Path)
+const AnimatedCircle = Animated.createAnimatedComponent(Circle)
+
+const PATH = 'M14.1 27.2l7.1 7.2 16.7-16.8'
+
+export interface AnimatedCheckRef {
+  play(cb?: () => void): void
+}
+
+export interface AnimatedCheckProps extends Props {
+  playOnMount?: boolean
+}
+
+export const AnimatedCheck = React.forwardRef<
+  AnimatedCheckRef,
+  AnimatedCheckProps
+>(function AnimatedCheck({playOnMount, ...props}, ref) {
+  const {fill, size, style, ...rest} = useCommonSVGProps(props)
+  const circleAnim = useSharedValue(0)
+  const checkAnim = useSharedValue(0)
+
+  const circleAnimatedProps = useAnimatedProps(() => ({
+    strokeDashoffset: 166 - circleAnim.value * 166,
+  }))
+  const checkAnimatedProps = useAnimatedProps(() => ({
+    strokeDashoffset: 48 - 48 * checkAnim.value,
+  }))
+
+  const play = React.useCallback(
+    (cb?: () => void) => {
+      circleAnim.value = 0
+      checkAnim.value = 0
+
+      circleAnim.value = withTiming(1, {duration: 500, easing: Easing.linear})
+      checkAnim.value = withDelay(
+        500,
+        withTiming(1, {duration: 300, easing: Easing.linear}, cb),
+      )
+    },
+    [circleAnim, checkAnim],
+  )
+
+  React.useImperativeHandle(ref, () => ({
+    play,
+  }))
+
+  React.useEffect(() => {
+    if (playOnMount) {
+      play()
+    }
+  }, [play, playOnMount])
+
+  return (
+    <Svg
+      fill="none"
+      {...rest}
+      viewBox="0 0 52 52"
+      width={size}
+      height={size}
+      style={style}>
+      <AnimatedCircle
+        animatedProps={circleAnimatedProps}
+        cx="26"
+        cy="26"
+        r="24"
+        fill="none"
+        stroke={fill}
+        strokeWidth={4}
+        strokeDasharray={166}
+      />
+      <AnimatedPath
+        animatedProps={checkAnimatedProps}
+        stroke={fill}
+        d={PATH}
+        strokeWidth={4}
+        strokeDasharray={48}
+      />
+    </Svg>
+  )
+})