Release GPS2Audio v2.5.44 POI category fix

This commit is contained in:
Perplexity Computer
2026-05-30 05:42:44 +00:00
parent 18ea77b21d
commit 014e6c1bf1
100 changed files with 28584 additions and 1083 deletions
@@ -8,14 +8,32 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.*
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import de.waypointaudio.data.TermsStore
import de.waypointaudio.data.TermsVersions
import de.waypointaudio.data.WakeLockSettingsStore
import de.waypointaudio.service.WakeLockController
import de.waypointaudio.ui.TermsDialog
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import de.waypointaudio.ui.ExplorerScreen
import de.waypointaudio.ui.ExplorerScreenMapLibre
import de.waypointaudio.ui.HomeScreen
import de.waypointaudio.ui.MapMode
import de.waypointaudio.ui.MapScreen
import de.waypointaudio.ui.PermissionRequiredScreen
import de.waypointaudio.ui.TrackDraftEditorScreen
import de.waypointaudio.ui.TrackDraftListScreen
import de.waypointaudio.ui.VersionNoticeDialogHost
import de.waypointaudio.ui.WaypointListScreen
import de.waypointaudio.ui.theme.WaypointAudioTheme
import de.waypointaudio.viewmodel.WaypointViewModel
@@ -40,6 +58,16 @@ class MainActivity : ComponentActivity() {
/** Nur Standortberechtigungen steuern, ob die App-UI angezeigt wird. */
private val locationPermissionsGranted = mutableStateOf(false)
/** Hält das Display abhängig von der Nutzer-Einstellung aktiv. */
lateinit var wakeLockController: WakeLockController
private set
/**
* v2.5.9 — Terms-Akzeptanz. -1 = noch nicht geladen, 0 = noch nicht akzeptiert
* (Dialog zeigen), 1 = akzeptiert (UI freigeben).
*/
private val termsState = mutableStateOf(-1)
// Launcher für Standortberechtigungen (zwingend erforderlich)
private val locationPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
@@ -60,31 +88,157 @@ class MainActivity : ComponentActivity() {
) { /* optional kein Block der Hauptoberfläche */ }
override fun onCreate(savedInstanceState: Bundle?) {
// v2.5.8 — Android Splash Screen (androidx.core.splashscreen). MUSS vor
// super.onCreate() installiert werden. Sorgt für ein kurzes, dezentes
// GPS2Audio-Intro mit Logo (Map-Pin + Wellen) auf Navy-Hintergrund.
// Wir halten den Splash bewusst nur ca. 700 ms — kein Loading-Spinner,
// keine Werbe-Pause. Auf API 31+ animiert das System das Logo automatisch
// beim Übergang. Auf API 2630 nutzt der Backport dieselbe Optik.
val splash = installSplashScreen()
val splashStart = android.os.SystemClock.elapsedRealtime()
splash.setKeepOnScreenCondition {
android.os.SystemClock.elapsedRealtime() - splashStart < 700L
}
super.onCreate(savedInstanceState)
// Wake-Lock-Controller initialisieren
wakeLockController = WakeLockController(this)
val wakeStore = WakeLockSettingsStore(applicationContext)
lifecycleScope.launchWhenStarted {
wakeStore.settings.collect { settings ->
wakeLockController.applySettings(settings)
}
}
lifecycleScope.launchWhenStarted {
viewModel.serviceRunning.collect { running ->
wakeLockController.setTourActive(running)
}
}
// v2.5.9 — Terms-Akzeptanz laden. Solange unklar, UI nicht aufdecken.
val termsStore = TermsStore(applicationContext)
lifecycleScope.launch {
val accepted = termsStore.acceptedVersion.first()
termsState.value = if (accepted == TermsVersions.CURRENT) 1 else 0
}
// Standortberechtigungen prüfen und ggf. anfordern
checkAndRequestLocationPermissions()
setContent {
WaypointAudioTheme(darkTheme = isSystemInDarkTheme()) {
val locationGranted by locationPermissionsGranted
val termsAccepted by termsState
if (locationGranted) {
// v2.5.9 — Solange der Akzeptanzstatus noch nicht geladen wurde
// (termsAccepted == -1) zeigen wir nichts; das verhindert ein
// kurzes "Aufflackern" der UI bevor der Dialog erscheint.
if (termsAccepted == -1) {
// bewusst leeres Theme — DataStore ist nach wenigen ms da.
} else if (termsAccepted == 0) {
TermsDialog(
onAccept = {
lifecycleScope.launch {
termsStore.setAccepted(TermsVersions.CURRENT)
termsState.value = 1
}
},
onDecline = {
// Ohne Zustimmung darf die App nicht weiter genutzt werden.
finishAndRemoveTask()
}
)
} else if (locationGranted) {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "list"
startDestination = "home"
) {
// v2.5.0 — neue Hauptseite "Audio-Bibliothek".
composable("home") {
HomeScreen(
viewModel = viewModel,
onOpenTour = { _ ->
// Tour wurde im HomeScreen bereits über
// viewModel.selectTour() aktiviert. Wir öffnen
// direkt die bestehende Tour-/Waypoint-Ansicht.
navController.navigate("list")
},
// v2.5.34 — Explorer-Kontext-Fix:
// Einstieg aus Audio-Bibliothek/Home muss immer neutral
// öffnen. selectDefaultTour() setzt selectedTour auf
// DEFAULT_TOUR_NAME, bevor der Explorer gerendert wird.
// Einstieg aus WaypointListScreen (Tour-Ansicht) behält
// die jeweils aktive Tour — dort wird selectDefaultTour()
// nicht aufgerufen.
onOpenExplorer = {
viewModel.selectDefaultTour()
navController.navigate("explorer")
},
// v2.5.19 — „Track Editor" wurde aus dem Hauptmenü
// entfernt; Drafts bleiben über den Explorer
// erreichbar. Die „drafts"-Route bleibt für den
// Explorer-Fluss bestehen.
onOpenClassicView = { navController.navigate("list") }
)
}
composable("list") {
WaypointListScreen(
viewModel = viewModel,
onNavigateToMap = { navController.navigate("map") }
onNavigateToMap = { navController.navigate("map") },
onNavigateToDrafts = { navController.navigate("drafts") },
onNavigateToExplorer = { navController.navigate("explorer") }
)
}
composable("map") {
// v2.2.3: Legacy-Editor — nur noch als interner Fallback erreichbar.
// Mode-Switch zwischen Karteneditor und Explorer entfällt, Explorer
// ist der zentrale Arbeitsbereich.
MapScreen(
viewModel = viewModel,
onNavigateBack = { navController.popBackStack() },
currentMode = null,
onModeChange = null
)
}
composable("explorer") {
// v2.4.0 — MapLibre Engine Cutover: aktiver Renderer ist jetzt MapLibre.
// Die osmdroid-Variante in [ExplorerScreen] bleibt im Quelltext als
// dokumentierter Fallback erhalten.
ExplorerScreenMapLibre(
viewModel = viewModel,
onNavigateBack = { navController.popBackStack() },
onOpenInEditor = { /* abgelöst — Explorer übernimmt */ },
onOpenDraft = { id -> navController.navigate("draft/$id") }
)
// Hinweis: ExplorerScreen (osmdroid) bleibt aus Build-/Symbol-
// Kompatibilität in der Sourcetree.
@Suppress("unused")
val osmdroidFallbackRef: @androidx.compose.runtime.Composable () -> Unit = {
ExplorerScreen(
viewModel = viewModel,
onNavigateBack = { navController.popBackStack() },
onOpenInEditor = { /* abgelöst — Explorer übernimmt */ },
onOpenDraft = { id -> navController.navigate("draft/$id") }
)
}
}
composable("drafts") {
TrackDraftListScreen(
viewModel = viewModel,
onOpenDraft = { id -> navController.navigate("draft/$id") },
onNavigateBack = { navController.popBackStack() }
)
}
composable(
route = "draft/{draftId}",
arguments = listOf(navArgument("draftId") { type = NavType.StringType })
) { backStackEntry ->
val id = backStackEntry.arguments?.getString("draftId") ?: ""
TrackDraftEditorScreen(
viewModel = viewModel,
draftId = id,
onNavigateBack = { navController.popBackStack() }
)
}
@@ -105,6 +259,16 @@ class MainActivity : ComponentActivity() {
if (locationPermissionsGranted.value) {
requestOptionalPermissions()
}
if (::wakeLockController.isInitialized) {
wakeLockController.onActivityResumed()
}
}
override fun onPause() {
if (::wakeLockController.isInitialized) {
wakeLockController.onActivityPaused()
}
super.onPause()
}
// ---------------------------------------------------------------------------