auto rotate wheel when tapping icon

This commit is contained in:
2026-06-03 04:12:58 +05:00
parent 5f6ec236bf
commit fc7fa420b2
@@ -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<com.google.android.material.appbar.MaterialToolbar>(R.id.toolbar)
toolbar.findViewWithTag<android.view.View>("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