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",