Füge Unterstützung für Push-Benachrichtigungen hinzu: Registriere das aktuelle Gerät bei der Anmeldung und synchronisiere den Push-Token.
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

This commit is contained in:
Torsten Schulz (local)
2026-09-08 16:00:05 +02:00
parent 65e7563e79
commit 3e981de770
4 changed files with 34 additions and 2 deletions

View File

@@ -21,9 +21,20 @@ import de.harheimertc.ui.navigation.NavigationViewModel
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import android.util.Log import android.util.Log
import androidx.compose.ui.platform.LocalContext 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 @AndroidEntryPoint
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@Inject
lateinit var authRepository: AuthRepository
@Inject
lateinit var pushTokenRepository: PushTokenRepository
private val notificationRoute = mutableStateOf<String?>(null) private val notificationRoute = mutableStateOf<String?>(null)
private val notificationPermissionLauncher = registerForActivityResult( private val notificationPermissionLauncher = registerForActivityResult(
@@ -50,6 +61,23 @@ class MainActivity : ComponentActivity() {
notificationRoute.value = extractNotificationRoute(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? = private fun extractNotificationRoute(intent: Intent?): String? =
intent?.getStringExtra(EXTRA_NOTIFICATION_ROUTE)?.takeIf { it.isNotBlank() } intent?.getStringExtra(EXTRA_NOTIFICATION_ROUTE)?.takeIf { it.isNotBlank() }

View File

@@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import de.harheimertc.repositories.LoginRepository import de.harheimertc.repositories.LoginRepository
import de.harheimertc.repositories.PasskeyRepository import de.harheimertc.repositories.PasskeyRepository
import de.harheimertc.repositories.PushTokenRepository
import de.harheimertc.ui.components.isValidEmail import de.harheimertc.ui.components.isValidEmail
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@@ -29,6 +30,7 @@ data class LoginUiState(
class LoginViewModel @Inject constructor( class LoginViewModel @Inject constructor(
private val repository: LoginRepository, private val repository: LoginRepository,
private val passkeyRepository: PasskeyRepository, private val passkeyRepository: PasskeyRepository,
private val pushTokenRepository: PushTokenRepository,
) : ViewModel() { ) : ViewModel() {
private val _state = MutableStateFlow(LoginUiState()) private val _state = MutableStateFlow(LoginUiState())
val state: StateFlow<LoginUiState> = _state val state: StateFlow<LoginUiState> = _state
@@ -70,6 +72,7 @@ class LoginViewModel @Inject constructor(
_state.value = current.copy(loading = true, error = null, message = null) _state.value = current.copy(loading = true, error = null, message = null)
repository.login(current.email, current.password) repository.login(current.email, current.password)
.onSuccess { response -> .onSuccess { response ->
viewModelScope.launch { pushTokenRepository.registerCurrentDevice() }
_state.value = current.copy( _state.value = current.copy(
password = "", password = "",
loading = false, loading = false,
@@ -92,6 +95,7 @@ class LoginViewModel @Inject constructor(
_state.value = current.copy(loading = true, error = null, message = null) _state.value = current.copy(loading = true, error = null, message = null)
passkeyRepository.login(context, current.email) passkeyRepository.login(context, current.email)
.onSuccess { response -> .onSuccess { response ->
viewModelScope.launch { pushTokenRepository.registerCurrentDevice() }
_state.value = current.copy( _state.value = current.copy(
password = "", password = "",
loading = false, loading = false,

View File

@@ -8,8 +8,8 @@ LOCAL_API_BASE_URL=https://harheimertc.tsschulz.de/
PRODUCTION_API_BASE_URL=https://harheimertc.de/ PRODUCTION_API_BASE_URL=https://harheimertc.de/
# Android app versioning for Play Store uploads # Android app versioning for Play Store uploads
ANDROID_VERSION_CODE=33 ANDROID_VERSION_CODE=34
ANDROID_VERSION_NAME=0.9.28 ANDROID_VERSION_NAME=0.9.29
# Temporary hotfix: disable R8 minification for release to avoid Retrofit generic signature stripping. # Temporary hotfix: disable R8 minification for release to avoid Retrofit generic signature stripping.
RELEASE_MINIFY_ENABLED=false RELEASE_MINIFY_ENABLED=false