diff --git a/android-app/app/build.gradle.kts b/android-app/app/build.gradle.kts index ace652e..357aed4 100644 --- a/android-app/app/build.gradle.kts +++ b/android-app/app/build.gradle.kts @@ -13,6 +13,7 @@ val localApiBaseUrl = providers.gradleProperty("LOCAL_API_BASE_URL") val productionApiBaseUrl = providers.gradleProperty("PRODUCTION_API_BASE_URL") .orElse("https://harheimertc.de/") .get() +val expectedProductionApiBaseUrl = "https://harheimertc.de/" val sentryDsn = providers.gradleProperty("SENTRY_DSN") .orElse("") .get() @@ -61,6 +62,16 @@ val ensureReleaseSigning = tasks.register("ensureReleaseSigning") { } } +val ensureProductionApiBaseUrl = tasks.register("ensureProductionApiBaseUrl") { + doFirst { + if (productionApiBaseUrl != expectedProductionApiBaseUrl) { + throw GradleException( + "Production Play Store builds must use $expectedProductionApiBaseUrl, but PRODUCTION_API_BASE_URL is $productionApiBaseUrl." + ) + } + } +} + android { namespace = "de.harheimertc" compileSdk = 35 @@ -163,6 +174,7 @@ val collectPlayStoreArtifacts = tasks.register("collectPlayStoreArtifacts") { group = "distribution" description = "Builds production release artifacts and collects AAB, mapping, and native symbols for Play Console upload." dependsOn(ensureReleaseSigning) + dependsOn(ensureProductionApiBaseUrl) dependsOn(":app:bundleProductionRelease") dependsOn(packageNativeDebugSymbolsForProductionRelease) @@ -193,6 +205,7 @@ tasks.matching { it.name in setOf("bundleProductionRelease", "assembleProductionRelease") }.configureEach { dependsOn(ensureReleaseSigning) + dependsOn(ensureProductionApiBaseUrl) } kotlin { diff --git a/android-app/app/src/main/java/de/harheimertc/ui/components/AppNavigationHeader.kt b/android-app/app/src/main/java/de/harheimertc/ui/components/AppNavigationHeader.kt index ffabfbe..d7f4cb9 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/components/AppNavigationHeader.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/components/AppNavigationHeader.kt @@ -90,7 +90,7 @@ private fun CompactNavigation( BrandRow( loggedIn = navigationState.loggedIn, onLogin = { onNavigate(Destinations.Login.route) }, - onOpenCms = { sectionOverride.value = MenuSection.CMS }, + onLogout = onLogout, ) ScrollableMenuRow(scrollState = mainScroll) { @@ -106,6 +106,9 @@ private fun CompactNavigation( } if (navigationState.loggedIn) { CompactSectionLink("Intern", MenuSection.INTERN, section) { sectionOverride.value = MenuSection.INTERN } + if (navigationState.canAccessCms) { + CompactSectionLink("CMS", MenuSection.CMS, section) { sectionOverride.value = MenuSection.CMS } + } } else { CompactLink("Login", Destinations.Login.route, selectedRoute, onNavigate) { sectionOverride.value = null } } @@ -202,6 +205,12 @@ private fun WebTabletNavigation( MainLink("Intern", section == MenuSection.INTERN, onClick = { sectionOverride.value = MenuSection.INTERN }) + if (navigationState.canAccessCms) { + MainLink("CMS", section == MenuSection.CMS, onClick = { + sectionOverride.value = MenuSection.CMS + onNavigate(Destinations.Cms.route) + }) + } } MainLink("Kontakt", selectedRoute == Destinations.Contact.route, primary = true, onClick = { sectionOverride.value = null @@ -210,7 +219,7 @@ private fun WebTabletNavigation( } Spacer(Modifier.width(12.dp)) if (navigationState.loggedIn) { - TextButton(onClick = { sectionOverride.value = MenuSection.CMS }) { Text("CMS", color = Color.White) } + TextButton(onClick = onLogout) { Text("Logout", color = Color.White) } } else { TextButton(onClick = { sectionOverride.value = null @@ -237,13 +246,13 @@ private fun WebTabletNavigation( private fun BrandRow( loggedIn: Boolean, onLogin: () -> Unit, - onOpenCms: () -> Unit, + onLogout: () -> Unit, ) { Row(verticalAlignment = Alignment.CenterVertically) { Brand() Spacer(Modifier.weight(1f)) if (loggedIn) { - TextButton(onClick = onOpenCms) { Text("CMS", color = Color.White) } + TextButton(onClick = onLogout) { Text("Logout", color = Color.White) } } else { TextButton(onClick = onLogin) { Text("Login", color = Color.White) } } @@ -465,23 +474,23 @@ private fun submenu(section: MenuSection?, state: NavigationUiState): List buildList { + if (state.canAccessFullCms) { + add(MenuTarget("Übersicht", Destinations.Cms.route)) + add(MenuTarget("Startseite", Destinations.CmsStartseite.route)) + add(MenuTarget("Inhalte", Destinations.CmsInhalte.route)) + add(MenuTarget("Vereinsmeisterschaften", Destinations.CmsVereinsmeisterschaften.route)) + add(MenuTarget("News", Destinations.MemberNews.route)) + add(MenuTarget("Sportbetrieb", Destinations.CmsSportbetrieb.route)) + add(MenuTarget("Mitgliederverwaltung", Destinations.CmsMitgliederverwaltung.route)) + add(MenuTarget("Einstellungen", Destinations.CmsEinstellungen.route)) + add(MenuTarget("Benutzerverwaltung", Destinations.CmsBenutzer.route)) + } if (state.canAccessNewsletter) add(MenuTarget("Newsletter", Destinations.CmsNewsletter.route)) if (state.canAccessContactRequests) add(MenuTarget("Kontaktanfragen", Destinations.CmsContactRequests.route)) } - MenuSection.CMS -> buildList { - add(MenuTarget("Übersicht", Destinations.Cms.route)) - add(MenuTarget("Startseite", Destinations.CmsStartseite.route)) - add(MenuTarget("Inhalte", Destinations.CmsInhalte.route)) - add(MenuTarget("Vereinsmeisterschaften", Destinations.CmsVereinsmeisterschaften.route)) - add(MenuTarget("News", Destinations.MemberNews.route)) - add(MenuTarget("Sportbetrieb", Destinations.CmsSportbetrieb.route)) - add(MenuTarget("Mitgliederverwaltung", Destinations.CmsMitgliederverwaltung.route)) - add(MenuTarget("Kontaktanfragen", Destinations.CmsContactRequests.route)) - add(MenuTarget("Einstellungen", Destinations.CmsEinstellungen.route)) - add(MenuTarget("Benutzerverwaltung", Destinations.CmsBenutzer.route)) - add(MenuTarget("Ausloggen", LOGOUT_ROUTE)) - } - null -> emptyList() } diff --git a/android-app/app/src/main/java/de/harheimertc/ui/components/LoadingState.kt b/android-app/app/src/main/java/de/harheimertc/ui/components/LoadingState.kt new file mode 100644 index 0000000..809fb2f --- /dev/null +++ b/android-app/app/src/main/java/de/harheimertc/ui/components/LoadingState.kt @@ -0,0 +1,24 @@ +package de.harheimertc.ui.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import de.harheimertc.ui.theme.Accent500 +import de.harheimertc.ui.theme.Primary600 + +@Composable +internal fun LoadingState(message: String = "Daten werden geladen...") { + Column( + modifier = Modifier.fillMaxWidth().padding(28.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + CircularProgressIndicator(color = Primary600) + Text(message, color = Accent500, modifier = Modifier.padding(top = 12.dp)) + } +} \ No newline at end of file diff --git a/android-app/app/src/main/java/de/harheimertc/ui/navigation/NavigationViewModel.kt b/android-app/app/src/main/java/de/harheimertc/ui/navigation/NavigationViewModel.kt index 2cd8156..c8c97e7 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/navigation/NavigationViewModel.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/navigation/NavigationViewModel.kt @@ -23,8 +23,10 @@ data class NavigationUiState( val connectionNote: String? = null, ) { val isAdmin: Boolean get() = "admin" in roles + val canAccessFullCms: Boolean get() = roles.any { it in setOf("admin", "vorstand") } val canAccessNewsletter: Boolean get() = roles.any { it in setOf("admin", "vorstand", "newsletter") } val canAccessContactRequests: Boolean get() = roles.any { it in setOf("admin", "vorstand", "trainer") } + val canAccessCms: Boolean get() = canAccessFullCms || canAccessNewsletter || canAccessContactRequests val showGallery: Boolean get() = hasGalleryImages || canAccessNewsletter } diff --git a/android-app/app/src/main/java/de/harheimertc/ui/screens/cms/CmsNewsScreens.kt b/android-app/app/src/main/java/de/harheimertc/ui/screens/cms/CmsNewsScreens.kt index e30e3d9..6264c27 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/screens/cms/CmsNewsScreens.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/screens/cms/CmsNewsScreens.kt @@ -12,7 +12,6 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Checkbox import androidx.compose.material3.Text @@ -36,6 +35,7 @@ import androidx.compose.ui.platform.LocalContext import de.harheimertc.data.NewsDto import de.harheimertc.data.NewsSaveRequest import de.harheimertc.ui.components.FormMessages +import de.harheimertc.ui.components.LoadingState import de.harheimertc.ui.components.NativeRichTextEditor import de.harheimertc.ui.navigation.Destinations import kotlinx.coroutines.launch @@ -112,7 +112,7 @@ fun CmsNewsScreen(navController: NavController, showBackNavigation: Boolean, vie } CmsPage(navController, showBackNavigation, "News", "Interne und öffentliche News") { - if (state.loading) item { CircularProgressIndicator() } + if (state.loading) item { LoadingState("News werden geladen...") } item { Button(onClick = { viewModel.load(); /* ensure latest */ }, modifier = Modifier.fillMaxWidth()) { Text("Neu laden") } diff --git a/android-app/app/src/main/java/de/harheimertc/ui/screens/cms/CmsScreens.kt b/android-app/app/src/main/java/de/harheimertc/ui/screens/cms/CmsScreens.kt index 260cb39..1ef296f 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/screens/cms/CmsScreens.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/screens/cms/CmsScreens.kt @@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -50,6 +49,7 @@ import de.harheimertc.data.PasswordResetMatchingUserDto import de.harheimertc.data.PasswordResetAttemptDto import de.harheimertc.data.PasswordResetStepDto import de.harheimertc.ui.components.FormMessages +import de.harheimertc.ui.components.LoadingState import de.harheimertc.ui.components.NativeRichTextEditor import de.harheimertc.ui.navigation.Destinations import de.harheimertc.repositories.MeisterschaftResult @@ -67,7 +67,7 @@ import java.util.Locale fun CmsDashboardScreen(navController: NavController, showBackNavigation: Boolean, viewModel: CmsViewModel = hiltViewModel()) { val state by viewModel.state.collectAsState() CmsPage(navController, showBackNavigation, "CMS", "Verwaltung und interne Werkzeuge") { - if (state.loading) item { CircularProgressIndicator(color = Primary600) } + if (state.loading) item { LoadingState("CMS-Daten werden geladen...") } item { CmsSummaryGrid(navController, state) } } } @@ -85,7 +85,7 @@ fun CmsStartseiteScreen(navController: NavController, showBackNavigation: Boolea CmsPage(navController, showBackNavigation, "Startseite konfigurieren", "Legen Sie die Reihenfolge der Elemente auf der Startseite fest.") { when { - state.loading || config == null -> item { CircularProgressIndicator(color = Primary600) } + state.loading || config == null -> item { LoadingState("Startseitenkonfiguration wird geladen...") } else -> { item { Button( @@ -171,7 +171,7 @@ fun CmsInhalteScreen(navController: NavController, showBackNavigation: Boolean, CmsPage(navController, showBackNavigation, "Inhalte", "Vereinsseiten und strukturierte Inhalte") { when { - state.loading || config == null -> item { CircularProgressIndicator(color = Primary600) } + state.loading || config == null -> item { LoadingState("Inhalte werden geladen...") } else -> { item { Surface(color = Color.White, shape = RoundedCornerShape(14.dp), shadowElevation = 3.dp) { @@ -262,7 +262,7 @@ fun CmsVereinsmeisterschaftenScreen(navController: NavController, showBackNaviga CmsPage(navController, showBackNavigation, "Vereinsmeisterschaften", "Ergebnisse und Hinweise als CSV-Inhalt bearbeiten") { when { - state.loading -> item { CircularProgressIndicator(color = Primary600) } + state.loading -> item { LoadingState("Vereinsmeisterschaften werden geladen...") } else -> { item { Row(horizontalArrangement = Arrangement.spacedBy(12.dp), modifier = Modifier.fillMaxWidth()) { @@ -456,7 +456,7 @@ fun CmsSportbetriebScreen(navController: NavController, showBackNavigation: Bool CmsPage(navController, showBackNavigation, "Sportbetrieb", "Trainingszeiten, Trainingsort und Trainer pflegen") { when { - state.loading || config == null -> item { CircularProgressIndicator(color = Primary600) } + state.loading || config == null -> item { LoadingState("Sportbetriebsdaten werden geladen...") } else -> { item { Button( @@ -555,7 +555,7 @@ fun CmsMitgliederverwaltungScreen(navController: NavController, showBackNavigati fun CmsContactRequestsScreen(navController: NavController, showBackNavigation: Boolean, viewModel: CmsViewModel = hiltViewModel()) { val state by viewModel.state.collectAsState() CmsPage(navController, showBackNavigation, "Kontaktanfragen", "Eingegangene Nachrichten") { - if (state.loading) item { CircularProgressIndicator(color = Primary600) } + if (state.loading) item { LoadingState("Kontaktanfragen werden geladen...") } if (!state.loading && state.contactRequests.isEmpty()) item { EmptyCard("Keine Kontaktanfragen gefunden.") } items(state.contactRequests.size) { index -> ContactRequestCard(state.contactRequests[index], viewModel) } } @@ -592,7 +592,7 @@ fun CmsNewsletterScreen( var grpTargetGroup by remember { mutableStateOf("") } var grpSendToExternal by remember { mutableStateOf(true) } CmsPage(navController, showBackNavigation, "Newsletter", "Newsletter und Gruppen") { - if (state.loading) item { CircularProgressIndicator(color = Primary600) } + if (state.loading) item { LoadingState("Newsletter-Daten werden geladen...") } item { if (canWrite) Button(onClick = { editingNewsletter = null @@ -769,7 +769,7 @@ fun CmsEinstellungenScreen(navController: NavController, showBackNavigation: Boo CmsPage(navController, showBackNavigation, "Einstellungen", "Vereins- und Website-Konfiguration") { when { - state.loading || config == null -> item { CircularProgressIndicator(color = Primary600) } + state.loading || config == null -> item { LoadingState("Einstellungen werden geladen...") } else -> { item { Button( @@ -883,7 +883,7 @@ fun CmsPasswordResetDiagnosticsScreen(navController: NavController, showBackNavi } if (state.loading) { - item { CircularProgressIndicator(color = Primary600) } + item { LoadingState("Diagnosedaten werden geladen...") } } if (state.passwordResetSearchTerm.isNotBlank()) { @@ -1073,7 +1073,7 @@ private fun CmsConfigPage( ) { CmsPage(navController, showBackNavigation, title, subtitle) { if (config == null) { - item { CircularProgressIndicator(color = Primary600) } + item { LoadingState("Konfiguration wird geladen...") } } else { item { Surface(color = Color.White, shape = RoundedCornerShape(14.dp), shadowElevation = 3.dp) { diff --git a/android-app/app/src/main/java/de/harheimertc/ui/screens/gallery/GalleryScreen.kt b/android-app/app/src/main/java/de/harheimertc/ui/screens/gallery/GalleryScreen.kt index d9c2515..2d16dfe 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/screens/gallery/GalleryScreen.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/screens/gallery/GalleryScreen.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.Checkbox -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ElevatedCard import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField @@ -36,6 +35,7 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import de.harheimertc.R import de.harheimertc.ui.components.FormMessages +import de.harheimertc.ui.components.LoadingState import de.harheimertc.ui.components.ImageGrid @Composable @@ -131,7 +131,7 @@ fun GalleryScreen(viewModel: GalleryViewModel = hiltViewModel()) { Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { if (loading) { - CircularProgressIndicator() + LoadingState("Galerie wird geladen...") } else if (images.isEmpty()) { Text(text = stringResource(R.string.gallery_empty)) } else { diff --git a/android-app/app/src/main/java/de/harheimertc/ui/screens/mannschaften/MannschaftenScreen.kt b/android-app/app/src/main/java/de/harheimertc/ui/screens/mannschaften/MannschaftenScreen.kt index bc8dbdc..ec09e90 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/screens/mannschaften/MannschaftenScreen.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/screens/mannschaften/MannschaftenScreen.kt @@ -17,7 +17,6 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.MaterialTheme @@ -45,6 +44,7 @@ import androidx.navigation.NavController import de.harheimertc.data.SpielDto import de.harheimertc.data.LeagueTableRowDto import de.harheimertc.repositories.Mannschaft +import de.harheimertc.ui.components.LoadingState import de.harheimertc.ui.navigation.Destinations import de.harheimertc.ui.theme.Accent100 import de.harheimertc.ui.theme.Accent500 @@ -424,9 +424,7 @@ private fun BackLink(navController: NavController, visible: Boolean) { @Composable private fun Loading() { - Column(Modifier.fillMaxWidth().padding(30.dp), horizontalAlignment = Alignment.CenterHorizontally) { - CircularProgressIndicator(color = Primary600) - } + LoadingState("Mannschaftsdaten werden geladen...") } @Composable diff --git a/android-app/app/src/main/java/de/harheimertc/ui/screens/memberarea/MemberAreaDetailScreens.kt b/android-app/app/src/main/java/de/harheimertc/ui/screens/memberarea/MemberAreaDetailScreens.kt index a1521d6..7aa215f 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/screens/memberarea/MemberAreaDetailScreens.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/screens/memberarea/MemberAreaDetailScreens.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Checkbox -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Surface @@ -39,6 +38,7 @@ import androidx.navigation.NavController import de.harheimertc.data.MemberDto import de.harheimertc.data.NewsDto import de.harheimertc.data.QttrRowDto +import de.harheimertc.ui.components.LoadingState import de.harheimertc.ui.components.RichText import de.harheimertc.ui.theme.Accent100 import de.harheimertc.ui.theme.Accent500 @@ -163,7 +163,7 @@ fun MembersScreen( } when { - state.loading -> item { CircularProgressIndicator(color = Primary600) } + state.loading -> item { LoadingState("Mitglieder werden geladen...") } state.error != null -> item { ErrorCard(state.error.orEmpty(), viewModel::load) } display.isEmpty() -> item { Text("Keine Mitglieder gefunden.", color = Accent700) } else -> if (viewMode == "table") { @@ -200,7 +200,7 @@ fun MemberNewsScreen( val state by viewModel.state.collectAsState() MemberAreaPage(navController, showBackNavigation, "News", "Neuigkeiten und Ankündigungen im Mitgliederbereich") { when { - state.loading -> item { CircularProgressIndicator(color = Primary600) } + state.loading -> item { LoadingState("News werden geladen...") } state.error != null -> item { ErrorCard(state.error.orEmpty(), viewModel::load) } state.news.isEmpty() -> item { Text("Noch keine News vorhanden.", color = Accent700) } else -> items(state.news.size) { index -> NewsCard(state.news[index]) } @@ -269,7 +269,7 @@ fun QttrScreen( } } when { - state.loading -> item { CircularProgressIndicator(color = Primary600) } + state.loading -> item { LoadingState("QTTR-Werte werden geladen...") } state.error != null -> item { ErrorCard(state.error.orEmpty(), viewModel::load) } state.rows.isEmpty() -> item { Text("Keine QTTR-Werte gefunden.", color = Accent700) } else -> items(state.rows.size) { index -> QttrRowCard(state.rows[index], isOwnRow(state.rows[index].playerName, state.currentUserName)) } diff --git a/android-app/app/src/main/java/de/harheimertc/ui/screens/memberarea/MemberAreaScreen.kt b/android-app/app/src/main/java/de/harheimertc/ui/screens/memberarea/MemberAreaScreen.kt index 555d954..257d9bf 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/screens/memberarea/MemberAreaScreen.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/screens/memberarea/MemberAreaScreen.kt @@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -28,6 +27,7 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import de.harheimertc.data.BirthdayDto +import de.harheimertc.ui.components.LoadingState import de.harheimertc.ui.navigation.Destinations import de.harheimertc.ui.theme.Accent100 import de.harheimertc.ui.theme.Accent500 @@ -158,8 +158,7 @@ private fun BirthdayCard( when { loading -> { - CircularProgressIndicator(color = Primary600, modifier = Modifier.size(28.dp)) - Text("Lade...", color = Accent500) + LoadingState("Geburtstage werden geladen...") } error != null -> { Text(error, color = MaterialTheme.colorScheme.error) diff --git a/android-app/app/src/main/java/de/harheimertc/ui/screens/newsletter/NewsletterScreens.kt b/android-app/app/src/main/java/de/harheimertc/ui/screens/newsletter/NewsletterScreens.kt index d9f9ae6..8c63b06 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/screens/newsletter/NewsletterScreens.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/screens/newsletter/NewsletterScreens.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Button -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -32,6 +31,7 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import de.harheimertc.data.NewsletterGroupDto +import de.harheimertc.ui.components.LoadingState import de.harheimertc.ui.components.ValidatedTextField import de.harheimertc.ui.navigation.Destinations import de.harheimertc.ui.theme.Accent100 @@ -93,8 +93,7 @@ fun NewsletterConfirmScreen( NewsletterStatusPage(navController, showBackNavigation, "Newsletter bestätigen") { when { state.loading -> { - CircularProgressIndicator(color = Primary600) - Text("Newsletter-Anmeldung wird bestätigt...", color = Accent700) + LoadingState("Newsletter-Anmeldung wird bestätigt...") } state.error != null -> { Text("Fehler", style = MaterialTheme.typography.titleLarge, color = Accent900) @@ -154,7 +153,7 @@ private fun NewsletterFormScreen( Text("Wählen Sie einen Newsletter und geben Sie Ihre E-Mail-Adresse ein.", color = Accent500, modifier = Modifier.padding(top = 8.dp)) } if (state.loading) { - item { CircularProgressIndicator(color = Primary600) } + item { LoadingState("Newsletter-Daten werden geladen...") } } else { item { Surface(color = Color.White, shape = RoundedCornerShape(14.dp), shadowElevation = 3.dp) { diff --git a/android-app/app/src/main/java/de/harheimertc/ui/screens/profile/ProfileScreen.kt b/android-app/app/src/main/java/de/harheimertc/ui/screens/profile/ProfileScreen.kt index e4ef8fe..b526b0a 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/screens/profile/ProfileScreen.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/screens/profile/ProfileScreen.kt @@ -38,6 +38,7 @@ import androidx.navigation.NavController import de.harheimertc.ui.theme.Accent500 import de.harheimertc.ui.theme.Accent900 import de.harheimertc.ui.components.ValidatedTextField +import de.harheimertc.ui.components.LoadingState import de.harheimertc.ui.theme.Primary600 @Composable @@ -67,9 +68,7 @@ fun ProfileScreen( if (state.loading) { item { - Column(Modifier.fillMaxWidth().padding(28.dp), horizontalAlignment = Alignment.CenterHorizontally) { - CircularProgressIndicator(color = Primary600) - } + LoadingState("Profil wird geladen...") } } else { item { diff --git a/android-app/app/src/main/java/de/harheimertc/ui/screens/publicpages/PublicScreenComponents.kt b/android-app/app/src/main/java/de/harheimertc/ui/screens/publicpages/PublicScreenComponents.kt index 1e8bee5..5b29ab2 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/screens/publicpages/PublicScreenComponents.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/screens/publicpages/PublicScreenComponents.kt @@ -15,7 +15,6 @@ import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -27,6 +26,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.navigation.NavController import de.harheimertc.BuildConfig +import de.harheimertc.ui.components.LoadingState import de.harheimertc.ui.components.RichText import de.harheimertc.ui.theme.Accent500 import de.harheimertc.ui.theme.Accent900 @@ -68,9 +68,7 @@ internal fun PublicCard(title: String? = null, content: @Composable () -> Unit) @Composable internal fun PublicLoading() { - Column(Modifier.fillMaxWidth().padding(28.dp), horizontalAlignment = Alignment.CenterHorizontally) { - CircularProgressIndicator(color = Primary600) - } + LoadingState() } @Composable diff --git a/android-app/app/src/main/java/de/harheimertc/ui/screens/spielplan/SpielplanScreen.kt b/android-app/app/src/main/java/de/harheimertc/ui/screens/spielplan/SpielplanScreen.kt index b7c69ac..36a6eb0 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/screens/spielplan/SpielplanScreen.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/screens/spielplan/SpielplanScreen.kt @@ -18,7 +18,6 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.MaterialTheme @@ -43,6 +42,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import de.harheimertc.data.SeasonDto import de.harheimertc.data.SpielDto +import de.harheimertc.ui.components.LoadingState import de.harheimertc.ui.theme.Accent100 import de.harheimertc.ui.theme.Accent200 import de.harheimertc.ui.theme.Accent500 @@ -228,10 +228,7 @@ private fun MatchRow(game: SpielDto) { @Composable private fun LoadingPlan() { - Column(Modifier.fillMaxWidth().padding(40.dp), horizontalAlignment = Alignment.CenterHorizontally) { - CircularProgressIndicator(color = Primary600) - Text("Spielpläne werden geladen...", color = Accent500, modifier = Modifier.padding(top = 12.dp)) - } + LoadingState("Spielpläne werden geladen...") } @Composable diff --git a/android-app/app/src/main/java/de/harheimertc/ui/screens/termine/TermineScreen.kt b/android-app/app/src/main/java/de/harheimertc/ui/screens/termine/TermineScreen.kt index f241ed7..e2ca930 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/screens/termine/TermineScreen.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/screens/termine/TermineScreen.kt @@ -15,7 +15,6 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -32,6 +31,7 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import de.harheimertc.data.TerminDto +import de.harheimertc.ui.components.LoadingState import de.harheimertc.ui.theme.Accent500 import de.harheimertc.ui.theme.Accent700 import de.harheimertc.ui.theme.Accent900 @@ -125,10 +125,7 @@ private fun TerminCard(termin: TerminDto) { @Composable private fun LoadingPanel() { - Column(Modifier.fillMaxWidth().padding(vertical = 38.dp), horizontalAlignment = Alignment.CenterHorizontally) { - CircularProgressIndicator(color = Primary600) - Text("Termine werden geladen...", color = Accent500, modifier = Modifier.padding(top = 12.dp)) - } + LoadingState("Termine werden geladen...") } @Composable diff --git a/android-app/app/src/main/java/de/harheimertc/ui/screens/training/TrainingScreens.kt b/android-app/app/src/main/java/de/harheimertc/ui/screens/training/TrainingScreens.kt index dc2e429..3a7f7bc 100644 --- a/android-app/app/src/main/java/de/harheimertc/ui/screens/training/TrainingScreens.kt +++ b/android-app/app/src/main/java/de/harheimertc/ui/screens/training/TrainingScreens.kt @@ -13,7 +13,6 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Surface @@ -32,6 +31,7 @@ import androidx.navigation.NavController import de.harheimertc.data.TrainingTimeDto import de.harheimertc.data.TrainerDto import de.harheimertc.ui.navigation.Destinations +import de.harheimertc.ui.components.LoadingState import de.harheimertc.ui.theme.Accent500 import de.harheimertc.ui.theme.Accent700 import de.harheimertc.ui.theme.Accent900 @@ -193,9 +193,7 @@ private fun TrainerCard(trainer: TrainerDto) { @Composable private fun Loading() { - Column(Modifier.fillMaxWidth().padding(30.dp), horizontalAlignment = Alignment.CenterHorizontally) { - CircularProgressIndicator(color = Primary600) - } + LoadingState("Trainingsdaten werden geladen...") } @Composable