• v2.0.2 b2aa1c167c

    marcel released this 2026-05-15 14:30:30 +02:00 | 7 commits to main since this release

    GPS2Audio v2.0.2 — Drag-and-Drop Waypoint Reorder

    Artifacts

    • Signed APK: /home/user/workspace/GPS2Audio_v2_0_2_drag_reorder_signed.apk
    • Source ZIP (no secrets): /home/user/workspace/GPS2Audio_v2_0_2_drag_reorder_source.zip
    • This handoff: /home/user/workspace/GPS2Audio_v2_0_2_drag_reorder_handoff.md

    Version / signing

    • applicationId: de.waypointaudio
    • versionName: 2.0.2
    • versionCode: 30 (was 29 in v2.0.1)
    • Signed with the existing release keystore
      (/home/user/workspace/GPS2Audio_release_keystore.jks,
      alias gps2audio_release).
    • Signing certificate (verified with apksigner verify --print-certs):
      • DN: CN=GPS2Audio, OU=NesoHub, O=GPS2Audio, L=Germany, C=DE
      • SHA-256: 7B:0E:A4:D5:52:86:05:17:3D:29:9D:7B:26:8E:7A:B8:76:8D:D5:04:EC:15:B6:6A:52:D4:7B:42:57:B3:BB:46
      • SHA-1: EB:92:2A:83:39:09:ED:6B:2D:CB:62:52:F0:CF:42:5F:26:DF:25:AD
        → identical to v2.0.0 / v2.0.1, so installs upgrade in place from any
        earlier de.waypointaudio build.
    • aapt dump badging confirmed:
      package: name='de.waypointaudio' versionCode='30' versionName='2.0.2'.
    • gradle :app:assembleRelease → BUILD SUCCESSFUL (only pre-existing
      deprecation warnings: launchWhenStarted, OSMDroid setters,
      Modifier.menuAnchor() — unchanged from v2.0.1).

    Headline change — direct drag-and-drop reordering

    Replaces the per-card ▲▼ IconButton column from v2.0.1 with a true
    drag-and-drop gesture on every waypoint card. The user asked to switch
    directly to drag-and-drop control; the arrow column was removed
    rather than augmented.

    Drag interaction (user-facing)

    • Every Waypoint-Track card now shows a left-edge drag handle
      (Icons.Filled.DragIndicator). German content description:
      Ziehgriff zum Verschieben (R.string.drag_handle_cd).
    • Two ways to start a reorder:
      1. Press the drag handle and drag (immediate, no long-press).
        The handle has its own pointerInput block — it doesn't compete
        with the outer verticalScroll, so a press on the handle never
        starts a page scroll.
      2. Long-press anywhere on the card and drag. This uses
        detectDragGesturesAfterLongPress on the whole card and exists as
        an accessibility / touch-target alternative; the long-press
        threshold protects normal vertical scrolling.
    • While dragging:
      • The dragged card is lifted via graphicsLayer.translationY,
        elevated to 8.dp, recoloured to primaryContainer @ 0.65f, and
        pulled above its siblings with zIndex(1f).
      • The other cards in the affected range shift by their own measured
        height (+/- pixels via graphicsLayer.translationY) so the gap
        appears at the prospective drop position. Reordering target is
        computed from cumulative drag offset and the per-item heights
        measured via onGloballyPositioned, with a half-height threshold
        per neighbour (see DragReorderState.computeTargetIndex).
    • On finger up, WaypointViewModel.moveWaypoint(from, to) is called
      once. That goes through the existing repository.saveAll path, so the
      final order is persisted exactly the same way the old arrow buttons
      persisted theirs. Cancelling the drag (e.g. system back / system
      cancel) snaps the items back without calling moveWaypoint.
    • Reorder is disabled while the GPS service is running OR a track
      recording is active (reorderBlocked = serviceRunning || isRecording):
      • Both pointerInput blocks short-circuit to Modifier so no drag can
        start.
      • The DragIndicator icon is shown at alpha 0.20 to read as disabled.
      • The pre-existing concise hint
        Sortieren während GPS/Aufzeichnung deaktiviert
        (R.string.reorder_blocked_hint_short) continues to appear at the
        right of the Wegpunkt-Tracks heading when more than one waypoint
        exists.

    Implementation summary

    All code touch points:

    • app/src/main/kotlin/de/waypointaudio/ui/WaypointListScreen.kt
      • Added imports: detectDragGestures,
        detectDragGesturesAfterLongPress, graphicsLayer, pointerInput,
        onGloballyPositioned, semantics/contentDescription, zIndex,
        kotlin.math.abs, kotlin.math.roundToInt.
      • Replaced the WaypointCard arrow column with a drag handle Box
        containing Icons.Filled.DragIndicator.
      • Wired both gesture detectors:
        • detectDragGestures on the handle (immediate, no long-press).
        • detectDragGesturesAfterLongPress on the card surface
          (accessibility alternative).
      • Added a per-list DragReorderState (held in a remember { } slot
        inside the list block via the rememberDragReorderState helper).
        The state tracks: itemCount, draggingIndex, dragOffsetPx,
        a mutableStateMapOf<Int,Int> of item heights, and exposes
        onDragStart/onDrag/onDragEnd/onDragCancel,
        computeTargetIndex, shiftDirectionFor, itemHeightFor.
      • The WaypointCard Composable now takes
        index: Int, reorderState: DragReorderState? instead of the old
        canMoveUp / canMoveDown / onMoveUp / onMoveDown parameters.
      • Card root applies graphicsLayer.translationY (drag offset or
        sibling shift), zIndex for the dragged card, and
        onGloballyPositioned to report height to the state.
    • app/src/main/res/values/strings.xml
      • Added drag_handle_cd = "Ziehgriff zum Verschieben".
      • Added drag_reorder_hint_short = "Ziehgriff halten und verschieben"
        (kept for future use; not displayed yet — heading stays compact).
    • app/build.gradle.kts
      • versionCode = 30, versionName = "2.0.2".

    Why this approach (tradeoffs)

    • Column, not LazyColumn. The Waypoint list shares the page's outer
      verticalScroll. Switching the inner list to a LazyColumn inside a
      scrolling Column is illegal (nested scroll) without significant
      re-architecture of the whole page, which carries regression risk for
      Atmo / PTT / map / draft / playlist features. The drag state is
      therefore implemented over the existing Column with
      onGloballyPositioned height measurement and graphicsLayer
      translation — minimal invasiveness, no new dependencies.
    • Dedicated handle + long-press fallback. Using only long-press
      delays the gesture; using only direct drag on the card surface
      competes with verticalScroll. A dedicated handle with its own
      pointerInput solves both: page scrolling stays untouched, the
      gesture starts immediately when the handle is grabbed, and
      long-press is still available for users who don't realise the handle
      exists. This is the same UX shape Google uses in Material reorder
      lists.
    • No new external library. No
      reorderable-compose, no androidx.compose.foundation snapshot
      dependency; only stable Compose Foundation APIs already in BOM.
    • Persist on drop. viewModel.moveWaypoint(from, to) is called
      exactly once on drag end, so the existing repository.saveAll
      pipeline is invoked once per drag — same persistence semantics as
      the v2.0.1 arrow taps. The half-neighbour-height threshold keeps the
      drop position visually predictable.
    • Tour ordering dialog unchanged. The Touren ordnen compact
      dialog still uses ▲▼ arrows (task says this is acceptable; tours
      list is short, dialog is rarely used).

    Preserved features (regression checklist)

    Verified by reading the source — no other files were touched:

    • applicationId = de.waypointaudio, signing config + keystore
      properties path unchanged → upgrade-in-place from v2.0.0 / v2.0.1.
    • Wake-Lock settings (Theme/MainActivity/WakeLockController):
      untouched.
    • Map provider selection (MapProvider, MapProviderDialog,
      MapScreen): untouched.
    • Atmo layout (Begleitmusik mini-player above the track list,
      BegleitmusikMiniPlayer + BegleitmusikDialog) and Atmo resume
      manager: untouched.
    • Compact top bar / ScrollableTabRow IndexOutOfBounds fix:
      untouched (tabs.joinToString("|") key still in place).
    • Track-Editor / Drafts (TrackDraftEditorScreen,
      TrackDraftListScreen, TrackDraft, TrackRecordingManager):
      untouched.
    • Backup import/export (BackupImportManager,
      BackupExportManager, ImportExportManager): untouched.
    • Map search (PlaceSearchDialog, NominatimClient): untouched.
    • Audio library playlist (TourMusicStore,
      BackgroundMusicManager, BackgroundMusicPlayer): untouched.
    • PTT Atmo resume (LivePttManager, LivePttService,
      AtmoResumeManager): untouched.
    • OSM attribution: untouched.
    • TabRow fix: untouched.
    • About PayPal / version notice (AboutDialog,
      VersionNoticeDialog, VersionNoticeStore, AppVersion):
      untouched. AppVersion reads version at runtime from the
      PackageManager, so the About dialog will show 2.0.2 (30)
      automatically.

    Regression checklist (manual smoke)

    When installing the APK over v2.0.1 on a real device, please verify:

    1. App launches; About dialog reads 2.0.2 (30).
    2. Tab row scrolls horizontally; adding / renaming / deleting tours
      does not crash the tab row.
    3. Waypoint list shows the DragIndicator handle on every card.
    4. Press handle, drag a card up/down past at least 2 neighbours, let
      go — the order is updated and survives an app restart.
    5. Long-press a card body (not the handle) for ~500 ms, drag, drop —
      same result.
    6. Start GPS service (▶ in top bar). Handles fade out; pressing them
      or long-pressing a card does nothing. The hint
      Sortieren während GPS/Aufzeichnung deaktiviert appears.
    7. Stop GPS, start a track recording. Same disabled behaviour.
    8. While not reordering, normal vertical page scroll still works
      (PTT → Atmo → manual player → track list → spacer).
    9. Atmo mini-player still plays / pauses / next / prev.
    10. Manual player bar still plays / pauses / next / prev.
    11. Map screen opens, OSM tiles render, attribution still visible,
      map provider dialog still works.
    12. Track-Editor / drafts: open from FAB / overflow, recording flow
      still works.
    13. Backup import + export still produce/consume the same JSON / ZIP
      shapes.
    14. Map search dialog (Nominatim) still returns results.
    15. PayPal link in About still opens correctly.

    Build / signature result

    • gradle :app:assembleReleaseBUILD SUCCESSFUL in 47s.
    • Warnings: only pre-existing deprecations (launchWhenStarted,
      OSMDroid setters, Modifier.menuAnchor()).
    • apksigner verify --print-certs:
      • Signer #1 DN matches v2.0.1.
      • SHA-256 matches v2.0.1 (7B:0E:A4:…:B3:BB:46).
    • aapt dump badging:
      • package: name='de.waypointaudio' versionCode='30' versionName='2.0.2'
      • sdkVersion:'26', targetSdkVersion:'35'
      • application-label:'GPS2Audio'
    Downloads
  • v2.0.1 b2aa1c167c

    marcel released this 2026-05-15 14:30:04 +02:00 | 7 commits to main since this release

    GPS2Audio v2.0.1 — Direct Reorder UI

    Artifacts

    • Signed APK: /home/user/workspace/GPS2Audio_v2_0_1_direct_reorder_signed.apk
    • Source ZIP (no secrets): /home/user/workspace/GPS2Audio_v2_0_1_direct_reorder_source.zip
    • This handoff: /home/user/workspace/GPS2Audio_v2_0_1_direct_reorder_handoff.md

    Version / signing

    • applicationId: de.waypointaudio
    • versionName: 2.0.1
    • versionCode: 29 (was 28)
    • Signed with the existing release keystore
      (GPS2Audio_release_keystore.jks, alias gps2audio_release).
    • Signing certificate (verified with apksigner verify --print-certs):
      • DN: CN=GPS2Audio, OU=NesoHub, O=GPS2Audio, L=Germany, C=DE
      • SHA-256: 7B:0E:A4:D5:52:86:05:17:3D:29:9D:7B:26:8E:7A:B8:76:8D:D5:04:EC:15:B6:6A:52:D4:7B:42:57:B3:BB:46
      • SHA-1: EB:92:2A:83:39:09:ED:6B:2D:CB:62:52:F0:CF:42:5F:26:DF:25:AD
    • aapt dump badging confirmed: package: name='de.waypointaudio' versionCode='29' versionName='2.0.1'.
    • gradle :app:assembleRelease → BUILD SUCCESSFUL (only pre-existing
      deprecation warnings — launchWhenStarted, OSMDroid setters,
      Modifier.menuAnchor()).

    UI changes (precise)

    All changes are in
    app/src/main/kotlin/de/waypointaudio/ui/WaypointListScreen.kt and
    app/src/main/res/values/strings.xml.

    1. Prominent Reihenfolge bearbeiten row removed

    • The SortModeBar composable and the associated full-width row that used
      to sit between the tour tabs and the Tour-Zähler card are deleted.
    • The sortMode/sortBlocked toggle state was removed from the screen
      state. Tab clicks no longer have to check if (!sortMode).
    • The TourReorderList panel that expanded under that bar is replaced
      by a compact dialog (see section 3).

    2. Direct waypoint reordering on each card

    WaypointCard now exposes a small two-arrow column on the left edge of
    every card. The arrows are always rendered, so the user can re-order
    waypoints with one tap (no mode to enter first):

    • Up arrow → viewModel.moveWaypoint(index, index - 1)
    • Down arrow → viewModel.moveWaypoint(index, index + 1)

    The arrows are disabled (greyed out) when:

    • The waypoint is at the top/bottom of the current tour's list
      (canMoveUp/canMoveDown).
    • The GPS service is running OR a track recording is active
      (reorderBlocked = serviceRunning || isRecording). In that case both
      arrows are non-interactive and the new short hint
      Sortieren während GPS/Aufzeichnung deaktiviert (string
      reorder_blocked_hint_short) is shown to the right of the
      Wegpunkt-Tracks heading.

    German accessibility labels are attached to both arrows via
    contentDescription (updated sort_move_up/sort_move_down to
    Nach oben verschieben / Nach unten verschieben). Icons are
    Icons.Filled.KeyboardArrowUp / KeyboardArrowDown for a clean look.

    The Switch for isActive no longer disables itself during reorder
    (there is no reorder mode anymore); it stays freely tappable whenever
    the card is visible.

    Persistence is unchanged: WaypointViewModel.moveWaypoint continues to
    delegate to WaypointStore.moveWaypointInTour and persists immediately.

    3. Compact tour reordering — Touren ordnen dialog

    • New overflow-menu item Touren ordnen (menu_tour_reorder) sits in
      the existing ⋮ menu just above Display aktiv halten. It is disabled
      whenever fewer than two tours exist or when GPS/recording is active.
    • Tapping it opens an AlertDialog titled Touren ordnen listing every
      tour with up/down arrows, calling viewModel.moveTour(from, to). The
      dialog closes with the existing Fertig button.
    • No large always-visible bar remains in the main screen — tour
      reordering is reachable in two taps (overflow → Touren ordnen) and
      consumes zero vertical space until invoked.

    4. Start-screen vertical density

    • Removed the full-width SortModeBar row (≈40 dp tall).
    • Removed the expandable Touren-Reihenfolge panel that grew under it.
    • The waypoint cards are now slightly more compact: padding tightened
      from start=12 / vertical=10 to start=8 / vertical=8 to compensate
      for the always-on arrow column without making the card taller.

    Section ordering on the start screen is preserved (top → bottom):
    ScrollableTabRow (Touren) → Tour-Zähler-Karte → Live/PTT → Atmo
    (Begleitmusik mini player) → Manual Player Bar → "Wegpunkt-Tracks"
    heading (with optional GPS-blocked hint) → waypoint cards. The whole
    content is still wrapped in a verticalScroll and the dual FAB stack
    is unchanged.

    How to reorder now (user-facing)

    • Waypoints inside a tour: tap the small ▲ or ▼ button on the left
      edge of any waypoint card. Order is saved immediately.
    • Tours (tab order): tap ⋮ → Touren ordnen. In the dialog use the
      ▲▼ buttons next to each tour. Close with Fertig.
    • While GPS service or track recording is active: both controls are
      disabled. The card arrows render greyed-out; the overflow item is
      disabled; a short hint
      Sortieren während GPS/Aufzeichnung deaktiviert appears next to the
      Wegpunkt-Tracks heading. Stop the service / recording to re-enable.

    Preserved features (regression checklist)

    • applicationId = de.waypointaudio, signed with the v2.0.0 release
      keystore → in-place upgrade over v2.0.0 works.
    • v2.0.0 features:
      • Wake Lock settings dialog accessible via overflow.
      • Atmo (BegleitmusikMiniPlayer) is placed above the waypoint
        list, with autostart / resume preserved (AtmoResumeManager,
        BackgroundMusicManager untouched).
      • Compact TopBar with launcher icon, app title, and Play/Map/
        Track-Editor/⋮ actions — unchanged.
      • Map provider selection — untouched.
    • Track-Editor / drafts (TrackDraftListScreen,
      TrackDraftEditorScreen) — unchanged, including thick route line,
      marking handles and "Import marked points".
    • Backup export/import (BackupDialog, BackupImportDialog) — wiring
      unchanged.
    • Map search everywhere (PlaceSearchDialog usage in MapScreen,
      TrackDraftEditorScreen) — unchanged.
    • Audio-library playlist (BegleitmusikDialog) — unchanged.
    • PTT pauses/resumes Atmo (LivePttCard + LivePttManager +
      BackgroundMusicPlayer.duck/pauseForPtt) — unchanged.
    • OSM attribution layout in MapScreen — unchanged.
    • ScrollableTabRow identity-key fix (key(tabs.joinToString("|"))) —
      retained.
    • About dialog incl. PayPal link / version notice — unchanged.
    • viewModel.moveWaypoint / moveTour semantics — unchanged; this
      patch only changes how the user reaches them.

    Regression checklist (suggested manual test plan)

    1. Fresh install: tab bar shows existing tours; no "Reihenfolge
      bearbeiten" row appears above Tour-Zähler.
    2. With two or more waypoints, tap ▲▼ on a card: list re-orders
      immediately and persists across app restart.
    3. Tap ▲ on the first card and ▼ on the last: visually disabled, no
      action.
    4. Start GPS service: card arrows grey out, hint
      Sortieren während GPS/Aufzeichnung deaktiviert shown next to
      "Wegpunkt-Tracks". Overflow Touren ordnen is disabled. Stop
      service → controls re-enabled.
    5. Start track recording (same expectations).
    6. Open ⋮ → Touren ordnen: dialog lists every tour; ▲▼ reorder, tabs
      reflect new order after closing with Fertig.
    7. Verify ScrollableTabRow does not throw IndexOutOfBounds when tours
      are reordered, renamed, or deleted (identity-key fix retained).
    8. Verify Atmo, Live/PTT, Manual Player, Tour-Zähler still appear in
      their v2.0.0 order and are scrollable.
    9. Backup export/import still completes round-trip.
    10. Install over v2.0.0 (same keystore) — no signature conflict.

    Build & verification commands used

    gradle :app:assembleRelease           # BUILD SUCCESSFUL
    apksigner verify --print-certs app-release.apk
    aapt dump badging app-release.apk
    

    Both confirm the signing cert SHA-256 7B0EA4D5...B3BB46 and package
    de.waypointaudio versionCode='29' versionName='2.0.1'.

    Source-tree hygiene

    • The signed build was produced with a local keystore.properties at
      the project root pointing to
      /home/user/workspace/GPS2Audio_release_keystore.jks and using the
      passwords from
      /home/user/workspace/GPS2Audio_release_keystore_credentials.txt.
    • GPS2Audio_v2_0_1_direct_reorder_source.zip does not contain
      keystore.properties, the .jks, or the credentials file. Only the
      unchanged keystore.properties.example is shipped. The Gradle config
      still reads either keystore.properties or the
      GPS2AUDIO_RELEASE_* env vars, so future builds work with the same
      mechanism v2.0.0 used.
    Downloads
  • v2.0.0 b2aa1c167c

    marcel released this 2026-05-15 14:29:52 +02:00 | 7 commits to main since this release

    GPS2Audio v2.0.0 — Phase 1 Fixes — Handoff

    Build date: 2026-05-14
    versionCode: 28
    versionName: 2.0.0
    applicationId: de.waypointaudio
    Signed: yes, with GPS2Audio_release_keystore.jks (same identity as the first release)

    Artifacts

    File Purpose
    /home/user/workspace/GPS2Audio_v2_0_0_phase1_signed.apk Signed release APK (≈ 14.4 MB)
    /home/user/workspace/GPS2Audio_v2_0_0_phase1_source.zip Full source tree (work/ root) without keystore, credentials, or real keystore.properties
    /home/user/workspace/GPS2Audio_v2_0_0_phase1_handoff.md This document

    Build / signing verification

    package: name='de.waypointaudio' versionCode='28' versionName='2.0.0'
    Signer #1 certificate DN: CN=GPS2Audio, OU=NesoHub, O=GPS2Audio, L=Germany, C=DE
    Signer #1 certificate SHA-256 digest:
      7b0ea4d5528605173d299d7b268e7ab8768dd504ec15b66a52d47b4257b3bb46
    

    The SHA-256 matches the fingerprint recorded in
    GPS2Audio_release_keystore_credentials.txt exactly — the APK is signed
    with the same release identity as GPS2Audio_first_release_signed.apk.
    apksigner verify reports the certificate without errors. The build was
    produced via gradle :app:assembleRelease; no debug build is shipped for
    this milestone.

    Install / update notes

    • This APK updates the installed first release (versionCode 27) because
      the package name (de.waypointaudio), keystore identity, and signature
      scheme are identical. No uninstall needed.
    • Users keep their tours, waypoints, audio files, drafts and tour-music
      settings — only new DataStore stores (wake_lock_settings,
      map_provider_settings) are added with safe defaults
      (mode = Nie, provider = OpenStreetMap).

    Phase 1 feature checklist

    1.1 Wake Lock / Display aktiv halten

    • WAKE_LOCK permission was already in AndroidManifest.xml (for audio
      service); confirmed present and unchanged.
    • German UI with three radio-button options:
      - Nie (default)
      - Nur bei aktiver Tour/GPS — only while the GPS service is running
      - Immer wenn App im Vordergrund — whenever the app window is visible
    • Implementation uses WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
      on the Activity window (recommended pattern, see
      https://developer.android.com/training/scheduling/wakelock). This is
      preferred over PowerManager.SCREEN_DIM_WAKE_LOCK (deprecated) because
      Android automatically clears the flag when the activity pauses, so the
      "release when app goes to background" requirement is satisfied by the
      framework itself and cannot leak.
    • Wake lock cleared explicitly in MainActivity.onPause() and re-applied
      in onResume() (in addition to the framework's automatic handling).
    • One-time Akku-Hinweis dialog appears the first time the user
      switches from Nie to an active mode. Tracked in DataStore
      (battery_hint_shown), so it never re-appears.
    • Setting persisted via DataStore (wake_lock_settings) — new file
      data/WakeLockSettings.kt.
    • Auto-dim after X min: not implemented in Phase 1 — would require a
      custom timer + screen-brightness reset path that fights the Android
      system display timeout. Limitation documented here; will revisit in
      Phase 2 if requested.

    Files touched:

    • app/src/main/kotlin/de/waypointaudio/data/WakeLockSettings.kt (new)
    • app/src/main/kotlin/de/waypointaudio/service/WakeLockController.kt (new)
    • app/src/main/kotlin/de/waypointaudio/ui/WakeLockSettingsDialog.kt (new)
    • app/src/main/kotlin/de/waypointaudio/MainActivity.kt (wires controller, observes service state)
    • app/src/main/kotlin/de/waypointaudio/ui/WaypointListScreen.kt (menu entry, dialog launch)
    • app/src/main/res/values/strings.xml (new wake-lock strings)

    1.2 Atmo-Bereich nach oben verschieben

    • New scroll-region order on the main page:
      Tour-Zähler → Live/PTT → Atmo (Begleitmusik) → Manueller Player → Wegpunkt-Tracks.
    • Existing fixed ScrollableTabRow for tours stays pinned at top, untouched.
    • Page remains scrollable; bottom FAB padding (Spacer 160 dp) preserved.
    • No duplicate cards — old positions of the Atmo player and manual player
      bar (below the waypoint list) were removed.

    Files touched:

    • app/src/main/kotlin/de/waypointaudio/ui/WaypointListScreen.kt

    1.3 Atmo Resume vollständig absichern

    • AtmoResumeManager introduced as a single source of truth for
      interrupt-start / interrupt-end across all three interruption
      sources (WAYPOINT, MANUAL_PLAYER, PTT). It uses pause() on the
      shared BackgroundMusicPlayer, which preserves the ExoPlayer's
      current position — never stop() (which releases the player and
      loses the position).
    • PTT path now delegates to AtmoResumeManager.notifyInterruptStart/End
      via LivePttManager.pauseAtmo / restoreAtmo. The previous inline logic
      (which already used pauseMusic() and a remembered "was playing"
      flag) was replaced — behavior is identical from the user's perspective,
      but it now runs through the central manager.
    • Waypoint path continues to use the existing
      BackgroundMusicPlayer.before/afterWaypointAudio hooks. Those hooks
      already call pause() internally for the PAUSE_RESUME behavior and
      preserve position via the live ExoPlayer instance. They are explicitly
      documented in the new AtmoResumeManager so future contributors know
      that the waypoint route is the canonical pause/resume contract.
    • Manual Player path wraps every manual play with the same
      musicManager.beforeWaypointAudio() / afterWaypointAudio() pair
      (unchanged) — that means manual-player interruptions use the same
      pause-with-position semantics as GPS-triggered waypoint audio.
    • Resume only fires if Atmo was active immediately before the first
      interruption and no other interruption is still active and the
      Atmo player still holds content (i.e. the user has not manually
      stopped it during the interruption).
    • Loop / natural-end edge case: BackgroundMusicPlayer already uses
      Player.REPEAT_MODE_ALL, so an Atmo track that finishes naturally
      mid-interruption simply transitions to the next item; on resume the
      next-item start position is correct.

    Files touched:

    • app/src/main/kotlin/de/waypointaudio/service/AtmoResumeManager.kt (new)
    • app/src/main/kotlin/de/waypointaudio/service/LivePttManager.kt (delegates to AtmoResumeManager)

    1.4 TopBar — Variante C (Icon + kompakter Titel)

    • Title row in WaypointListScreen is now Row { Image(24dp) + Text(titleMedium / SemiBold) }.
    • R.drawable.ic_launcher is reused (the launcher icon already encodes
      the MapPin + sound-wave concept; there is no separate
      ic_launcher_foreground resource — single-source icon in this repo).
    • Line break in GPS2Audio fixed via maxLines = 1 + softWrap = false
      + overflow = TextOverflow.Ellipsis.

    Files touched:

    • app/src/main/kotlin/de/waypointaudio/ui/WaypointListScreen.kt

    1.5 Versionsnummer bereinigen

    • app/build.gradle.kts: versionCode = 28, versionName = "2.0.0".
    • No suffix; Über diese App (AboutDialog) reads via AppVersion.get()
      (existing util) and therefore now displays Version 2.0.0 (28) with
      no code changes.

    1.6 Karten-Provider Auswahl

    • New enum MapProvider with eight OSMDroid-based tile sources:
      OSM (default / fallback), CartoDB Positron, CartoDB Dark Matter,
      OpenTopoMap, ESRI Satellite, ESRI Hybrid, Stadia Alidade, Stadia
      Outdoors. All are wired through XYTileSource — no library swap.
    • German selection dialog (MapProviderDialog) reached from a
      new layers-icon button in the Map TopBar actions row.
    • Selection persisted app-wide via DataStore
      (map_provider_settings). Per-tour persistence not implemented:
      tours currently store only audio settings (TourAudioSettings),
      not map settings — adding a per-tour map provider would require a new
      per-tour store and migration of existing tour data, which is out of
      scope for Phase 1. The app-wide setting is reachable from the map at
      any time, so it is one tap to switch.
    • Live tile-source switch: LaunchedEffect(selectedProvider) in both
      MapScreen and TrackDraftEditorScreen updates the active MapView
      and calls invalidate() so the new tiles load immediately.
    • OSM-Attribution remains the persistent OsmAttributionBadge overlay
      on MapScreen — visible for all providers. The provider-specific
      copyright (CartoDB, Esri, Stadia, OpenTopoMap) is encoded in each
      XYTileSource and surfaced when osmdroid prints copyright info.

    Files touched:

    • app/src/main/kotlin/de/waypointaudio/data/MapProvider.kt (new)
    • app/src/main/kotlin/de/waypointaudio/ui/MapProviderDialog.kt (new)
    • app/src/main/kotlin/de/waypointaudio/ui/MapScreen.kt
    • app/src/main/kotlin/de/waypointaudio/ui/TrackDraftEditorScreen.kt
    • app/src/main/res/values/strings.xml (new provider strings)

    First-release regression checklist

    Each of these features from the first release was inspected and is not
    modified
    by this milestone:

    • applicationId de.waypointaudio unchanged.
    • Track-Editor / draft archive, thick route line + handles, marking,
      "import marked points" flow — code paths in TrackDraftListScreen,
      TrackDraftEditorScreen, WaypointRepository untouched apart from
      a single map-tile-source line.
    • Backup export / import unchanged (io/BackupExportManager.kt,
      io/BackupImportManager.kt).
    • Sort mode for tours and waypoint tracks unchanged (SortModeBar +
      TourReorderList still in WaypointListScreen).
    • Scrollable main page preserved (the outer verticalScroll column
      still wraps everything below the tab row).
    • Map search in normal map and editor unchanged (PlaceSearchDialog
      still wired into both MapScreen and TrackDraftEditorScreen).
    • Audio library playlist selection unchanged (BegleitmusikDialog).
    • PTT / Atmo collapsible unchanged (LivePttCard).
    • PTT pauses / resumes Atmo correctly — same behavior, now routed
      through AtmoResumeManager. Manually traced: pauseAtmo
      notifyInterruptStart(PTT) → snapshots wasAtmoPlayingAtFirstInterruption
      and pauses if playing; restoreAtmonotifyInterruptEnd(PTT)
      resumes only if it was playing and the player still has content.
    • OSM attribution layout (OsmAttributionBadge) still rendered for
      every provider — verified by inspecting MapScreen.kt lines 819–824.
    • About: PayPal support link, automatic version display
      (AppVersion.get()), per-version startup notice
      (VersionNoticeStore, VersionNoticeDialogHost) — all unchanged.
      Because versionCode = 28 is new, the one-time version notice will
      fire once on first launch of v2.0.0.
    • JSON / GPX I/O (ImportExportManager), GPS behaviors
      (WaypointLocationService, TrackRecordingService) untouched.

    Build details

    gradle :app:assembleRelease
    BUILD SUCCESSFUL in 1m 51s
    43 actionable tasks: 43 executed
    

    Compiler warnings (non-fatal, all pre-existing):

    • launchWhenStarted deprecation in MainActivity (could be migrated to
      repeatOnLifecycle in a later cleanup pass).
    • A handful of osmdroid + Material3 deprecations carried over from the
      first release.

    Implementation notes worth remembering

    • WAKE_LOCK manifest permission is genuinely needed by the audio
      service (MediaPlayer keeps CPU alive in foreground service). The new
      display-on logic does not need an additional manifest permission —
      FLAG_KEEP_SCREEN_ON requires none.
    • Per-tour map provider was considered and explicitly deferred because
      the existing TourAudioSettings store is audio-only; adding a parallel
      per-tour map store would have created two parallel persistence schemas
      in one milestone. The single app-wide setting is one tap away on the map.
    • PowerManager wake lock is not held in addition to
      FLAG_KEEP_SCREEN_ON for the display use case. Two mechanisms competing
      for the same outcome makes future maintenance harder and provides no
      user-visible benefit on modern Android.
    • AtmoResumeManager.activeInterruptions is a Set: if a PTT press
      overlaps with a waypoint trigger, both must end before the Atmo resumes.
      This prevents the Atmo from briefly re-starting between two adjacent
      interruptions.
    • keystore.properties is excluded from the source zip (only the
      .example template is included). The keystore .jks file and
      credentials are never bundled. Build from this zip with the
      signing-config environment variables or by writing a local
      keystore.properties outside source control.
    Downloads
  • marcel released this 2026-05-15 14:29:39 +02:00 | 7 commits to main since this release

    GPS2Audio First Release

    Diese Version wurde als erste Release-Basis festgelegt.

    Version

    • applicationId: de.waypointaudio
    • versionCode: 27
    • versionName: 1.6.2-osm-layout

    Enthaltene Kernfunktionen

    • GPS-Aufzeichnung mit einstellbarem Aufzeichnungsabstand
    • Track-Entwürfe und Karteneditor
    • Ortssuche in Karte und Track-Editor
    • Wegpunkt-Markierung im Track-Editor
    • Backup-Export und Backup-Import
    • Sortiermodus für Touren und Wegpunkt-Tracks
    • einklappbare PTT- und Atmo-Bereiche
    • Atmo-Pause/Wiederaufnahme während PTT
    • Audio-Bibliothek für Begleitmusik-Playlist
    • automatische Versionsanzeige
    • Start-Hinweis pro neuer Version
    • PayPal-Unterstützungslink in „Über diese App“
    • OSM-Attribution sichtbar ohne Button-Überlagerung
    • robuster ScrollableTabRow-Crash-Fix

    Hinweis zum Signieren

    Das vorliegende APK ist ein Debug-Build. Für eine dauerhaft updatefähige öffentliche Verteilung sollte ein fester Release-Keystore eingerichtet und ein signiertes Release-APK gebaut werden.

    Downloads
  • v1.0.0 b2aa1c167c

    GPS2Audio v0.0.1 Pre-Release

    marcel released this 2026-05-05 21:42:02 +02:00 | 7 commits to main since this release

    Erste Testversion von GPS2Audio.

    Enthält:

    • GPS-Wegpunkte mit Audioausgabe
    • Touren und Wegpunkt-Tracks
    • Atmo/Begleitmusik
    • Karteneditor
    • GPS-Track-Aufzeichnung
    • Live/PTT-Funktion
    • Manuelle Einzelwiedergabe pro Wegpunkt
    Downloads