mirror of https://github.com/readrops/Readrops.git
Add progress indicator in AddFeedDialog and fix account selection bug
This commit is contained in:
parent
aa3a835756
commit
6cb8c2853d
|
@ -1,12 +1,16 @@
|
|||
package com.readrops.app.feeds
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Patterns
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import com.readrops.api.localfeed.LocalRSSDataSource
|
||||
import com.readrops.api.services.Credentials
|
||||
import com.readrops.api.utils.AuthInterceptor
|
||||
import com.readrops.api.utils.HtmlParser
|
||||
import com.readrops.app.R
|
||||
import com.readrops.app.base.TabScreenModel
|
||||
import com.readrops.app.repositories.BaseRepository
|
||||
import com.readrops.app.repositories.GetFoldersWithFeeds
|
||||
import com.readrops.app.util.components.TextFieldError
|
||||
import com.readrops.app.util.components.dialog.TextFieldDialogState
|
||||
|
@ -26,6 +30,7 @@ import kotlinx.coroutines.flow.update
|
|||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import java.net.UnknownHostException
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
|
@ -134,7 +139,8 @@ class FeedScreenModel(
|
|||
it.copy(
|
||||
url = "",
|
||||
error = null,
|
||||
exception = null
|
||||
exception = null,
|
||||
isLoading = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -240,6 +246,8 @@ class FeedScreenModel(
|
|||
}
|
||||
|
||||
else -> screenModelScope.launch(dispatcher) {
|
||||
_addFeedDialogState.update { it.copy(exception = null, isLoading = true) }
|
||||
|
||||
try {
|
||||
if (localRSSDataSource.isUrlRSSResource(url)) {
|
||||
insertFeeds(listOf(Feed(url = url)))
|
||||
|
@ -248,7 +256,7 @@ class FeedScreenModel(
|
|||
|
||||
if (rssUrls.isEmpty()) {
|
||||
_addFeedDialogState.update {
|
||||
it.copy(error = TextFieldError.NoRSSFeed)
|
||||
it.copy(error = TextFieldError.NoRSSFeed, isLoading = false)
|
||||
}
|
||||
} else {
|
||||
insertFeeds(rssUrls.map { Feed(url = it.url) })
|
||||
|
@ -256,8 +264,19 @@ class FeedScreenModel(
|
|||
}
|
||||
} catch (e: Exception) {
|
||||
when (e) {
|
||||
is UnknownHostException -> _addFeedDialogState.update { it.copy(error = TextFieldError.UnreachableUrl) }
|
||||
else -> _addFeedDialogState.update { it.copy(error = TextFieldError.NoRSSFeed) }
|
||||
is UnknownHostException -> _addFeedDialogState.update {
|
||||
it.copy(
|
||||
error = TextFieldError.UnreachableUrl,
|
||||
isLoading = false
|
||||
)
|
||||
}
|
||||
|
||||
else -> _addFeedDialogState.update {
|
||||
it.copy(
|
||||
error = TextFieldError.NoRSSFeed,
|
||||
isLoading = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -265,15 +284,34 @@ class FeedScreenModel(
|
|||
}
|
||||
|
||||
private suspend fun insertFeeds(feeds: List<Feed>) {
|
||||
val errors = repository?.insertNewFeeds(
|
||||
val selectedAccount = _addFeedDialogState.value.selectedAccount
|
||||
|
||||
if (!selectedAccount.isLocal) {
|
||||
get<SharedPreferences>().apply {
|
||||
selectedAccount.login = getString(selectedAccount.loginKey, null)
|
||||
selectedAccount.password = getString(selectedAccount.passwordKey, null)
|
||||
}
|
||||
get<AuthInterceptor>().apply {
|
||||
credentials = Credentials.toCredentials(selectedAccount)
|
||||
}
|
||||
}
|
||||
|
||||
val repository = get<BaseRepository> { parametersOf(selectedAccount) }
|
||||
|
||||
val errors = repository.insertNewFeeds(
|
||||
newFeeds = feeds,
|
||||
onUpdate = { /* no need of this here */ }
|
||||
)!!
|
||||
onUpdate = { /* TODO */ }
|
||||
)
|
||||
|
||||
if (errors.isEmpty()) {
|
||||
closeDialog(DialogState.AddFeed)
|
||||
} else {
|
||||
_addFeedDialogState.update { it.copy(exception = errors.values.first()) }
|
||||
_addFeedDialogState.update {
|
||||
it.copy(
|
||||
exception = errors.values.first(),
|
||||
isLoading = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,7 +394,12 @@ class FeedScreenModel(
|
|||
)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
_updateFeedDialogState.update { it.copy(exception = e, isLoading = false) }
|
||||
_updateFeedDialogState.update {
|
||||
it.copy(
|
||||
exception = e,
|
||||
isLoading = false
|
||||
)
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ data class FeedState(
|
|||
)
|
||||
|
||||
sealed interface DialogState {
|
||||
object AddFeed : DialogState
|
||||
object AddFolder : DialogState
|
||||
data object AddFeed : DialogState
|
||||
data object AddFolder : DialogState
|
||||
class DeleteFeed(val feed: Feed) : DialogState
|
||||
class DeleteFolder(val folder: Folder) : DialogState
|
||||
class UpdateFeed(val feed: Feed, val folder: Folder?) : DialogState
|
||||
|
@ -24,7 +24,7 @@ sealed interface DialogState {
|
|||
}
|
||||
|
||||
sealed class FolderAndFeedsState {
|
||||
object InitialState : FolderAndFeedsState()
|
||||
data object InitialState : FolderAndFeedsState()
|
||||
data class ErrorState(val exception: Exception) : FolderAndFeedsState()
|
||||
data class LoadedState(val values: Map<Folder?, List<Feed>>) : FolderAndFeedsState()
|
||||
}
|
||||
|
@ -34,7 +34,8 @@ data class AddFeedDialogState(
|
|||
val selectedAccount: Account = Account(accountName = ""),
|
||||
val accounts: List<Account> = listOf(),
|
||||
val error: TextFieldError? = null,
|
||||
val exception: Exception? = null
|
||||
val exception: Exception? = null,
|
||||
val isLoading: Boolean = false
|
||||
) {
|
||||
val isError: Boolean get() = error != null
|
||||
}
|
||||
|
|
|
@ -236,7 +236,7 @@ object FeedTab : Tab {
|
|||
when (val dialog = state.dialog) {
|
||||
is DialogState.AddFeed -> {
|
||||
AddFeedDialog(
|
||||
viewModel = screenModel,
|
||||
screenModel = screenModel,
|
||||
onDismiss = {
|
||||
screenModel.closeDialog(DialogState.AddFeed)
|
||||
},
|
||||
|
|
|
@ -13,7 +13,6 @@ import androidx.compose.material3.IconButton
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -30,6 +29,7 @@ import com.readrops.app.R
|
|||
import com.readrops.app.account.selection.adaptiveIconPainterResource
|
||||
import com.readrops.app.feeds.FeedScreenModel
|
||||
import com.readrops.app.util.ErrorMessage
|
||||
import com.readrops.app.util.components.LoadingTextButton
|
||||
import com.readrops.app.util.components.dialog.BaseDialog
|
||||
import com.readrops.app.util.theme.LargeSpacer
|
||||
import com.readrops.app.util.theme.MediumSpacer
|
||||
|
@ -38,29 +38,27 @@ import com.readrops.app.util.theme.ShortSpacer
|
|||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AddFeedDialog(
|
||||
viewModel: FeedScreenModel,
|
||||
screenModel: FeedScreenModel,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val state by viewModel.addFeedDialogState.collectAsStateWithLifecycle()
|
||||
val state by screenModel.addFeedDialogState.collectAsStateWithLifecycle()
|
||||
|
||||
var isExpanded by remember { mutableStateOf(false) }
|
||||
|
||||
BaseDialog(
|
||||
title = stringResource(R.string.add_feed_item),
|
||||
icon = painterResource(id = R.drawable.ic_rss_feed_grey),
|
||||
onDismiss = onDismiss
|
||||
onDismiss = { if (!state.isLoading) onDismiss() }
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = state.url,
|
||||
label = {
|
||||
Text(text = "URL")
|
||||
},
|
||||
onValueChange = { viewModel.setAddFeedDialogURL(it) },
|
||||
label = { Text(text = stringResource(id = R.string.url)) },
|
||||
onValueChange = { screenModel.setAddFeedDialogURL(it) },
|
||||
singleLine = true,
|
||||
trailingIcon = {
|
||||
if (state.url.isNotEmpty()) {
|
||||
IconButton(
|
||||
onClick = { viewModel.setAddFeedDialogURL("") }
|
||||
onClick = { screenModel.setAddFeedDialogURL("") }
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Clear,
|
||||
|
@ -77,7 +75,7 @@ fun AddFeedDialog(
|
|||
|
||||
ExposedDropdownMenuBox(
|
||||
expanded = isExpanded,
|
||||
onExpandedChange = { isExpanded = isExpanded.not() }
|
||||
onExpandedChange = { isExpanded = !isExpanded }
|
||||
) {
|
||||
ExposedDropdownMenu(
|
||||
expanded = isExpanded,
|
||||
|
@ -88,12 +86,12 @@ fun AddFeedDialog(
|
|||
text = { Text(text = account.accountName!!) },
|
||||
onClick = {
|
||||
isExpanded = false
|
||||
viewModel.setAddFeedDialogSelectedAccount(account)
|
||||
screenModel.setAddFeedDialogSelectedAccount(account)
|
||||
},
|
||||
leadingIcon = {
|
||||
Image(
|
||||
painter = adaptiveIconPainterResource(
|
||||
id = state.selectedAccount.accountType!!.iconRes
|
||||
id = account.accountType!!.iconRes
|
||||
),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp)
|
||||
|
@ -135,10 +133,10 @@ fun AddFeedDialog(
|
|||
|
||||
LargeSpacer()
|
||||
|
||||
TextButton(
|
||||
onClick = { viewModel.addFeedDialogValidate() },
|
||||
) {
|
||||
Text(text = stringResource(R.string.validate))
|
||||
}
|
||||
LoadingTextButton(
|
||||
text = stringResource(id = R.string.validate),
|
||||
isLoading = state.isLoading,
|
||||
onClick = { screenModel.addFeedDialogValidate() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -174,4 +174,5 @@
|
|||
<string name="update">Mettre à jour</string>
|
||||
<string name="rename_account">Renommer le compte</string>
|
||||
<string name="name">Nom</string>
|
||||
<string name="url">URL</string>
|
||||
</resources>
|
|
@ -183,4 +183,5 @@
|
|||
<string name="update">Update</string>
|
||||
<string name="rename_account">Rename account</string>
|
||||
<string name="name">Name</string>
|
||||
<string name="url">URL</string>
|
||||
</resources>
|
Loading…
Reference in New Issue