diff --git a/app/src/main/java/sh/sar/basedbank/ui/home/CircularNavFragment.kt b/app/src/main/java/sh/sar/basedbank/ui/home/CircularNavFragment.kt index 9981451..016c529 100644 --- a/app/src/main/java/sh/sar/basedbank/ui/home/CircularNavFragment.kt +++ b/app/src/main/java/sh/sar/basedbank/ui/home/CircularNavFragment.kt @@ -23,6 +23,8 @@ import kotlin.math.* class CircularNavFragment : Fragment() { + private var wheelView: CircularWheelView? = null + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -47,9 +49,10 @@ class CircularNavFragment : Fragment() { android.widget.LinearLayout.LayoutParams.MATCH_PARENT, 0, 1f ) } - val wheelView = CircularWheelView(ctx).apply { + val prefs = ctx.getSharedPreferences("prefs", Context.MODE_PRIVATE) + wheelView = CircularWheelView(ctx).apply { layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT) - val prefs = ctx.getSharedPreferences("prefs", Context.MODE_PRIVATE) + wheelAngle = prefs.getFloat("circular_wheel_angle", 0f) val savedSlots = NavCustomization.getCircularSlots(prefs).map { id -> val def = NavCustomization.ALL_SWAPPABLE.find { it.id == id }!! CircularWheelView.WheelItem(def.id, def.iconRes, ctx.getString(def.titleRes)) @@ -112,6 +115,10 @@ class CircularNavFragment : Fragment() { override fun onPause() { super.onPause() + wheelView?.let { wv -> + requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE) + .edit().putFloat("circular_wheel_angle", wv.wheelAngle).apply() + } val toolbar = requireActivity().findViewById(R.id.toolbar) toolbar.findViewWithTag("wheel_title")?.let { toolbar.removeView(it) } requireActivity().invalidateOptionsMenu() @@ -181,7 +188,7 @@ class CircularWheelView @JvmOverloads constructor( // ---- touch & fling ---------------------------------------------------- - private var wheelAngle = 0f + var wheelAngle = 0f private var isDragging = false private var snapAnimator: ValueAnimator? = null @@ -358,7 +365,7 @@ class CircularWheelView @JvmOverloads constructor( dist <= innerRadius -> onCenterClick?.invoke() dist <= outerRadius -> { val idx = segmentAt(event.x, event.y) - if (idx in items.indices) onItemClick?.invoke(items[idx].navId) + if (idx in items.indices) animateToSixOClock(idx) { onItemClick?.invoke(items[idx].navId) } } } } else { @@ -423,6 +430,30 @@ class CircularWheelView @JvmOverloads constructor( return (a / (360f / items.size)).toInt() % items.size } + private fun animateToSixOClock(index: Int, onDone: () -> Unit) { + val segDeg = 360f / items.size.coerceAtLeast(1) + val midDeg = index * segDeg + segDeg / 2f + // delta needed so this segment's midpoint lands at 90° (6 o'clock in math coords) + var delta = (90f - midDeg) - wheelAngle + // normalise to shortest path [-180, 180] + delta = ((delta % 360f) + 360f) % 360f + if (delta > 180f) delta -= 360f + val endAngle = wheelAngle + delta + + snapAnimator?.cancel() + snapAnimator = ValueAnimator.ofFloat(wheelAngle, endAngle).apply { + duration = 350 + interpolator = DecelerateInterpolator() + addUpdateListener { wheelAngle = it.animatedValue as Float; invalidate() } + addListener(object : AnimatorListenerAdapter() { + private var cancelled = false + override fun onAnimationCancel(a: Animator) { cancelled = true } + override fun onAnimationEnd(a: Animator) { if (!cancelled) onDone() } + }) + start() + } + } + private fun snapToNearest() { val segDeg = 360f / items.size.coerceAtLeast(1) val target = (wheelAngle / segDeg).roundToInt() * segDeg