diff --git a/app/src/main/java/com/readrops/app/feeds/newfeed/NewFeedScreen.kt b/app/src/main/java/com/readrops/app/feeds/newfeed/NewFeedScreen.kt index 17b523db..ee0a255d 100644 --- a/app/src/main/java/com/readrops/app/feeds/newfeed/NewFeedScreen.kt +++ b/app/src/main/java/com/readrops/app/feeds/newfeed/NewFeedScreen.kt @@ -18,9 +18,12 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -51,6 +54,7 @@ class NewFeedScreen(val url: String? = null) : AndroidScreen() { val navigator = LocalNavigator.currentOrThrow val screenModel = koinScreenModel { parametersOf(url) } + val appBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) val state by screenModel.state.collectAsStateWithLifecycle() if (state.popScreen) { @@ -72,7 +76,8 @@ class NewFeedScreen(val url: String? = null) : AndroidScreen() { contentDescription = null ) } - } + }, + scrollBehavior = appBarScrollBehavior ) } ) { paddingValues -> @@ -80,6 +85,7 @@ class NewFeedScreen(val url: String? = null) : AndroidScreen() { modifier = Modifier .padding(paddingValues) .padding(horizontal = MaterialTheme.spacing.mediumSpacing) + .nestedScroll(appBarScrollBehavior.nestedScrollConnection) .verticalScroll(rememberScrollState()) .animateContentSize() .fillMaxSize(), @@ -194,6 +200,7 @@ class NewFeedScreen(val url: String? = null) : AndroidScreen() { isExpanded = false ) }, + error = parsingResult.error, modifier = Modifier.fillMaxWidth() ) @@ -206,6 +213,7 @@ class NewFeedScreen(val url: String? = null) : AndroidScreen() { Text( text = ErrorMessage.get(state.exception!!, LocalContext.current), + style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.error, textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth() diff --git a/app/src/main/java/com/readrops/app/feeds/newfeed/NewFeedScreenModel.kt b/app/src/main/java/com/readrops/app/feeds/newfeed/NewFeedScreenModel.kt index dae4ede3..21bd7fef 100644 --- a/app/src/main/java/com/readrops/app/feeds/newfeed/NewFeedScreenModel.kt +++ b/app/src/main/java/com/readrops/app/feeds/newfeed/NewFeedScreenModel.kt @@ -11,6 +11,7 @@ import com.readrops.api.utils.AuthInterceptor import com.readrops.api.utils.HtmlParser import com.readrops.app.R import com.readrops.app.repositories.BaseRepository +import com.readrops.app.util.ErrorMessage import com.readrops.app.util.components.TextFieldError import com.readrops.db.Database import com.readrops.db.entities.Feed @@ -87,7 +88,15 @@ class NewFeedScreenModel( val url = mutableState.value.url 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) { insertFeeds(state.value.parsingResults @@ -189,6 +198,7 @@ class NewFeedScreenModel( selectedAccount.login = getString(selectedAccount.loginKey, null) selectedAccount.password = getString(selectedAccount.passwordKey, null) } + get().apply { credentials = Credentials.toCredentials(selectedAccount) } @@ -198,17 +208,37 @@ class NewFeedScreenModel( val errors = repository.insertNewFeeds( newFeeds = feeds, - onUpdate = { /* TODO */ } + onUpdate = {} ) if (errors.isEmpty()) { mutableState.update { it.copy(popScreen = true) } } else { - mutableState.update { - it.copy( - exception = errors.values.first(), - isLoading = false - ) + 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 { + mutableState.update { + it.copy( + exception = errors.values.first(), + isLoading = false + ) + } } } } @@ -284,7 +314,7 @@ class NewFeedScreenModel( } data class State( - val url: String = "https://blog.broulik.de/", + val url: String = "", val selectedAccount: Account? = null, val selectedFolder: Folder? = null, val accounts: List = listOf(), @@ -310,7 +340,8 @@ data class ParsingResultState( val label: String?, val isSelected: Boolean, val folder: Folder?, - val isExpanded: Boolean + val isExpanded: Boolean, + val error: String? = null ) { val folderId: Int? get() = folder?.id.takeUnless { it == 0 } } \ No newline at end of file diff --git a/app/src/main/java/com/readrops/app/feeds/newfeed/ParsingResultItem.kt b/app/src/main/java/com/readrops/app/feeds/newfeed/ParsingResultItem.kt index 3153342c..c9f400b2 100644 --- a/app/src/main/java/com/readrops/app/feeds/newfeed/ParsingResultItem.kt +++ b/app/src/main/java/com/readrops/app/feeds/newfeed/ParsingResultItem.kt @@ -19,6 +19,7 @@ import androidx.compose.ui.text.style.TextOverflow import com.readrops.app.R import com.readrops.app.util.components.CompactDropdownBox 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.VeryShortSpacer import com.readrops.app.util.theme.spacing @@ -32,7 +33,8 @@ fun ParsingResultItem( onExpandedChange: (Boolean) -> Unit, onSelectFolder: (Folder) -> Unit, onDismiss: () -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + error: String? = null ) { Surface( 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 + ) + } } } } diff --git a/app/src/main/java/com/readrops/app/util/components/IconText.kt b/app/src/main/java/com/readrops/app/util/components/IconText.kt index f22b00f0..ab214b7b 100644 --- a/app/src/main/java/com/readrops/app/util/components/IconText.kt +++ b/app/src/main/java/com/readrops/app/util/components/IconText.kt @@ -31,6 +31,7 @@ fun BaseText( modifier: Modifier = Modifier, color: Color = LocalContentColor.current, spacing: Dp = MaterialTheme.spacing.veryShortSpacing, + maxLines: Int = 1, onClick: (() -> Unit)? = null, leftContent: @Composable () -> Unit ) { @@ -46,7 +47,7 @@ fun BaseText( text = text, style = style, color = color, - maxLines = 1, + maxLines = maxLines, overflow = TextOverflow.Ellipsis ) } @@ -58,6 +59,7 @@ fun IconText( text: String, style: TextStyle, modifier: Modifier = Modifier, + maxLines: Int = 1, color: Color = LocalContentColor.current, tint: Color = LocalContentColor.current, spacing: Dp = MaterialTheme.spacing.veryShortSpacing, @@ -69,6 +71,7 @@ fun IconText( color = color, spacing = spacing, modifier = modifier, + maxLines = maxLines, onClick = onClick ) { Icon(