Files
harheimertc/android-app/app/src/main/java/de/harheimertc/MainActivity.kt
Torsten Schulz (local) 3e981de770
All checks were successful
Code Analysis and Production Deploy / analyze (push) Successful in 4m41s
Code Analysis and Production Deploy / deploy-production (push) Has been skipped
Code Analysis and Production Deploy / deploy-test (push) Successful in 2m43s
Füge Unterstützung für Push-Benachrichtigungen hinzu: Registriere das aktuelle Gerät bei der Anmeldung und synchronisiere den Push-Token.
2026-09-08 16:00:05 +02:00

125 lines
4.4 KiB
Kotlin
Executable File

package de.harheimertc
import android.Manifest
import android.content.Intent
import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.compose.setContent
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.compose.rememberNavController
import de.harheimertc.ui.navigation.NavGraph
import de.harheimertc.ui.navigation.Destinations
import de.harheimertc.notifications.HarheimerNotifications
import de.harheimertc.ui.theme.HarheimerTheme
import androidx.hilt.navigation.compose.hiltViewModel
import de.harheimertc.ui.navigation.NavigationViewModel
import dagger.hilt.android.AndroidEntryPoint
import android.util.Log
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.lifecycleScope
import de.harheimertc.repositories.AuthRepository
import de.harheimertc.repositories.PushTokenRepository
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject
lateinit var authRepository: AuthRepository
@Inject
lateinit var pushTokenRepository: PushTokenRepository
private val notificationRoute = mutableStateOf<String?>(null)
private val notificationPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission(),
) { granted ->
Log.i("NOTIFICATIONS", "POST_NOTIFICATIONS granted=$granted")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestNotificationPermissionIfNeeded()
notificationRoute.value = extractNotificationRoute(intent)
setContent {
App(
notificationRoute = notificationRoute.value,
onNotificationRouteConsumed = { notificationRoute.value = null },
)
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
notificationRoute.value = extractNotificationRoute(intent)
}
override fun onResume() {
super.onResume()
syncPushTokenWhenSignedIn()
}
/**
* Server-side tokens are persistent, but re-registering the current FCM
* token is cheap and idempotent. It restores a token if server data was
* ever recovered from a backup or manually repaired.
*/
private fun syncPushTokenWhenSignedIn() {
if (authRepository.getToken().isNullOrBlank() && authRepository.getRefreshToken().isNullOrBlank()) return
lifecycleScope.launch {
pushTokenRepository.registerCurrentDevice()
}
}
private fun extractNotificationRoute(intent: Intent?): String? =
intent?.getStringExtra(EXTRA_NOTIFICATION_ROUTE)?.takeIf { it.isNotBlank() }
private fun requestNotificationPermissionIfNeeded() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && !HarheimerNotifications.hasNotificationPermission(this)) {
notificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}
companion object {
const val EXTRA_NOTIFICATION_TYPE = "de.harheimertc.extra.NOTIFICATION_TYPE"
const val EXTRA_NOTIFICATION_ROUTE = "de.harheimertc.extra.NOTIFICATION_ROUTE"
const val EXTRA_NEWS_ID = "de.harheimertc.extra.NEWS_ID"
}
}
@Composable
fun App(
notificationRoute: String? = null,
onNotificationRouteConsumed: () -> Unit = {},
) {
HarheimerTheme {
val navController = rememberNavController()
val ctx = LocalContext.current
val activity = ctx as? ComponentActivity
Log.i("HILT_FACTORY", "defaultViewModelProviderFactory=${activity?.defaultViewModelProviderFactory?.javaClass?.name}")
val navigationViewModel: NavigationViewModel = hiltViewModel()
LaunchedEffect(notificationRoute) {
val route = notificationRoute?.takeIf { it.isNotBlank() } ?: return@LaunchedEffect
navController.navigate(route) {
launchSingleTop = true
popUpTo(Destinations.Home.route)
}
onNotificationRouteConsumed()
}
NavGraph(navController = navController, navigationViewModelParam = navigationViewModel)
}
}
@Preview
@Composable
fun PreviewMain() {
App()
}