chore: füge SyncManager und Peer-Zähler hinzu, verbessere Navigation-Breadcrumbs und passe MD3-Stil an
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
This commit is contained in:
@@ -24,8 +24,9 @@ Die Nachmittags-Session konzentriert sich auf die Bereinigung der App-Start-Sequ
|
|||||||
|
|
||||||
## 📅 Nächste Schritte
|
## 📅 Nächste Schritte
|
||||||
1. **🔐 Infrastruktur:** Integration des `ConnectivityTracker` zur Visualisierung von Backend-/DB-/Auth-Status (Plug-and-Play konform umgesetzt ✓).
|
1. **🔐 Infrastruktur:** Integration des `ConnectivityTracker` zur Visualisierung von Backend-/DB-/Auth-Status (Plug-and-Play konform umgesetzt ✓).
|
||||||
2. **📡 Discovery:** Start des `NetworkDiscoveryService` (mDNS) für die automatische Peer-Erkennung im LAN (Plug-and-Play konform umgesetzt ✓).
|
2. **📡 Discovery:** Start des `NetworkDiscoveryService` (mDNS) für die automatische Peer-Recogniton im LAN (Plug-and-Play konform umgesetzt ✓).
|
||||||
3. **🗺️ Layout:** Finalisierung der `Navigation-Rail` und des `Sync-Indikators`.
|
3. **🗺️ Layout:** Finalisierung der `Navigation-Rail` (MD3-Refinement), des `Sync-Indikators` (WebSocket-Peer-Zähler) und der navigierbaren `Breadcrumbs` (✓).
|
||||||
|
4. **🏟️ Fachlicher Einstieg:** `VeranstaltungVerwaltung` als Default-Landeseite nach Onboarding validiert (✓).
|
||||||
|
|
||||||
---
|
---
|
||||||
*Dokumentation erstellt durch den Curator im Rahmen des "Meldestelle"-Protokolls.*
|
*Dokumentation erstellt durch den Curator im Rahmen des "Meldestelle"-Protokolls.*
|
||||||
|
|||||||
+73
-29
@@ -25,6 +25,7 @@ import at.mocode.frontend.core.domain.zns.ZnsImportProvider
|
|||||||
import at.mocode.frontend.core.navigation.AppScreen
|
import at.mocode.frontend.core.navigation.AppScreen
|
||||||
import at.mocode.frontend.core.network.ConnectivityTracker
|
import at.mocode.frontend.core.network.ConnectivityTracker
|
||||||
import at.mocode.frontend.core.network.discovery.NetworkDiscoveryService
|
import at.mocode.frontend.core.network.discovery.NetworkDiscoveryService
|
||||||
|
import at.mocode.frontend.core.network.sync.SyncManager
|
||||||
import at.mocode.frontend.features.billing.presentation.BillingScreen
|
import at.mocode.frontend.features.billing.presentation.BillingScreen
|
||||||
import at.mocode.frontend.features.billing.presentation.BillingViewModel
|
import at.mocode.frontend.features.billing.presentation.BillingViewModel
|
||||||
import at.mocode.frontend.features.device.initialization.data.local.DeviceInitializationSettingsManager
|
import at.mocode.frontend.features.device.initialization.data.local.DeviceInitializationSettingsManager
|
||||||
@@ -88,6 +89,8 @@ fun DesktopMainLayout(
|
|||||||
onLogout: () -> Unit,
|
onLogout: () -> Unit,
|
||||||
isAuthenticated: Boolean = false
|
isAuthenticated: Boolean = false
|
||||||
) {
|
) {
|
||||||
|
val syncManager = koinInject<SyncManager>()
|
||||||
|
val connectedPeers by syncManager.getConnectedPeers().collectAsState(initial = emptyList())
|
||||||
println("[Navigation] Rendering Screen: ${currentScreen::class.simpleName} (Details: $currentScreen)")
|
println("[Navigation] Rendering Screen: ${currentScreen::class.simpleName} (Details: $currentScreen)")
|
||||||
// DeviceInitialization-Daten (On-the-fly geladen oder Default)
|
// DeviceInitialization-Daten (On-the-fly geladen oder Default)
|
||||||
var onboardingSettings by remember {
|
var onboardingSettings by remember {
|
||||||
@@ -118,7 +121,8 @@ fun DesktopMainLayout(
|
|||||||
onNavigate = onNavigate,
|
onNavigate = onNavigate,
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onLogout = onLogout,
|
onLogout = onLogout,
|
||||||
isAuthenticated = isAuthenticated
|
isAuthenticated = isAuthenticated,
|
||||||
|
connectedPeersCount = connectedPeers.size
|
||||||
)
|
)
|
||||||
|
|
||||||
Box(modifier = Modifier.weight(1f).fillMaxWidth()) {
|
Box(modifier = Modifier.weight(1f).fillMaxWidth()) {
|
||||||
@@ -150,8 +154,8 @@ private fun DesktopNavRail(
|
|||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxHeight().width(Dimens.NavRailWidth),
|
modifier = Modifier.fillMaxHeight().width(Dimens.NavRailWidth),
|
||||||
color = AppColors.NavigationSurface,
|
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f),
|
||||||
contentColor = AppColors.NavigationContent,
|
tonalElevation = 2.dp
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxHeight().padding(vertical = Dimens.SpacingM),
|
modifier = Modifier.fillMaxHeight().padding(vertical = Dimens.SpacingM),
|
||||||
@@ -160,7 +164,7 @@ private fun DesktopNavRail(
|
|||||||
) {
|
) {
|
||||||
// App Icon / Logo Platzhalter
|
// App Icon / Logo Platzhalter
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.size(40.dp),
|
modifier = Modifier.size(40.dp).clickable { onNavigate(AppScreen.VeranstaltungVerwaltung) },
|
||||||
shape = MaterialTheme.shapes.medium,
|
shape = MaterialTheme.shapes.medium,
|
||||||
color = MaterialTheme.colorScheme.primary
|
color = MaterialTheme.colorScheme.primary
|
||||||
) {
|
) {
|
||||||
@@ -283,8 +287,8 @@ private fun NavRailItem(
|
|||||||
enabled: Boolean = true
|
enabled: Boolean = true
|
||||||
) {
|
) {
|
||||||
val contentAlpha = if (enabled) 1.0f else 0.38f
|
val contentAlpha = if (enabled) 1.0f else 0.38f
|
||||||
val tint = if (selected) MaterialTheme.colorScheme.primary else AppColors.NavigationContent.copy(alpha = contentAlpha)
|
val tint = if (selected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = contentAlpha)
|
||||||
val background = if (selected) MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.5f) else Color.Transparent
|
val background = if (selected) MaterialTheme.colorScheme.primaryContainer else Color.Transparent
|
||||||
|
|
||||||
TooltipBox(
|
TooltipBox(
|
||||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
|
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(
|
||||||
@@ -328,7 +332,8 @@ private fun DesktopTopHeader(
|
|||||||
onNavigate: (AppScreen) -> Unit,
|
onNavigate: (AppScreen) -> Unit,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onLogout: () -> Unit,
|
onLogout: () -> Unit,
|
||||||
isAuthenticated: Boolean
|
isAuthenticated: Boolean,
|
||||||
|
connectedPeersCount: Int = 0
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxWidth().height(Dimens.TopBarHeight),
|
modifier = Modifier.fillMaxWidth().height(Dimens.TopBarHeight),
|
||||||
@@ -361,6 +366,31 @@ private fun DesktopTopHeader(
|
|||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.spacedBy(Dimens.SpacingM)
|
horizontalArrangement = Arrangement.spacedBy(Dimens.SpacingM)
|
||||||
) {
|
) {
|
||||||
|
// Sync-Status Indikator
|
||||||
|
val syncColor = if (connectedPeersCount > 0) AppColors.Success else MaterialTheme.colorScheme.outline
|
||||||
|
val syncText = if (connectedPeersCount > 0) "$connectedPeersCount Peer(s)" else "Offline"
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(Dimens.SpacingS),
|
||||||
|
modifier = Modifier
|
||||||
|
.background(syncColor.copy(alpha = 0.1f), MaterialTheme.shapes.small)
|
||||||
|
.padding(horizontal = Dimens.SpacingS, vertical = 4.dp)
|
||||||
|
) {
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier.size(8.dp),
|
||||||
|
shape = MaterialTheme.shapes.extraSmall,
|
||||||
|
color = syncColor
|
||||||
|
) {}
|
||||||
|
Text(
|
||||||
|
text = syncText,
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
color = syncColor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
VerticalDivider(modifier = Modifier.height(16.dp), thickness = 1.dp, color = MaterialTheme.colorScheme.outlineVariant)
|
||||||
|
|
||||||
// Profil / Logout Bereich
|
// Profil / Logout Bereich
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
Text(
|
Text(
|
||||||
@@ -460,19 +490,39 @@ private fun BreadcrumbContent(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is AppScreen.VeranstaltungVerwaltung -> {
|
||||||
|
BreadcrumbSeparator()
|
||||||
|
Text(
|
||||||
|
text = "Veranstaltungs-Verwaltung",
|
||||||
|
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
is AppScreen.VeranstaltungDetail -> {
|
is AppScreen.VeranstaltungDetail -> {
|
||||||
|
BreadcrumbSeparator()
|
||||||
|
Text(
|
||||||
|
text = "Veranstaltungs-Verwaltung",
|
||||||
|
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f)),
|
||||||
|
modifier = Modifier.clickable { onNavigate(AppScreen.VeranstaltungVerwaltung) },
|
||||||
|
)
|
||||||
BreadcrumbSeparator()
|
BreadcrumbSeparator()
|
||||||
Text(
|
Text(
|
||||||
text = "Veranstaltung #${currentScreen.id}",
|
text = "Veranstaltung #${currentScreen.id}",
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
is AppScreen.VeranstaltungNeu -> {
|
is AppScreen.VeranstaltungNeu -> {
|
||||||
|
BreadcrumbSeparator()
|
||||||
|
Text(
|
||||||
|
text = "Veranstaltungs-Verwaltung",
|
||||||
|
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f)),
|
||||||
|
modifier = Modifier.clickable { onNavigate(AppScreen.VeranstaltungVerwaltung) },
|
||||||
|
)
|
||||||
BreadcrumbSeparator()
|
BreadcrumbSeparator()
|
||||||
Text(
|
Text(
|
||||||
text = "Neue Veranstaltung",
|
text = "Neue Veranstaltung",
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,14 +530,14 @@ private fun BreadcrumbContent(
|
|||||||
BreadcrumbSeparator()
|
BreadcrumbSeparator()
|
||||||
Text(
|
Text(
|
||||||
text = "Veranstaltung #${currentScreen.veranstaltungId}",
|
text = "Veranstaltung #${currentScreen.veranstaltungId}",
|
||||||
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.75f)),
|
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f)),
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier.clickable {
|
||||||
onNavigate(AppScreen.VeranstaltungDetail(currentScreen.veranstaltungId))
|
onNavigate(AppScreen.VeranstaltungDetail(currentScreen.veranstaltungId))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
BreadcrumbSeparator()
|
BreadcrumbSeparator()
|
||||||
Text(
|
Text(
|
||||||
text = "Turnier ${currentScreen.turnierId}",
|
text = "Turnier #${currentScreen.turnierId}",
|
||||||
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
|
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -496,17 +546,9 @@ private fun BreadcrumbContent(
|
|||||||
BreadcrumbSeparator()
|
BreadcrumbSeparator()
|
||||||
Text(
|
Text(
|
||||||
text = "Veranstaltung #${currentScreen.veranstaltungId}",
|
text = "Veranstaltung #${currentScreen.veranstaltungId}",
|
||||||
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.75f)),
|
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f)),
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier.clickable {
|
||||||
onNavigate(AppScreen.VeranstaltungProfil(0, currentScreen.veranstaltungId))
|
onNavigate(AppScreen.VeranstaltungDetail(currentScreen.veranstaltungId))
|
||||||
},
|
|
||||||
)
|
|
||||||
BreadcrumbSeparator()
|
|
||||||
Text(
|
|
||||||
text = "Turnier ${currentScreen.turnierId}",
|
|
||||||
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.75f)),
|
|
||||||
modifier = Modifier.clickable {
|
|
||||||
onNavigate(AppScreen.TurnierDetail(currentScreen.veranstaltungId, currentScreen.turnierId))
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
BreadcrumbSeparator()
|
BreadcrumbSeparator()
|
||||||
@@ -520,7 +562,7 @@ private fun BreadcrumbContent(
|
|||||||
BreadcrumbSeparator()
|
BreadcrumbSeparator()
|
||||||
Text(
|
Text(
|
||||||
text = "Veranstaltung #${currentScreen.veranstaltungId}",
|
text = "Veranstaltung #${currentScreen.veranstaltungId}",
|
||||||
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.75f)),
|
style = MaterialTheme.typography.bodyMedium.copy(color = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f)),
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier.clickable {
|
||||||
onNavigate(AppScreen.VeranstaltungDetail(currentScreen.veranstaltungId))
|
onNavigate(AppScreen.VeranstaltungDetail(currentScreen.veranstaltungId))
|
||||||
},
|
},
|
||||||
@@ -528,7 +570,7 @@ private fun BreadcrumbContent(
|
|||||||
BreadcrumbSeparator()
|
BreadcrumbSeparator()
|
||||||
Text(
|
Text(
|
||||||
text = "Neues Turnier",
|
text = "Neues Turnier",
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1072,18 +1114,20 @@ private fun StatusIndicator(
|
|||||||
label: String,
|
label: String,
|
||||||
color: Color
|
color: Color
|
||||||
) {
|
) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
imageVector = icon,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = color,
|
tint = color.copy(alpha = 0.8f),
|
||||||
modifier = Modifier.size(Dimens.IconSizeS)
|
modifier = Modifier.size(14.dp)
|
||||||
)
|
)
|
||||||
Spacer(Modifier.width(Dimens.SpacingXS))
|
|
||||||
Text(
|
Text(
|
||||||
text = label,
|
text = label,
|
||||||
style = MaterialTheme.typography.labelSmall,
|
style = MaterialTheme.typography.labelSmall.copy(fontSize = 10.sp),
|
||||||
color = MaterialTheme.colorScheme.onSurface
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user