Add Open In feed parameter
This commit is contained in:
parent
cf75fc914e
commit
ef9111c604
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -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
|
@ -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),
|
||||
|
136
app/src/main/java/com/readrops/app/feeds/dialogs/FeedDialogs.kt
Normal file
136
app/src/main/java/com/readrops/app/feeds/dialogs/FeedDialogs.kt
Normal file
@ -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 -> {}
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -188,4 +188,7 @@
|
||||
<string name="error_image_download">Une erreur s\'est produite lors du téléchargement de l\'image</string>
|
||||
<string name="enable_notifications">Activer les notifications</string>
|
||||
<string name="account_notifications_disabled">Les notifications du compte sont actuellement désactivées</string>
|
||||
<string name="open_feed_in">Ouvrir le flux dans</string>
|
||||
<string name="local_view">Vue locale</string>
|
||||
<string name="external_view">Vue externe</string>
|
||||
</resources>
|
@ -197,4 +197,7 @@
|
||||
<string name="error_image_download">An error occurred while downloading the image</string>
|
||||
<string name="enable_notifications">Enable notifications</string>
|
||||
<string name="account_notifications_disabled">Account notifications are currently disabled</string>
|
||||
<string name="open_feed_in">Open Feed in</string>
|
||||
<string name="local_view">Local view</string>
|
||||
<string name="external_view">External view</string>
|
||||
</resources>
|
@ -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')"
|
||||
]
|
||||
}
|
||||
}
|
@ -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""")
|
||||
}
|
||||
}
|
||||
|
@ -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<Feed> {
|
||||
@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
|
||||
*
|
||||
|
@ -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,
|
||||
)
|
@ -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
|
||||
)
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user