* feat(#363): add descriptive text to loading spinners - Updates LoadingState composable to accept optional subtitle - Shows 'Fetching model providers...' on ModelScreen - Shows 'Loading channels...' on ChannelsScreen - Removes dead/unreachable CircularProgressIndicator from ModelScreen * fix(#363): pass loading_state_subtitle_models string to LoadingState --------- Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
96e754dd3b
commit
c0ebc8ec64
4 files changed
+30
-29
No files matched your search
@@ -73,7 +73,10 @@ fun ChannelsScreen(
|
|||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
when {
|
when {
|
||||||
state.isLoading && state.platforms.isEmpty() -> {
|
state.isLoading && state.platforms.isEmpty() -> {
|
||||||
LoadingState(modifier = Modifier.padding(paddingValues))
|
LoadingState(
|
||||||
|
subtitle = stringResource(R.string.loading_state_subtitle_channels),
|
||||||
|
modifier = Modifier.padding(paddingValues),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
state.errorMessage != null -> {
|
state.errorMessage != null -> {
|
||||||
|
|||||||
@@ -35,7 +35,10 @@ import com.m57.hermescontrol.theme.LocalSpacing
|
|||||||
// ── Loading ───────────────────────────────────────────────────────────
|
// ── Loading ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LoadingState(modifier: Modifier = Modifier) {
|
fun LoadingState(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
subtitle: String? = null,
|
||||||
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier =
|
modifier =
|
||||||
modifier
|
modifier
|
||||||
@@ -43,6 +46,7 @@ fun LoadingState(modifier: Modifier = Modifier) {
|
|||||||
.testTag("loading_state"),
|
.testTag("loading_state"),
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
strokeWidth = 3.dp,
|
strokeWidth = 3.dp,
|
||||||
@@ -51,6 +55,15 @@ fun LoadingState(modifier: Modifier = Modifier) {
|
|||||||
.size(40.dp)
|
.size(40.dp)
|
||||||
.testTag("loading_spinner"),
|
.testTag("loading_spinner"),
|
||||||
)
|
)
|
||||||
|
if (subtitle != null) {
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
Text(
|
||||||
|
text = subtitle,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.m57.hermescontrol.ui.model
|
|||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
@@ -16,13 +15,10 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Check
|
import androidx.compose.material.icons.filled.Check
|
||||||
import androidx.compose.material.icons.filled.Refresh
|
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -83,7 +79,10 @@ fun ModelScreen(
|
|||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
when {
|
when {
|
||||||
state.isLoading && state.providers.isEmpty() -> {
|
state.isLoading && state.providers.isEmpty() -> {
|
||||||
LoadingState(modifier = Modifier.padding(paddingValues))
|
LoadingState(
|
||||||
|
subtitle = stringResource(R.string.loading_state_subtitle_models),
|
||||||
|
modifier = Modifier.padding(paddingValues),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
state.errorMessage != null -> {
|
state.errorMessage != null -> {
|
||||||
@@ -105,24 +104,6 @@ fun ModelScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
Box(Modifier.fillMaxSize()) {
|
|
||||||
if (state.isLoading && state.providers.isEmpty()) {
|
|
||||||
CircularProgressIndicator()
|
|
||||||
} else if (state.errorMessage != null && state.providers.isEmpty()) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(16.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
|
||||||
Text(text = state.errorMessage ?: "", color = MaterialTheme.colorScheme.error)
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
IconButton(onClick = { viewModel.loadModelOptions() }) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.Refresh,
|
|
||||||
contentDescription = stringResource(R.string.action_retry),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentPadding = PaddingValues(16.dp),
|
contentPadding = PaddingValues(16.dp),
|
||||||
@@ -258,8 +239,9 @@ fun ModelScreen(
|
|||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
.padding(12.dp),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement =
|
||||||
|
Arrangement.SpaceBetween,
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
@@ -302,5 +284,3 @@ fun ModelScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -397,4 +397,9 @@
|
|||||||
<string name="landing_subtitle">Control panel for Hermes Agent</string>
|
<string name="landing_subtitle">Control panel for Hermes Agent</string>
|
||||||
<string name="landing_action_auth_login">Auth Login</string>
|
<string name="landing_action_auth_login">Auth Login</string>
|
||||||
<string name="landing_action_pairing_login">Pairing Login</string>
|
<string name="landing_action_pairing_login">Pairing Login</string>
|
||||||
|
|
||||||
|
<!-- Loading State -->
|
||||||
|
<string name="loading_state_subtitle_default">Loading…</string>
|
||||||
|
<string name="loading_state_subtitle_models">Fetching model providers…</string>
|
||||||
|
<string name="loading_state_subtitle_channels">Loading channels…</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in new issue
Block a user