Display errors in NewFeedScreen more accurately

This commit is contained in:
Shinokuni 2024-11-11 17:32:50 +01:00
parent 7134772a5f
commit 7dcb2cbb29
4 changed files with 69 additions and 12 deletions

View File

@ -18,9 +18,12 @@ import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -51,6 +54,7 @@ class NewFeedScreen(val url: String? = null) : AndroidScreen() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val screenModel = koinScreenModel<NewFeedScreenModel> { parametersOf(url) } val screenModel = koinScreenModel<NewFeedScreenModel> { parametersOf(url) }
val appBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
val state by screenModel.state.collectAsStateWithLifecycle() val state by screenModel.state.collectAsStateWithLifecycle()
if (state.popScreen) { if (state.popScreen) {
@ -72,7 +76,8 @@ class NewFeedScreen(val url: String? = null) : AndroidScreen() {
contentDescription = null contentDescription = null
) )
} }
} },
scrollBehavior = appBarScrollBehavior
) )
} }
) { paddingValues -> ) { paddingValues ->
@ -80,6 +85,7 @@ class NewFeedScreen(val url: String? = null) : AndroidScreen() {
modifier = Modifier modifier = Modifier
.padding(paddingValues) .padding(paddingValues)
.padding(horizontal = MaterialTheme.spacing.mediumSpacing) .padding(horizontal = MaterialTheme.spacing.mediumSpacing)
.nestedScroll(appBarScrollBehavior.nestedScrollConnection)
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
.animateContentSize() .animateContentSize()
.fillMaxSize(), .fillMaxSize(),
@ -194,6 +200,7 @@ class NewFeedScreen(val url: String? = null) : AndroidScreen() {
isExpanded = false isExpanded = false
) )
}, },
error = parsingResult.error,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
@ -206,6 +213,7 @@ class NewFeedScreen(val url: String? = null) : AndroidScreen() {
Text( Text(
text = ErrorMessage.get(state.exception!!, LocalContext.current), text = ErrorMessage.get(state.exception!!, LocalContext.current),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.error, color = MaterialTheme.colorScheme.error,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()

View File

@ -11,6 +11,7 @@ import com.readrops.api.utils.AuthInterceptor
import com.readrops.api.utils.HtmlParser import com.readrops.api.utils.HtmlParser
import com.readrops.app.R import com.readrops.app.R
import com.readrops.app.repositories.BaseRepository import com.readrops.app.repositories.BaseRepository
import com.readrops.app.util.ErrorMessage
import com.readrops.app.util.components.TextFieldError import com.readrops.app.util.components.TextFieldError
import com.readrops.db.Database import com.readrops.db.Database
import com.readrops.db.entities.Feed import com.readrops.db.entities.Feed
@ -87,7 +88,15 @@ class NewFeedScreenModel(
val url = mutableState.value.url val url = mutableState.value.url
if (state.value.selectedResultsCount > 0) { if (state.value.selectedResultsCount > 0) {
mutableState.update { it.copy(exception = null, isLoading = true) } mutableState.update {
it.copy(
exception = null,
isLoading = true,
parsingResults = state.value.parsingResults.map { parsingResult ->
parsingResult.copy(error = null)
}
)
}
screenModelScope.launch(dispatcher) { screenModelScope.launch(dispatcher) {
insertFeeds(state.value.parsingResults insertFeeds(state.value.parsingResults
@ -189,6 +198,7 @@ class NewFeedScreenModel(
selectedAccount.login = getString(selectedAccount.loginKey, null) selectedAccount.login = getString(selectedAccount.loginKey, null)
selectedAccount.password = getString(selectedAccount.passwordKey, null) selectedAccount.password = getString(selectedAccount.passwordKey, null)
} }
get<AuthInterceptor>().apply { get<AuthInterceptor>().apply {
credentials = Credentials.toCredentials(selectedAccount) credentials = Credentials.toCredentials(selectedAccount)
} }
@ -198,11 +208,30 @@ class NewFeedScreenModel(
val errors = repository.insertNewFeeds( val errors = repository.insertNewFeeds(
newFeeds = feeds, newFeeds = feeds,
onUpdate = { /* TODO */ } onUpdate = {}
) )
if (errors.isEmpty()) { if (errors.isEmpty()) {
mutableState.update { it.copy(popScreen = true) } mutableState.update { it.copy(popScreen = true) }
} else {
if (state.value.selectedResultsCount > 0) {
val newParsingResults = state.value.parsingResults.map { parsingResult ->
val feed = errors.keys.find { feed -> feed.url == parsingResult.url }
if (feed != null) {
val error = errors[feed]
parsingResult.copy(error = ErrorMessage.get(error!!, context))
} else {
parsingResult
}
}
mutableState.update {
it.copy(
parsingResults = newParsingResults,
isLoading = false
)
}
} else { } else {
mutableState.update { mutableState.update {
it.copy( it.copy(
@ -212,6 +241,7 @@ class NewFeedScreenModel(
} }
} }
} }
}
fun updateUrl(url: String) = mutableState.update { it.copy(url = url, urlError = null) } fun updateUrl(url: String) = mutableState.update { it.copy(url = url, urlError = null) }
@ -284,7 +314,7 @@ class NewFeedScreenModel(
} }
data class State( data class State(
val url: String = "https://blog.broulik.de/", val url: String = "",
val selectedAccount: Account? = null, val selectedAccount: Account? = null,
val selectedFolder: Folder? = null, val selectedFolder: Folder? = null,
val accounts: List<Account> = listOf(), val accounts: List<Account> = listOf(),
@ -310,7 +340,8 @@ data class ParsingResultState(
val label: String?, val label: String?,
val isSelected: Boolean, val isSelected: Boolean,
val folder: Folder?, val folder: Folder?,
val isExpanded: Boolean val isExpanded: Boolean,
val error: String? = null
) { ) {
val folderId: Int? get() = folder?.id.takeUnless { it == 0 } val folderId: Int? get() = folder?.id.takeUnless { it == 0 }
} }

View File

@ -19,6 +19,7 @@ import androidx.compose.ui.text.style.TextOverflow
import com.readrops.app.R import com.readrops.app.R
import com.readrops.app.util.components.CompactDropdownBox import com.readrops.app.util.components.CompactDropdownBox
import com.readrops.app.util.components.DropdownBoxValue import com.readrops.app.util.components.DropdownBoxValue
import com.readrops.app.util.components.IconText
import com.readrops.app.util.theme.ShortSpacer import com.readrops.app.util.theme.ShortSpacer
import com.readrops.app.util.theme.VeryShortSpacer import com.readrops.app.util.theme.VeryShortSpacer
import com.readrops.app.util.theme.spacing import com.readrops.app.util.theme.spacing
@ -32,7 +33,8 @@ fun ParsingResultItem(
onExpandedChange: (Boolean) -> Unit, onExpandedChange: (Boolean) -> Unit,
onSelectFolder: (Folder) -> Unit, onSelectFolder: (Folder) -> Unit,
onDismiss: () -> Unit, onDismiss: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier,
error: String? = null
) { ) {
Surface( Surface(
color = animateColorAsState( color = animateColorAsState(
@ -110,6 +112,19 @@ fun ParsingResultItem(
) )
} }
} }
if (error != null) {
ShortSpacer()
IconText(
icon = painterResource(R.drawable.ic_error),
text = error,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.error,
tint = MaterialTheme.colorScheme.error,
maxLines = 2
)
}
} }
} }
} }

View File

@ -31,6 +31,7 @@ fun BaseText(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
color: Color = LocalContentColor.current, color: Color = LocalContentColor.current,
spacing: Dp = MaterialTheme.spacing.veryShortSpacing, spacing: Dp = MaterialTheme.spacing.veryShortSpacing,
maxLines: Int = 1,
onClick: (() -> Unit)? = null, onClick: (() -> Unit)? = null,
leftContent: @Composable () -> Unit leftContent: @Composable () -> Unit
) { ) {
@ -46,7 +47,7 @@ fun BaseText(
text = text, text = text,
style = style, style = style,
color = color, color = color,
maxLines = 1, maxLines = maxLines,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
} }
@ -58,6 +59,7 @@ fun IconText(
text: String, text: String,
style: TextStyle, style: TextStyle,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
maxLines: Int = 1,
color: Color = LocalContentColor.current, color: Color = LocalContentColor.current,
tint: Color = LocalContentColor.current, tint: Color = LocalContentColor.current,
spacing: Dp = MaterialTheme.spacing.veryShortSpacing, spacing: Dp = MaterialTheme.spacing.veryShortSpacing,
@ -69,6 +71,7 @@ fun IconText(
color = color, color = color,
spacing = spacing, spacing = spacing,
modifier = modifier, modifier = modifier,
maxLines = maxLines,
onClick = onClick onClick = onClick
) { ) {
Icon( Icon(