diff options
| author | Claude <noreply@anthropic.com> | 2026-05-20 09:52:18 +0000 |
|---|---|---|
| committer | Claude <noreply@anthropic.com> | 2026-05-20 09:52:18 +0000 |
| commit | cdb3fa7c6167e108f46b4d411655f78a22e3bebe (patch) | |
| tree | 393b7ffb45bad2eda862f192ae492e94f9f881fd /android-app/app/src | |
| parent | 6dc2b16da127dd0a68907c037e8219eaacc8806c (diff) | |
Fix Recenter bleed-through; drop noisy speed events; track detail as bottom sheet
Recenter button was reappearing over overlays because the isFollowing
flow kept calling fadeIn(fabRecenter) even when an overlay was visible.
Added overlayShowing flag — the flow skips FAB updates while an overlay
is shown. hideOverlays() now correctly restores fabRecenter visibility
based on the actual following state instead of just resetting alpha.
Speed up/Slow down events fired on every 1.5 kt GPS jitter, flooding
the log with noise. Removed the detection loop entirely — no reliable
motor on/off signal is available from GPS alone.
TrackDetailSheet converted from a full-screen Fragment to a
BottomSheetDialogFragment: opens at half-screen height so the track
route is visible on the map behind it, draggable to full height, 20%
background dim. SavedTracksFragment now calls hideOverlays() then
sheet.show() instead of fragment-replacing the overlay container.
https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
Diffstat (limited to 'android-app/app/src')
4 files changed, 36 insertions, 33 deletions
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt b/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt index 7ce417d..caabe40 100644 --- a/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt +++ b/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt @@ -114,6 +114,7 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { private val viewModel: MainViewModel by viewModels() private var pendingServiceStart = false private var serviceStarted = false + private var overlayShowing = false override fun onResume() { super.onResume() @@ -418,6 +419,7 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { } private fun showOverlay(fragment: androidx.fragment.app.Fragment) { + overlayShowing = true fragmentContainer.visibility = View.VISIBLE fabRecordTrack.visibility = View.GONE fabLayers.visibility = View.GONE @@ -432,9 +434,12 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { } internal fun hideOverlays() { + overlayShowing = false fragmentContainer.visibility = View.GONE fabRecordTrack.visibility = View.VISIBLE fabLayers.visibility = View.VISIBLE + val following = mapHandler?.isFollowing?.value ?: true + fabRecenter.visibility = if (following) View.GONE else View.VISIBLE fabRecenter.alpha = 1f bottomSheetBehavior.isHideable = false bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED @@ -592,12 +597,14 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener { lifecycleScope.launch { mapHandler!!.isFollowing.collect { following -> mapCrosshair.visibility = if (following) View.GONE else View.VISIBLE - if (following) { - fadeOut(fabRecenter, gone = true) - fadeIn(fabRecordTrack) - } else { - fadeOut(fabRecordTrack, gone = true) - fadeIn(fabRecenter) + if (!overlayShowing) { + if (following) { + fadeOut(fabRecenter, gone = true) + fadeIn(fabRecordTrack) + } else { + fadeOut(fabRecordTrack, gone = true) + fadeIn(fabRecenter) + } } } } diff --git a/android-app/app/src/main/kotlin/org/terst/nav/track/SavedTracksFragment.kt b/android-app/app/src/main/kotlin/org/terst/nav/track/SavedTracksFragment.kt index d8b9858..f992e1e 100644 --- a/android-app/app/src/main/kotlin/org/terst/nav/track/SavedTracksFragment.kt +++ b/android-app/app/src/main/kotlin/org/terst/nav/track/SavedTracksFragment.kt @@ -44,11 +44,8 @@ class SavedTracksFragment : Fragment() { val adapter = SavedTrackAdapter { track -> viewModel.selectTrack(track) - parentFragmentManager - .beginTransaction() - .replace(R.id.fragment_container, TrackDetailSheet.newInstance()) - .addToBackStack(null) - .commit() + (requireActivity() as MainActivity).hideOverlays() + TrackDetailSheet.newInstance().show(parentFragmentManager, "track_detail") } rv.adapter = adapter diff --git a/android-app/app/src/main/kotlin/org/terst/nav/track/TrackDetailSheet.kt b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackDetailSheet.kt index c1764a8..627ce89 100644 --- a/android-app/app/src/main/kotlin/org/terst/nav/track/TrackDetailSheet.kt +++ b/android-app/app/src/main/kotlin/org/terst/nav/track/TrackDetailSheet.kt @@ -5,11 +5,13 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView -import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialog +import com.google.android.material.bottomsheet.BottomSheetDialogFragment import org.terst.nav.R import org.terst.nav.ui.MainViewModel import java.time.Instant @@ -28,7 +30,7 @@ data class LogEvent( val detail: String ) -class TrackDetailSheet : Fragment() { +class TrackDetailSheet : BottomSheetDialogFragment() { private val viewModel: MainViewModel by activityViewModels() @@ -41,13 +43,11 @@ class TrackDetailSheet : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val track = viewModel.selectedTrack.value ?: run { - parentFragmentManager.popBackStack() + dismiss() return } - view.findViewById<View>(R.id.btn_back).setOnClickListener { - parentFragmentManager.popBackStack() - } + view.findViewById<View>(R.id.btn_back).setOnClickListener { dismiss() } val titleFmt = DateTimeFormatter.ofPattern("dd MMM yyyy · HH:mm", Locale.getDefault()) .withZone(ZoneId.systemDefault()) @@ -70,6 +70,14 @@ class TrackDetailSheet : Fragment() { rv.adapter = LogEventAdapter(events) { event -> viewModel.panToTrackPoint(event.lat, event.lon) } + + (dialog as? BottomSheetDialog)?.behavior?.apply { + isFitToContents = false + halfExpandedRatio = 0.5f + skipCollapsed = true + state = BottomSheetBehavior.STATE_HALF_EXPANDED + } + dialog?.window?.setDimAmount(0.2f) } override fun onDestroyView() { @@ -96,22 +104,6 @@ class TrackDetailSheet : Fragment() { "%.0f° → %.0f° (Δ%.0f°)".format(t.cogBefore, t.cogAfter, abs(delta))) } - for (i in 1 until points.size - 1) { - val prev = points[i - 1].sogKnots - val curr = points[i].sogKnots - val next = points[i + 1].sogKnots - val rise = curr - prev - val fall = curr - next - val p = points[i] - if (rise > 1.5 && rise > fall) { - events += LogEvent(p.lat, p.lon, p.timestampMs, "↑", - "Speed up", "%.1f → %.1f kt".format(prev, curr)) - } else if (fall > 1.5 && fall > rise) { - events += LogEvent(p.lat, p.lon, p.timestampMs, "↓", - "Slow down", "%.1f → %.1f kt".format(curr, next)) - } - } - points.lastOrNull()?.let { p -> events += LogEvent(p.lat, p.lon, p.timestampMs, "🏁", "End", formatPointDetail(p)) } diff --git a/android-app/app/src/main/res/layout/layout_track_detail_sheet.xml b/android-app/app/src/main/res/layout/layout_track_detail_sheet.xml index 6a2ba50..97b1da8 100644 --- a/android-app/app/src/main/res/layout/layout_track_detail_sheet.xml +++ b/android-app/app/src/main/res/layout/layout_track_detail_sheet.xml @@ -6,6 +6,13 @@ android:orientation="vertical" android:background="?attr/colorSurface"> + <!-- Drag handle --> + <View + android:layout_width="36dp" + android:layout_height="40dp" + android:layout_gravity="center_horizontal" + android:background="@drawable/drag_handle_bg" /> + <!-- Header --> <LinearLayout android:layout_width="match_parent" |
