diff --git a/app/src/main/java/com/readrops/app/feeds/FeedScreenModel.kt b/app/src/main/java/com/readrops/app/feeds/FeedScreenModel.kt index 2ddc0331..965148ce 100644 --- a/app/src/main/java/com/readrops/app/feeds/FeedScreenModel.kt +++ b/app/src/main/java/com/readrops/app/feeds/FeedScreenModel.kt @@ -11,6 +11,7 @@ import com.readrops.app.util.components.dialog.TextFieldDialogState import com.readrops.db.Database import com.readrops.db.entities.Feed import com.readrops.db.entities.Folder +import com.readrops.db.entities.OpenIn import com.readrops.db.filters.MainFilter import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers @@ -69,12 +70,22 @@ class FeedScreenModel( } .collect { foldersAndFeeds -> _feedState.update { state -> - val dialog = if (state.dialog is DialogState.FeedSheet) { - val feed = foldersAndFeeds.values.flatten() - .first { it.id == state.dialog.feed.id } - state.dialog.copy(feed = feed) - } else { - state.dialog + val dialog = when (state.dialog) { + is DialogState.FeedSheet -> { + val feed = foldersAndFeeds.values.flatten() + .first { it.id == state.dialog.feed.id } + state.dialog.copy(feed = feed) + } + + is DialogState.UpdateFeedOpenInSetting -> { + val feed = foldersAndFeeds.values.flatten() + .first { it.id == state.dialog.feed.id } + state.dialog.copy(feed = feed) + } + + else -> { + state.dialog + } } state.copy( @@ -137,7 +148,19 @@ class FeedScreenModel( else -> {} } - _feedState.update { it.copy(dialog = null) } + if (dialog is DialogState.UpdateFeedOpenInSetting) { + _feedState.update { + it.copy( + dialog = DialogState.FeedSheet( + feed = dialog.feed, + folder = null, + config = currentAccount!!.config + ) + ) + } + } else { + _feedState.update { it.copy(dialog = null) } + } } fun openDialog(state: DialogState) { @@ -342,4 +365,10 @@ class FeedScreenModel( database.feedDao().updateFeedNotificationState(feedId, isEnabled) } } + + fun updateFeedOpenInSetting(feedId: Int, openIn: OpenIn) { + screenModelScope.launch(dispatcher) { + database.feedDao().updateOpenInSetting(feedId, openIn) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/readrops/app/feeds/FeedState.kt b/app/src/main/java/com/readrops/app/feeds/FeedState.kt index c54fadfa..fabfebb2 100644 --- a/app/src/main/java/com/readrops/app/feeds/FeedState.kt +++ b/app/src/main/java/com/readrops/app/feeds/FeedState.kt @@ -24,6 +24,7 @@ sealed interface DialogState { class DeleteFolder(val folder: Folder) : DialogState class UpdateFeed(val feed: Feed, val folder: Folder?) : DialogState class UpdateFolder(val folder: Folder) : DialogState + data class UpdateFeedOpenInSetting(val feed: Feed) : DialogState data class FeedSheet( val feed: Feed, diff --git a/app/src/main/java/com/readrops/app/feeds/FeedTab.kt b/app/src/main/java/com/readrops/app/feeds/FeedTab.kt index 359c6d77..0d260517 100644 --- a/app/src/main/java/com/readrops/app/feeds/FeedTab.kt +++ b/app/src/main/java/com/readrops/app/feeds/FeedTab.kt @@ -10,7 +10,6 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add -import androidx.compose.material.icons.filled.Delete import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon @@ -29,7 +28,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext @@ -46,14 +44,13 @@ import cafe.adriel.voyager.navigator.tab.Tab import cafe.adriel.voyager.navigator.tab.TabOptions import com.readrops.app.MainActivity import com.readrops.app.R -import com.readrops.app.feeds.dialogs.FeedModalBottomSheet -import com.readrops.app.feeds.dialogs.UpdateFeedDialog +import com.readrops.app.feeds.components.FeedItem +import com.readrops.app.feeds.components.FolderExpandableItem +import com.readrops.app.feeds.dialogs.FeedDialogs import com.readrops.app.feeds.newfeed.NewFeedScreen import com.readrops.app.util.components.CenteredProgressIndicator import com.readrops.app.util.components.ErrorMessage import com.readrops.app.util.components.Placeholder -import com.readrops.app.util.components.dialog.TextFieldDialog -import com.readrops.app.util.components.dialog.TwoChoicesDialog import com.readrops.app.util.theme.spacing import com.readrops.db.entities.Feed import kotlinx.coroutines.channels.Channel @@ -260,98 +257,6 @@ object FeedTab : Tab { } } - @Composable - private fun FeedDialogs(state: FeedState, screenModel: FeedScreenModel) { - val uriHandler = LocalUriHandler.current - - val folderState by screenModel.folderState.collectAsStateWithLifecycle() - - when (val dialog = state.dialog) { - is DialogState.DeleteFeed -> { - TwoChoicesDialog( - title = stringResource(R.string.delete_feed), - text = stringResource(R.string.delete_feed_question, dialog.feed.name!!), - icon = rememberVectorPainter(image = Icons.Default.Delete), - confirmText = stringResource(R.string.delete), - dismissText = stringResource(R.string.cancel), - onDismiss = { screenModel.closeDialog() }, - onConfirm = { - screenModel.deleteFeed(dialog.feed) - screenModel.closeDialog() - } - ) - } - - is DialogState.FeedSheet -> { - FeedModalBottomSheet( - feed = dialog.feed, - accountNotificationsEnabled = state.isAccountNotificationsEnabled, - onDismissRequest = { screenModel.closeDialog() }, - onOpen = { - uriHandler.openUri(dialog.feed.siteUrl!!) - screenModel.closeDialog() - }, - onUpdate = { - screenModel.openDialog(DialogState.UpdateFeed(dialog.feed, dialog.folder)) - }, - onDelete = { screenModel.openDialog(DialogState.DeleteFeed(dialog.feed)) }, - onUpdateNotifications = { - screenModel.updateFeedNotifications(dialog.feed.id, it) - }, - canUpdateFeed = dialog.config.canUpdateFeed, - canDeleteFeed = dialog.config.canDeleteFeed - ) - } - - is DialogState.UpdateFeed -> { - UpdateFeedDialog( - viewModel = screenModel, - onDismissRequest = { screenModel.closeDialog(dialog) } - ) - } - - DialogState.AddFolder -> { - TextFieldDialog( - title = stringResource(id = R.string.add_folder), - icon = painterResource(id = R.drawable.ic_new_folder), - label = stringResource(id = R.string.name), - state = folderState, - onValueChange = { screenModel.setFolderName(it) }, - onValidate = { screenModel.folderValidate() }, - onDismiss = { screenModel.closeDialog(DialogState.AddFolder) } - ) - } - - is DialogState.DeleteFolder -> { - TwoChoicesDialog( - title = stringResource(R.string.delete_folder), - text = stringResource(R.string.delete_folder_question, dialog.folder.name!!), - icon = rememberVectorPainter(image = Icons.Default.Delete), - confirmText = stringResource(R.string.delete), - dismissText = stringResource(R.string.cancel), - onDismiss = { screenModel.closeDialog() }, - onConfirm = { - screenModel.deleteFolder(dialog.folder) - screenModel.closeDialog() - } - ) - } - - is DialogState.UpdateFolder -> { - TextFieldDialog( - title = stringResource(id = R.string.edit_folder), - icon = painterResource(id = R.drawable.ic_folder_grey), - label = stringResource(id = R.string.name), - state = folderState, - onValueChange = { screenModel.setFolderName(it) }, - onValidate = { screenModel.folderValidate(updateFolder = true) }, - onDismiss = { screenModel.closeDialog(DialogState.UpdateFolder(dialog.folder)) } - ) - } - - null -> {} - } - } suspend fun openAddFeedDialog(url: String) { addFeedDialogChannel.send(url) diff --git a/app/src/main/java/com/readrops/app/feeds/components/FeedBanner.kt b/app/src/main/java/com/readrops/app/feeds/components/FeedBanner.kt new file mode 100644 index 00000000..0e45c2e9 --- /dev/null +++ b/app/src/main/java/com/readrops/app/feeds/components/FeedBanner.kt @@ -0,0 +1,111 @@ +package com.readrops.app.feeds.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.blur +import androidx.compose.ui.draw.drawWithContent +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import coil3.compose.AsyncImage +import com.readrops.app.R +import com.readrops.app.util.theme.MediumSpacer +import com.readrops.app.util.theme.VeryShortSpacer +import com.readrops.app.util.theme.spacing +import com.readrops.db.entities.Feed + +@Composable +fun FeedBanner(feed: Feed) { + Column { + Box( + modifier = Modifier.fillMaxWidth() + ) { + if (feed.imageUrl != null) { + AsyncImage( + model = feed.imageUrl, + contentDescription = null, + contentScale = ContentScale.Crop, + modifier = Modifier + .matchParentSize() + .drawWithContent { + drawContent() + drawRect( + color = Color.Black.copy(alpha = 0.65f) + ) + } + .blur(2.5.dp) + ) + } + + Row( + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding( + top = MaterialTheme.spacing.largeSpacing, + start = MaterialTheme.spacing.largeSpacing, + end = MaterialTheme.spacing.largeSpacing, + bottom = MaterialTheme.spacing.mediumSpacing + ) + ) { + AsyncImage( + model = feed.iconUrl, + contentDescription = feed.name!!, + placeholder = painterResource(id = R.drawable.ic_rss_feed_grey), + error = painterResource(id = R.drawable.ic_rss_feed_grey), + modifier = Modifier.size(MaterialTheme.spacing.veryLargeSpacing) + ) + + MediumSpacer() + + Column { + Text( + text = feed.name!!, + style = MaterialTheme.typography.titleLarge, + color = if (feed.imageUrl != null) { + Color.White + } else { + MaterialTheme.colorScheme.onBackground + }, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + + if (feed.description != null) { + VeryShortSpacer() + + Text( + text = feed.description!!, + style = MaterialTheme.typography.bodyMedium, + color = if (feed.imageUrl != null) { + Color.White + } else { + MaterialTheme.colorScheme.onSurfaceVariant + }, + maxLines = 2, + overflow = TextOverflow.Ellipsis + ) + } + } + } + } + + if (feed.imageUrl == null) { + HorizontalDivider( + modifier = Modifier.padding(horizontal = MaterialTheme.spacing.mediumSpacing) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/readrops/app/feeds/FeedItem.kt b/app/src/main/java/com/readrops/app/feeds/components/FeedItem.kt similarity index 98% rename from app/src/main/java/com/readrops/app/feeds/FeedItem.kt rename to app/src/main/java/com/readrops/app/feeds/components/FeedItem.kt index fe2e1057..67dbf227 100644 --- a/app/src/main/java/com/readrops/app/feeds/FeedItem.kt +++ b/app/src/main/java/com/readrops/app/feeds/components/FeedItem.kt @@ -1,4 +1,4 @@ -package com.readrops.app.feeds +package com.readrops.app.feeds.components import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.combinedClickable diff --git a/app/src/main/java/com/readrops/app/feeds/FolderExpandableItem.kt b/app/src/main/java/com/readrops/app/feeds/components/FolderExpandableItem.kt similarity index 99% rename from app/src/main/java/com/readrops/app/feeds/FolderExpandableItem.kt rename to app/src/main/java/com/readrops/app/feeds/components/FolderExpandableItem.kt index 980ee429..dc86d079 100644 --- a/app/src/main/java/com/readrops/app/feeds/FolderExpandableItem.kt +++ b/app/src/main/java/com/readrops/app/feeds/components/FolderExpandableItem.kt @@ -1,4 +1,4 @@ -package com.readrops.app.feeds +package com.readrops.app.feeds.components import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.LinearOutSlowInEasing diff --git a/app/src/main/java/com/readrops/app/feeds/dialogs/FeedBottomSheet.kt b/app/src/main/java/com/readrops/app/feeds/dialogs/FeedBottomSheet.kt index fa1a1445..9eba8f8c 100644 --- a/app/src/main/java/com/readrops/app/feeds/dialogs/FeedBottomSheet.kt +++ b/app/src/main/java/com/readrops/app/feeds/dialogs/FeedBottomSheet.kt @@ -1,18 +1,16 @@ package com.readrops.app.feeds.dialogs import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Create import androidx.compose.material.icons.filled.Delete import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet @@ -20,36 +18,31 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.blur -import androidx.compose.ui.draw.drawWithContent -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.dp -import coil3.compose.AsyncImage import com.readrops.app.R +import com.readrops.app.feeds.components.FeedBanner +import com.readrops.app.more.preferences.components.BasePreference import com.readrops.app.util.components.SwitchText import com.readrops.app.util.theme.LargeSpacer import com.readrops.app.util.theme.MediumSpacer -import com.readrops.app.util.theme.VeryShortSpacer import com.readrops.app.util.theme.spacing import com.readrops.db.entities.Feed +import com.readrops.db.entities.OpenIn @OptIn(ExperimentalMaterial3Api::class) @Composable fun FeedModalBottomSheet( feed: Feed, - accountNotificationsEnabled: Boolean, onDismissRequest: () -> Unit, onOpen: () -> Unit, onUpdate: () -> Unit, //onUpdateColor: () -> Unit, onUpdateNotifications: (Boolean) -> Unit, + onOpenInClick: () -> Unit, onDelete: () -> Unit, + accountNotificationsEnabled: Boolean, canUpdateFeed: Boolean, canDeleteFeed: Boolean ) { @@ -58,83 +51,7 @@ fun FeedModalBottomSheet( onDismissRequest = { onDismissRequest() } ) { Column { - Box( - modifier = Modifier.fillMaxWidth() - ) { - if (feed.imageUrl != null) { - AsyncImage( - model = feed.imageUrl, - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .matchParentSize() - .drawWithContent { - drawContent() - drawRect( - color = Color.Black.copy(alpha = 0.65f) - ) - } - .blur(2.5.dp) - ) - } - - Row( - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding( - top = MaterialTheme.spacing.largeSpacing, - start = MaterialTheme.spacing.largeSpacing, - end = MaterialTheme.spacing.largeSpacing, - bottom = MaterialTheme.spacing.mediumSpacing - ) - ) { - AsyncImage( - model = feed.iconUrl, - contentDescription = feed.name!!, - placeholder = painterResource(id = R.drawable.ic_rss_feed_grey), - error = painterResource(id = R.drawable.ic_rss_feed_grey), - modifier = Modifier.size(MaterialTheme.spacing.veryLargeSpacing) - ) - - MediumSpacer() - - Column { - Text( - text = feed.name!!, - style = MaterialTheme.typography.titleLarge, - color = if (feed.imageUrl != null) { - Color.White - } else { - MaterialTheme.colorScheme.onBackground - }, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - - if (feed.description != null) { - VeryShortSpacer() - - Text( - text = feed.description!!, - style = MaterialTheme.typography.bodyMedium, - color = if (feed.imageUrl != null) { - Color.White - } else { - MaterialTheme.colorScheme.onSurfaceVariant - }, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - } - } - } - } - - if (feed.imageUrl == null) { - HorizontalDivider( - modifier = Modifier.padding(horizontal = MaterialTheme.spacing.mediumSpacing) - ) - } + FeedBanner(feed) SwitchText( title = stringResource(R.string.enable_notifications), @@ -145,6 +62,20 @@ fun FeedModalBottomSheet( onCheckedChange = onUpdateNotifications ) + BasePreference( + title = stringResource(R.string.open_feed_in), + subtitle = if (feed.openIn == OpenIn.LOCAL_VIEW) { + stringResource(R.string.local_view) + } else { + stringResource(R.string.external_view) + }, + onClick = onOpenInClick, + paddingValues = PaddingValues( + horizontal = MaterialTheme.spacing.mediumSpacing, + vertical = MaterialTheme.spacing.shortSpacing + ) + ) + BottomSheetOption( text = stringResource(R.string.open), icon = ImageVector.vectorResource(id = R.drawable.ic_open_in_browser), diff --git a/app/src/main/java/com/readrops/app/feeds/dialogs/FeedDialogs.kt b/app/src/main/java/com/readrops/app/feeds/dialogs/FeedDialogs.kt new file mode 100644 index 00000000..173c7d82 --- /dev/null +++ b/app/src/main/java/com/readrops/app/feeds/dialogs/FeedDialogs.kt @@ -0,0 +1,136 @@ +package com.readrops.app.feeds.dialogs + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Delete +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.readrops.app.R +import com.readrops.app.feeds.DialogState +import com.readrops.app.feeds.FeedScreenModel +import com.readrops.app.feeds.FeedState +import com.readrops.app.more.preferences.components.RadioButtonPreferenceDialog +import com.readrops.app.more.preferences.components.ToggleableInfo +import com.readrops.app.util.components.dialog.TextFieldDialog +import com.readrops.app.util.components.dialog.TwoChoicesDialog +import com.readrops.db.entities.OpenIn + +@Composable +fun FeedDialogs(state: FeedState, screenModel: FeedScreenModel) { + val uriHandler = LocalUriHandler.current + + val folderState by screenModel.folderState.collectAsStateWithLifecycle() + + when (val dialog = state.dialog) { + is DialogState.DeleteFeed -> { + TwoChoicesDialog( + title = stringResource(R.string.delete_feed), + text = stringResource(R.string.delete_feed_question, dialog.feed.name!!), + icon = rememberVectorPainter(image = Icons.Default.Delete), + confirmText = stringResource(R.string.delete), + dismissText = stringResource(R.string.cancel), + onDismiss = { screenModel.closeDialog() }, + onConfirm = { + screenModel.deleteFeed(dialog.feed) + screenModel.closeDialog() + } + ) + } + + is DialogState.FeedSheet -> { + FeedModalBottomSheet( + feed = dialog.feed, + accountNotificationsEnabled = state.isAccountNotificationsEnabled, + onDismissRequest = { screenModel.closeDialog() }, + onOpen = { + uriHandler.openUri(dialog.feed.siteUrl!!) + screenModel.closeDialog() + }, + onUpdate = { + screenModel.openDialog(DialogState.UpdateFeed(dialog.feed, dialog.folder)) + }, + onDelete = { screenModel.openDialog(DialogState.DeleteFeed(dialog.feed)) }, + onUpdateNotifications = { + screenModel.updateFeedNotifications(dialog.feed.id, it) + }, + onOpenInClick = { + screenModel.openDialog(DialogState.UpdateFeedOpenInSetting(dialog.feed)) + }, + canUpdateFeed = dialog.config.canUpdateFeed, + canDeleteFeed = dialog.config.canDeleteFeed + ) + } + + is DialogState.UpdateFeed -> { + UpdateFeedDialog( + viewModel = screenModel, + onDismissRequest = { screenModel.closeDialog(dialog) } + ) + } + + DialogState.AddFolder -> { + TextFieldDialog( + title = stringResource(id = R.string.add_folder), + icon = painterResource(id = R.drawable.ic_new_folder), + label = stringResource(id = R.string.name), + state = folderState, + onValueChange = { screenModel.setFolderName(it) }, + onValidate = { screenModel.folderValidate() }, + onDismiss = { screenModel.closeDialog(DialogState.AddFolder) } + ) + } + + is DialogState.DeleteFolder -> { + TwoChoicesDialog( + title = stringResource(R.string.delete_folder), + text = stringResource(R.string.delete_folder_question, dialog.folder.name!!), + icon = rememberVectorPainter(image = Icons.Default.Delete), + confirmText = stringResource(R.string.delete), + dismissText = stringResource(R.string.cancel), + onDismiss = { screenModel.closeDialog() }, + onConfirm = { + screenModel.deleteFolder(dialog.folder) + screenModel.closeDialog() + } + ) + } + + is DialogState.UpdateFolder -> { + TextFieldDialog( + title = stringResource(id = R.string.edit_folder), + icon = painterResource(id = R.drawable.ic_folder_grey), + label = stringResource(id = R.string.name), + state = folderState, + onValueChange = { screenModel.setFolderName(it) }, + onValidate = { screenModel.folderValidate(updateFolder = true) }, + onDismiss = { screenModel.closeDialog(DialogState.UpdateFolder(dialog.folder)) } + ) + } + + is DialogState.UpdateFeedOpenInSetting -> { + RadioButtonPreferenceDialog( + title = stringResource(R.string.open_feed_in), + entries = listOf( + ToggleableInfo( + key = OpenIn.LOCAL_VIEW, + text = stringResource(R.string.local_view), + isSelected = dialog.feed.openIn == OpenIn.LOCAL_VIEW + ), + ToggleableInfo( + key = OpenIn.EXTERNAL_VIEW, + text = stringResource(R.string.external_view), + isSelected = dialog.feed.openIn == OpenIn.EXTERNAL_VIEW + ) + ), + onCheckChange = { screenModel.updateFeedOpenInSetting(dialog.feed.id, it) }, + onDismiss = { screenModel.closeDialog(dialog) }, + ) + } + + null -> {} + } +} diff --git a/app/src/main/java/com/readrops/app/more/preferences/components/BasePreference.kt b/app/src/main/java/com/readrops/app/more/preferences/components/BasePreference.kt index 288f4e26..1d9afe60 100644 --- a/app/src/main/java/com/readrops/app/more/preferences/components/BasePreference.kt +++ b/app/src/main/java/com/readrops/app/more/preferences/components/BasePreference.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme @@ -22,7 +23,8 @@ fun BasePreference( onClick: () -> Unit, modifier: Modifier = Modifier, subtitle: String? = null, - rightComponent: (@Composable () -> Unit)? = null + rightComponent: (@Composable () -> Unit)? = null, + paddingValues: PaddingValues = PaddingValues(MaterialTheme.spacing.mediumSpacing) ) { Box( modifier = modifier.clickable { onClick() } @@ -30,7 +32,7 @@ fun BasePreference( Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, - modifier = Modifier.padding(MaterialTheme.spacing.mediumSpacing) + modifier = Modifier.padding(paddingValues) ) { Column( modifier = Modifier.weight(1f) diff --git a/app/src/main/java/com/readrops/app/repositories/GetFoldersWithFeeds.kt b/app/src/main/java/com/readrops/app/repositories/GetFoldersWithFeeds.kt index 65b66f28..a756f185 100644 --- a/app/src/main/java/com/readrops/app/repositories/GetFoldersWithFeeds.kt +++ b/app/src/main/java/com/readrops/app/repositories/GetFoldersWithFeeds.kt @@ -3,6 +3,7 @@ package com.readrops.app.repositories import com.readrops.db.Database import com.readrops.db.entities.Feed import com.readrops.db.entities.Folder +import com.readrops.db.entities.OpenIn import com.readrops.db.filters.MainFilter import com.readrops.db.queries.FeedUnreadCountQueryBuilder import com.readrops.db.queries.FoldersAndFeedsQueryBuilder @@ -49,6 +50,11 @@ class GetFoldersWithFeeds( siteUrl = it.feedSiteUrl, description = it.feedDescription, isNotificationEnabled = it.feedNotificationsEnabled, + openIn = if (it.feedOpenIn != null) { + it.feedOpenIn!! + } else { + OpenIn.LOCAL_VIEW + }, remoteId = it.feedRemoteId, unreadCount = itemCounts[it.feedId] ?: 0 ) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 5bbe8415..be26c198 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -188,4 +188,7 @@ Une erreur s\'est produite lors du téléchargement de l\'image Activer les notifications Les notifications du compte sont actuellement désactivées + Ouvrir le flux dans + Vue locale + Vue externe \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0b520784..460e9435 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -197,4 +197,7 @@ An error occurred while downloading the image Enable notifications Account notifications are currently disabled + Open Feed in + Local view + External view \ No newline at end of file diff --git a/db/schemas/com.readrops.db.Database/5.json b/db/schemas/com.readrops.db.Database/5.json index fd47e112..9c1ac701 100644 --- a/db/schemas/com.readrops.db.Database/5.json +++ b/db/schemas/com.readrops.db.Database/5.json @@ -2,11 +2,11 @@ "formatVersion": 1, "database": { "version": 5, - "identityHash": "63de09bfed367e5705a0889d928f056d", + "identityHash": "4f9ecfcf1febf90be9bd9c0cedf0f8a1", "entities": [ { "tableName": "Feed", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `description` TEXT, `url` TEXT, `image_url` TEXT, `siteUrl` TEXT, `last_updated` TEXT, `color` INTEGER NOT NULL, `icon_url` TEXT, `etag` TEXT, `last_modified` TEXT, `folder_id` INTEGER, `remote_id` TEXT, `account_id` INTEGER NOT NULL, `notification_enabled` INTEGER NOT NULL DEFAULT 1, FOREIGN KEY(`folder_id`) REFERENCES `Folder`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`account_id`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `description` TEXT, `url` TEXT, `image_url` TEXT, `siteUrl` TEXT, `last_updated` TEXT, `color` INTEGER NOT NULL, `icon_url` TEXT, `etag` TEXT, `last_modified` TEXT, `folder_id` INTEGER, `remote_id` TEXT, `account_id` INTEGER NOT NULL, `notification_enabled` INTEGER NOT NULL DEFAULT 1, `open_in` TEXT NOT NULL DEFAULT 'LOCAL_VIEW', FOREIGN KEY(`folder_id`) REFERENCES `Folder`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`account_id`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "id", @@ -98,6 +98,13 @@ "affinity": "INTEGER", "notNull": true, "defaultValue": "1" + }, + { + "fieldPath": "openIn", + "columnName": "open_in", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'LOCAL_VIEW'" } ], "primaryKey": { @@ -526,7 +533,7 @@ "views": [], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '63de09bfed367e5705a0889d928f056d')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '4f9ecfcf1febf90be9bd9c0cedf0f8a1')" ] } } \ No newline at end of file diff --git a/db/src/main/java/com/readrops/db/Database.kt b/db/src/main/java/com/readrops/db/Database.kt index e98f2934..8193875f 100644 --- a/db/src/main/java/com/readrops/db/Database.kt +++ b/db/src/main/java/com/readrops/db/Database.kt @@ -124,5 +124,8 @@ object MigrationFrom4To5 : Migration(4, 5) { // add image_url field db.execSQL("""ALTER TABLE `Feed` ADD `image_url` TEXT DEFAULT NULL""") + + // add open_in field + db.execSQL("""ALTER TABLE `Feed` ADD `open_in` TEXT DEFAULT "LOCAL_VIEW" NOT NULL""") } } diff --git a/db/src/main/java/com/readrops/db/dao/FeedDao.kt b/db/src/main/java/com/readrops/db/dao/FeedDao.kt index 5aa8aac8..2415417e 100644 --- a/db/src/main/java/com/readrops/db/dao/FeedDao.kt +++ b/db/src/main/java/com/readrops/db/dao/FeedDao.kt @@ -7,6 +7,7 @@ import androidx.room.Transaction import androidx.sqlite.db.SupportSQLiteQuery import com.readrops.db.entities.Feed import com.readrops.db.entities.Item +import com.readrops.db.entities.OpenIn import com.readrops.db.entities.account.Account import com.readrops.db.pojo.FeedWithCount import com.readrops.db.pojo.FeedWithFolder @@ -73,6 +74,9 @@ interface FeedDao : BaseDao { @Query("Update Feed set icon_url = :iconUrl Where id = :feedId") suspend fun updateFeedIconUrl(feedId: Int, iconUrl: String) + @Query("Update Feed set open_in = :openIn Where id = :feedId") + suspend fun updateOpenInSetting(feedId: Int, openIn: OpenIn) + /** * Insert, update and delete feeds by account * diff --git a/db/src/main/java/com/readrops/db/entities/Feed.kt b/db/src/main/java/com/readrops/db/entities/Feed.kt index fd2e0173..1e49a698 100644 --- a/db/src/main/java/com/readrops/db/entities/Feed.kt +++ b/db/src/main/java/com/readrops/db/entities/Feed.kt @@ -8,6 +8,11 @@ import androidx.room.Ignore import androidx.room.PrimaryKey import com.readrops.db.entities.account.Account +enum class OpenIn { + LOCAL_VIEW, + EXTERNAL_VIEW +} + @Entity( foreignKeys = [ ForeignKey( @@ -42,6 +47,10 @@ data class Feed( name = "notification_enabled", defaultValue = "1" ) var isNotificationEnabled: Boolean = true, + @ColumnInfo( + name = "open_in", + defaultValue = "LOCAL_VIEW" + ) var openIn: OpenIn = OpenIn.LOCAL_VIEW, @Ignore var unreadCount: Int = 0, @Ignore var remoteFolderId: String? = null, ) \ No newline at end of file diff --git a/db/src/main/java/com/readrops/db/pojo/FeedWithFolder.kt b/db/src/main/java/com/readrops/db/pojo/FeedWithFolder.kt index 6b81c034..cef71e48 100644 --- a/db/src/main/java/com/readrops/db/pojo/FeedWithFolder.kt +++ b/db/src/main/java/com/readrops/db/pojo/FeedWithFolder.kt @@ -3,6 +3,7 @@ package com.readrops.db.pojo import androidx.room.ColumnInfo import androidx.room.Embedded import com.readrops.db.entities.Feed +import com.readrops.db.entities.OpenIn data class FeedWithFolder( @Embedded val feed: Feed, @@ -21,6 +22,7 @@ data class FolderWithFeed( val feedDescription: String? = null, val feedSiteUrl: String? = null, val feedNotificationsEnabled: Boolean = true, + val feedOpenIn: OpenIn? = null, val feedRemoteId: String? = null, val accountId: Int = 0 ) diff --git a/db/src/main/java/com/readrops/db/queries/FoldersAndFeedsQueryBuilder.kt b/db/src/main/java/com/readrops/db/queries/FoldersAndFeedsQueryBuilder.kt index a28f2f79..8d8caf99 100644 --- a/db/src/main/java/com/readrops/db/queries/FoldersAndFeedsQueryBuilder.kt +++ b/db/src/main/java/com/readrops/db/queries/FoldersAndFeedsQueryBuilder.kt @@ -15,6 +15,7 @@ object FoldersAndFeedsQueryBuilder { "Feed.siteUrl As feedSiteUrl", "Feed.description as feedDescription", "Feed.notification_enabled as feedNotificationsEnabled", + "Feed.open_in as feedOpenIn", "Feed.remote_id as feedRemoteId", "Folder.id As folderId", "Folder.name As folderName",