fixed deploy and navigation
Some checks failed
Code Analysis and Production Deploy / deploy-production (push) Has been cancelled
Code Analysis and Production Deploy / analyze (push) Has been cancelled
Code Analysis and Production Deploy / deploy-test (push) Has been cancelled

This commit is contained in:
Torsten Schulz (local)
2026-06-10 16:36:50 +02:00
parent 7e533fae49
commit 14cd5f04d5
6 changed files with 97 additions and 8 deletions

View File

@@ -11,7 +11,8 @@
android:theme="@style/Theme.HarheimerTC"
android:usesCleartextTraffic="${usesCleartextTraffic}">
<activity android:name="de.harheimertc.MainActivity"
android:exported="true">
android:exported="true"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

View File

@@ -1,12 +1,15 @@
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
@@ -21,6 +24,8 @@ import androidx.compose.ui.platform.LocalContext
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
private val notificationRoute = mutableStateOf<String?>(null)
private val notificationPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission(),
) { granted ->
@@ -30,26 +35,56 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestNotificationPermissionIfNeeded()
notificationRoute.value = extractNotificationRoute(intent)
setContent {
App()
App(
notificationRoute = notificationRoute.value,
onNotificationRouteConsumed = { notificationRoute.value = null },
)
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
notificationRoute.value = extractNotificationRoute(intent)
}
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() {
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)
}
}

View File

@@ -37,7 +37,7 @@ class HarheimerMessagingService : FirebaseMessagingService() {
val notificationId = message.data["notificationId"]?.toIntOrNull()
?: message.messageId?.hashCode()
?: System.currentTimeMillis().toInt()
val shown = HarheimerNotifications.showBasicNotification(this, notificationId, title, body)
val shown = HarheimerNotifications.showBasicNotification(this, notificationId, title, body, message.data)
Log.d("HarheimerMessaging", "Push message received type=${message.data["type"]}, shown=$shown")
}
}

View File

@@ -3,13 +3,17 @@ package de.harheimertc.notifications
import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import de.harheimertc.MainActivity
import de.harheimertc.R
import de.harheimertc.ui.navigation.Destinations
object HarheimerNotifications {
const val DEFAULT_CHANNEL_ID = "harheimer_tc_updates"
@@ -35,6 +39,7 @@ object HarheimerNotifications {
notificationId: Int,
title: String,
message: String,
data: Map<String, String> = emptyMap(),
): Boolean {
if (!hasNotificationPermission(context)) return false
val notification = NotificationCompat.Builder(context, DEFAULT_CHANNEL_ID)
@@ -43,9 +48,31 @@ object HarheimerNotifications {
.setContentText(message)
.setStyle(NotificationCompat.BigTextStyle().bigText(message))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(createContentIntent(context, notificationId, data))
.setAutoCancel(true)
.build()
NotificationManagerCompat.from(context).notify(notificationId, notification)
return true
}
private fun createContentIntent(context: Context, notificationId: Int, payload: Map<String, String>): PendingIntent {
val route = destinationRoute(payload)
val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
putExtra(MainActivity.EXTRA_NOTIFICATION_TYPE, payload["type"])
putExtra(MainActivity.EXTRA_NOTIFICATION_ROUTE, route)
payload["newsId"]?.let { putExtra(MainActivity.EXTRA_NEWS_ID, it) }
}
return PendingIntent.getActivity(
context,
notificationId,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
private fun destinationRoute(data: Map<String, String>): String = when (data["type"]) {
"news" -> Destinations.MemberNews.route
else -> Destinations.Home.route
}
}

View File

@@ -279,9 +279,25 @@ use_project_node
ensure_node_version
install_dependencies_if_needed
# 4. Remove old build (but keep data!)
# 4. Stop running apps before replacing build artifacts
echo ""
echo "4. Cleaning build artifacts..."
echo "4. Stopping PM2 before replacing build artifacts..."
if command -v pm2 >/dev/null 2>&1; then
for instance_name in harheimertc harheimertc-3102; do
if pm2 describe "$instance_name" >/dev/null 2>&1; then
pm2 stop "$instance_name" || true
echo "$instance_name gestoppt"
else
echo " PM2-Prozess $instance_name läuft nicht"
fi
done
else
echo " PM2 ist nicht verfügbar"
fi
# 5. Remove old build (but keep data!)
echo ""
echo "5. Cleaning build artifacts..."
# Sicherstellen, dass .output vollständig gelöscht wird
if [ -d ".output" ]; then
echo " Removing .output directory..."

View File

@@ -285,9 +285,19 @@ use_project_node
ensure_node_version
install_dependencies_if_needed
# 4. Remove old build (but keep data!)
# 4. Stop running app before replacing build artifacts
echo ""
echo "4. Cleaning build artifacts..."
echo "4. Stopping PM2 before replacing build artifacts..."
if command -v pm2 >/dev/null 2>&1 && pm2 describe harheimertc.test >/dev/null 2>&1; then
pm2 stop harheimertc.test || true
echo " ✓ harheimertc.test gestoppt"
else
echo " PM2-Prozess harheimertc.test läuft nicht oder PM2 ist nicht verfügbar"
fi
# 5. Remove old build (but keep data!)
echo ""
echo "5. Cleaning build artifacts..."
# Sicherstellen, dass .output vollständig gelöscht wird
if [ -d ".output" ]; then
echo " Removing .output directory..."