Skip to content

Commit

Permalink
Add UpdateFeedDialog in FeedTab
Browse files Browse the repository at this point in the history
  • Loading branch information
Shinokuni committed Jan 18, 2024
1 parent a6d753e commit caf5545
Show file tree
Hide file tree
Showing 11 changed files with 360 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import androidx.lifecycle.viewModelScope
import com.readrops.app.compose.repositories.BaseRepository
import com.readrops.db.Database
import com.readrops.db.entities.account.Account
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
Expand All @@ -26,7 +26,7 @@ abstract class TabViewModel(

protected var currentAccount: Account? = null

protected val accountEvent = Channel<Account>()
protected val accountEvent = MutableSharedFlow<Account>()

init {
viewModelScope.launch {
Expand All @@ -38,7 +38,7 @@ abstract class TabViewModel(
currentAccount = account
repository = get(parameters = { parametersOf(account) })

accountEvent.send(account)
accountEvent.emit(account)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.readrops.app.compose.feeds
import com.readrops.db.entities.Feed
import com.readrops.db.entities.Folder
import com.readrops.db.entities.account.Account
import com.readrops.db.entities.account.AccountType

data class FeedState(
val foldersAndFeeds: FolderAndFeedsState = FolderAndFeedsState.InitialState,
Expand All @@ -14,7 +15,7 @@ sealed interface DialogState {
object AddFolder : DialogState
class DeleteFeed(val feed: Feed) : DialogState
class DeleteFolder(val folder: Folder) : DialogState
class UpdateFeed(val feed: Feed) : DialogState
class UpdateFeed(val feed: Feed, val folder: Folder?) : DialogState
class UpdateFolder(val folder: Folder) : DialogState
class FeedSheet(val feed: Feed, val folder: Folder?) : DialogState
}
Expand All @@ -30,9 +31,8 @@ data class AddFeedDialogState(
val selectedAccount: Account = Account(accountName = ""),
val accounts: List<Account> = listOf(),
val error: AddFeedError? = null,
val closeDialog: Boolean = false,
) {
fun isError() = error != null
val isError: Boolean get() = error != null

val errorText: String
get() = when (error) {
Expand All @@ -51,4 +51,39 @@ data class AddFeedDialogState(
object NoRSSFeed : AddFeedError()
object NoConnection : AddFeedError()
}
}

data class UpdateFeedDialogState(
val feedName: String = "",
val feedNameError: Error? = null,
val feedUrl: String = "",
val feedUrlError: Error? = null,
val accountType: AccountType? = null,
val selectedFolder: Folder? = null,
val folders: List<Folder> = listOf(),
val isAccountDropDownExpanded: Boolean = false,
) {

sealed class Error {
object EmptyField : Error()
object BadUrl : Error()
object NoRSSUrl : Error()
}

val isFeedNameError
get() = feedNameError != null

val isFeedUrlError
get() = feedUrlError != null

fun errorText(error: Error?): String = when (error) {
Error.BadUrl -> "Input is not a valid URL"
Error.EmptyField -> "Field can't be empty"
Error.NoRSSUrl -> "The provided URL is not a valid RSS feed"
else -> ""
}

val isFeedUrlReadOnly: Boolean
get() = accountType != null && !accountType.accountConfig!!.isFeedUrlEditable

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import com.readrops.app.compose.R
import com.readrops.app.compose.feeds.dialogs.AddFeedDialog
import com.readrops.app.compose.feeds.dialogs.DeleteFeedDialog
import com.readrops.app.compose.feeds.dialogs.FeedModalBottomSheet
import com.readrops.app.compose.feeds.dialogs.UpdateFeedDialog
import com.readrops.app.compose.util.components.Placeholder
import com.readrops.db.entities.Feed
import org.koin.androidx.compose.getViewModel
Expand Down Expand Up @@ -84,13 +85,19 @@ object FeedTab : Tab {
uriHandler.openUri(dialog.feed.siteUrl!!)
viewModel.closeDialog()
},
onModify = { },
onUpdate = { viewModel.openDialog(DialogState.UpdateFeed(dialog.feed, dialog.folder)) },
onUpdateColor = {},
onDelete = { viewModel.openDialog(DialogState.DeleteFeed(dialog.feed)) },
)
}

is DialogState.UpdateFeed -> {}
is DialogState.UpdateFeed -> {
UpdateFeedDialog(
viewModel = viewModel,
onDismissRequest = { viewModel.closeDialog() }
)
}

DialogState.AddFolder -> {}
is DialogState.DeleteFolder -> {}
is DialogState.UpdateFolder -> {}
Expand Down
174 changes: 137 additions & 37 deletions appcompose/src/main/java/com/readrops/app/compose/feeds/FeedViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import com.readrops.app.compose.base.TabViewModel
import com.readrops.app.compose.repositories.GetFoldersWithFeeds
import com.readrops.db.Database
import com.readrops.db.entities.Feed
import com.readrops.db.entities.Folder
import com.readrops.db.entities.account.Account
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.consumeAsFlow
import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
Expand All @@ -32,9 +32,12 @@ class FeedViewModel(
private val _addFeedDialogState = MutableStateFlow(AddFeedDialogState())
val addFeedDialogState = _addFeedDialogState.asStateFlow()

private val _updateFeedDialogState = MutableStateFlow(UpdateFeedDialogState())
val updateFeedDialogState = _updateFeedDialogState.asStateFlow()

init {
viewModelScope.launch(context = Dispatchers.IO) {
accountEvent.consumeAsFlow()
accountEvent
.flatMapConcat { account ->
getFoldersWithFeeds.get(account.id)
}
Expand Down Expand Up @@ -62,18 +65,48 @@ class FeedViewModel(
}
}
}

viewModelScope.launch(context = Dispatchers.IO) {
accountEvent
.flatMapConcat { account ->
database.newFolderDao()
.selectFolders(account.id)
}
.collect { folders ->
_updateFeedDialogState.update {
it.copy(
folders = folders,
accountType = currentAccount!!.accountType
)
}
}
}
}

fun closeDialog() = _feedState.update { it.copy(dialog = null) }

fun openDialog(state: DialogState) = _feedState.update { it.copy(dialog = state) }
fun openDialog(state: DialogState) {
if (state is DialogState.UpdateFeed) {
_updateFeedDialogState.update {
it.copy(
feedName = state.feed.name!!,
feedUrl = state.feed.url!!,
selectedFolder = state.folder
)
}
}

_feedState.update { it.copy(dialog = state) }
}

fun deleteFeed(feed: Feed) {
viewModelScope.launch(Dispatchers.IO) {
repository?.deleteFeed(feed)
}
}

// Add feed

fun setAddFeedDialogURL(url: String) {
_addFeedDialogState.update {
it.copy(
Expand All @@ -94,47 +127,41 @@ class FeedViewModel(
fun addFeedDialogValidate() {
val url = _addFeedDialogState.value.url

if (url.isEmpty()) {
_addFeedDialogState.update {
it.copy(
error = AddFeedDialogState.AddFeedError.EmptyUrl
)
}
when {
url.isEmpty() -> {
_addFeedDialogState.update {
it.copy(error = AddFeedDialogState.AddFeedError.EmptyUrl)
}

return
} else if (!Patterns.WEB_URL.matcher(url).matches()) {
_addFeedDialogState.update {
it.copy(
error = AddFeedDialogState.AddFeedError.BadUrl
)
return
}

return
}

viewModelScope.launch(Dispatchers.IO) {
if (localRSSDataSource.isUrlRSSResource(url)) {
// TODO add support for all account types
repository?.insertNewFeeds(listOf(url))

!Patterns.WEB_URL.matcher(url).matches() -> {
_addFeedDialogState.update {
it.copy(closeDialog = true)
it.copy(error = AddFeedDialogState.AddFeedError.BadUrl)
}
} else {
val rssUrls = HtmlParser.getFeedLink(url, get())

if (rssUrls.isEmpty()) {
_addFeedDialogState.update {
it.copy(
error = AddFeedDialogState.AddFeedError.NoRSSFeed
)
}
} else {
return
}

else -> viewModelScope.launch(Dispatchers.IO) {
if (localRSSDataSource.isUrlRSSResource(url)) {
// TODO add support for all account types
repository?.insertNewFeeds(rssUrls.map { it.url })
repository?.insertNewFeeds(listOf(url))

closeDialog()
} else {
val rssUrls = HtmlParser.getFeedLink(url, get())

if (rssUrls.isEmpty()) {
_addFeedDialogState.update {
it.copy(error = AddFeedDialogState.AddFeedError.NoRSSFeed)
}
} else {
// TODO add support for all account types
repository?.insertNewFeeds(rssUrls.map { it.url })

_addFeedDialogState.update {
it.copy(closeDialog = true)
closeDialog()
}
}
}
Expand All @@ -146,9 +173,82 @@ class FeedViewModel(
it.copy(
url = "",
error = null,
closeDialog = false
)
}
}

// add feed

// update feed

fun setAccountDropDownState(isExpanded: Boolean) {
_updateFeedDialogState.update {
it.copy(isAccountDropDownExpanded = isExpanded)
}
}

fun setSelectedFolder(folder: Folder) {
_updateFeedDialogState.update {
it.copy(selectedFolder = folder)
}
}

fun setUpdateFeedDialogStateFeedName(feedName: String) {
_updateFeedDialogState.update {
it.copy(
feedName = feedName,
feedNameError = null,
)
}
}

fun setUpdateFeedDialogFeedUrl(feedUrl: String) {
_updateFeedDialogState.update {
it.copy(
feedUrl = feedUrl,
feedUrlError = null,
)
}
}

fun updateFeedDialogValidate() {
val feedName = _updateFeedDialogState.value.feedName
val feedUrl = _updateFeedDialogState.value.feedUrl

when {
feedName.isEmpty() -> {
_updateFeedDialogState.update {
it.copy(feedNameError = UpdateFeedDialogState.Error.EmptyField)
}
return
}

feedUrl.isEmpty() -> {
_updateFeedDialogState.update {
it.copy(feedUrlError = UpdateFeedDialogState.Error.EmptyField)
}
return
}

!Patterns.WEB_URL.matcher(feedUrl).matches() -> {
_updateFeedDialogState.update {
it.copy(feedUrlError = UpdateFeedDialogState.Error.BadUrl)
}
return
}

else -> {
viewModelScope.launch(Dispatchers.IO) {
// TODO add logig to update feed
//repository?.updateFeed()
closeDialog()
}
}
}

}


// update feed
}

Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@ fun AddFeedDialog(

var isExpanded by remember { mutableStateOf(false) }

if (state.closeDialog) {
onDismiss()
}

Dialog(
onDismissRequest = onDismiss
) {
Expand Down Expand Up @@ -100,7 +96,7 @@ fun AddFeedDialog(
}
}
},
isError = state.isError(),
isError = state.isError,
supportingText = { Text(state.errorText) }
)

Expand Down
Loading

0 comments on commit caf5545

Please sign in to comment.