Improve NotificationsScreen UI
This commit is contained in:
parent
9210b8b7fe
commit
4771831d15
@ -20,7 +20,6 @@ import androidx.compose.ui.unit.dp
|
||||
import coil.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
|
||||
|
||||
@Composable
|
||||
@ -62,13 +61,10 @@ fun NotificationItem(
|
||||
text = feedName,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
|
||||
)
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
|
||||
if (folderName != null) {
|
||||
VeryShortSpacer()
|
||||
|
||||
Text(
|
||||
text = folderName,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
|
@ -6,8 +6,6 @@ import android.content.Intent
|
||||
import android.provider.Settings
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@ -27,7 +25,6 @@ import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@ -45,8 +42,11 @@ import com.readrops.app.R
|
||||
import com.readrops.app.more.preferences.PreferencesScreen
|
||||
import com.readrops.app.more.preferences.components.BasePreference
|
||||
import com.readrops.app.util.components.AndroidScreen
|
||||
import com.readrops.app.util.components.CenteredProgressIndicator
|
||||
import com.readrops.app.util.components.Placeholder
|
||||
import com.readrops.app.util.components.ThreeDotsMenu
|
||||
import com.readrops.app.util.components.dialog.TwoChoicesDialog
|
||||
import com.readrops.app.util.theme.LargeSpacer
|
||||
import com.readrops.app.util.theme.MediumSpacer
|
||||
import com.readrops.app.util.theme.spacing
|
||||
import com.readrops.db.entities.account.Account
|
||||
@ -68,9 +68,10 @@ class NotificationsScreen(val account: Account) : AndroidScreen() {
|
||||
TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
|
||||
val permissionState = rememberPermissionState(Manifest.permission.POST_NOTIFICATIONS)
|
||||
val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) {
|
||||
screenModel.refreshNotificationManager()
|
||||
}
|
||||
val launcher =
|
||||
rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) {
|
||||
screenModel.refreshNotificationManager()
|
||||
}
|
||||
|
||||
LaunchedEffect(permissionState.status) {
|
||||
if (permissionState.status.isGranted) {
|
||||
@ -108,18 +109,25 @@ class NotificationsScreen(val account: Account) : AndroidScreen() {
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
ThreeDotsMenu(
|
||||
items = mapOf(
|
||||
1 to if (state.allFeedNotificationsEnabled) {
|
||||
stringResource(id = R.string.disable_all)
|
||||
} else {
|
||||
stringResource(id = R.string.enable_all)
|
||||
}
|
||||
),
|
||||
onItemClick = {
|
||||
screenModel.setAllFeedsNotificationsState(!state.allFeedNotificationsEnabled)
|
||||
if (state.feedsWithFolderState is FeedsWithFolderState.Loaded) {
|
||||
val loadedState =
|
||||
state.feedsWithFolderState as FeedsWithFolderState.Loaded
|
||||
|
||||
if (loadedState.feedsWithFolder.isNotEmpty()) {
|
||||
ThreeDotsMenu(
|
||||
items = mapOf(
|
||||
1 to if (loadedState.allFeedNotificationsEnabled) {
|
||||
stringResource(id = R.string.disable_all)
|
||||
} else {
|
||||
stringResource(id = R.string.enable_all)
|
||||
}
|
||||
),
|
||||
onItemClick = {
|
||||
screenModel.setAllFeedsNotificationsState(!loadedState.allFeedNotificationsEnabled)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
scrollBehavior = topAppBarScrollBehavior
|
||||
)
|
||||
@ -155,28 +163,29 @@ class NotificationsScreen(val account: Account) : AndroidScreen() {
|
||||
}
|
||||
|
||||
item {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = MaterialTheme.spacing.mediumSpacing)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.enable_notifications)
|
||||
)
|
||||
BasePreference(
|
||||
title = stringResource(R.string.show_notifications_background_sync),
|
||||
subtitle = stringResource(R.string.background_sync_new_articles),
|
||||
onClick = {
|
||||
screenModel.setAccountNotificationsState(!state.areAccountNotificationsEnabled)
|
||||
|
||||
Switch(
|
||||
checked = state.areAccountNotificationsEnabled,
|
||||
onCheckedChange = {
|
||||
screenModel.setAccountNotificationsState(it)
|
||||
|
||||
if (it) {
|
||||
screenModel.setBackgroundSyncDialogState(true)
|
||||
}
|
||||
if (state.areAccountNotificationsEnabled.not()) {
|
||||
screenModel.setBackgroundSyncDialogState(true)
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
rightComponent = {
|
||||
Switch(
|
||||
checked = state.areAccountNotificationsEnabled,
|
||||
onCheckedChange = {
|
||||
screenModel.setAccountNotificationsState(it)
|
||||
|
||||
if (it) {
|
||||
screenModel.setBackgroundSyncDialogState(true)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
MediumSpacer()
|
||||
|
||||
@ -187,26 +196,56 @@ class NotificationsScreen(val account: Account) : AndroidScreen() {
|
||||
)
|
||||
}
|
||||
|
||||
items(
|
||||
items = state.feedsWithFolder,
|
||||
key = { it.feed.id }
|
||||
) { feedWithFolder ->
|
||||
NotificationItem(
|
||||
feedName = feedWithFolder.feed.name!!,
|
||||
iconUrl = feedWithFolder.feed.iconUrl,
|
||||
folderName = feedWithFolder.folderName,
|
||||
checked = feedWithFolder.feed.isNotificationEnabled,
|
||||
enabled = state.areAccountNotificationsEnabled,
|
||||
onCheckChange = {
|
||||
if (state.areAccountNotificationsEnabled) {
|
||||
screenModel.setFeedNotificationsState(feedWithFolder.feed.id, it)
|
||||
when (state.feedsWithFolderState) {
|
||||
is FeedsWithFolderState.Loaded -> {
|
||||
val feedsWithFolder =
|
||||
(state.feedsWithFolderState as FeedsWithFolderState.Loaded).feedsWithFolder
|
||||
|
||||
if (feedsWithFolder.isNotEmpty()) {
|
||||
items(
|
||||
items = (state.feedsWithFolderState as FeedsWithFolderState.Loaded).feedsWithFolder,
|
||||
key = { it.feed.id }
|
||||
) { feedWithFolder ->
|
||||
NotificationItem(
|
||||
feedName = feedWithFolder.feed.name!!,
|
||||
iconUrl = feedWithFolder.feed.iconUrl,
|
||||
folderName = feedWithFolder.folderName,
|
||||
checked = feedWithFolder.feed.isNotificationEnabled,
|
||||
enabled = state.areAccountNotificationsEnabled,
|
||||
onCheckChange = {
|
||||
if (state.areAccountNotificationsEnabled) {
|
||||
screenModel.setFeedNotificationsState(
|
||||
feedWithFolder.feed.id,
|
||||
it
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
item {
|
||||
LargeSpacer()
|
||||
|
||||
Placeholder(
|
||||
text = stringResource(id = R.string.no_feed),
|
||||
painter = painterResource(id = R.drawable.ic_rss_feed_grey),
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
FeedsWithFolderState.Loading -> {
|
||||
item {
|
||||
repeat(4) {
|
||||
LargeSpacer()
|
||||
}
|
||||
|
||||
CenteredProgressIndicator()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,12 @@ class NotificationsScreenModel(
|
||||
private val preferences: Preferences,
|
||||
private val notificationManager: NotificationManagerCompat,
|
||||
private val dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||
) : StateScreenModel<NotificationsState>(NotificationsState(areAccountNotificationsEnabled = account.isNotificationsEnabled)) {
|
||||
) : StateScreenModel<NotificationsState>(
|
||||
NotificationsState(
|
||||
areNotificationsEnabled = notificationManager.areNotificationsEnabled(),
|
||||
areAccountNotificationsEnabled = account.isNotificationsEnabled
|
||||
)
|
||||
) {
|
||||
|
||||
init {
|
||||
screenModelScope.launch(dispatcher) {
|
||||
@ -31,7 +36,11 @@ class NotificationsScreenModel(
|
||||
screenModelScope.launch(dispatcher) {
|
||||
database.feedDao().selectFeedsWithFolderName(account.id)
|
||||
.collect { feedsWithFolder ->
|
||||
mutableState.update { it.copy(feedsWithFolder = feedsWithFolder) }
|
||||
mutableState.update {
|
||||
it.copy(
|
||||
feedsWithFolderState = FeedsWithFolderState.Loaded(feedsWithFolder)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,12 +88,18 @@ class NotificationsScreenModel(
|
||||
|
||||
data class NotificationsState(
|
||||
val areAccountNotificationsEnabled: Boolean = false,
|
||||
val feedsWithFolder: List<FeedWithFolder> = emptyList(),
|
||||
val feedsWithFolderState: FeedsWithFolderState = FeedsWithFolderState.Loading,
|
||||
val showBackgroundSyncDialog: Boolean = false,
|
||||
val isBackGroundSyncEnabled: Boolean = false,
|
||||
val areNotificationsEnabled: Boolean = false
|
||||
) {
|
||||
)
|
||||
|
||||
val allFeedNotificationsEnabled
|
||||
get() = feedsWithFolder.none { !it.feed.isNotificationEnabled }
|
||||
sealed class FeedsWithFolderState {
|
||||
data object Loading : FeedsWithFolderState()
|
||||
|
||||
data class Loaded(val feedsWithFolder: List<FeedWithFolder>) : FeedsWithFolderState() {
|
||||
|
||||
val allFeedNotificationsEnabled
|
||||
get() = feedsWithFolder.none { !it.feed.isNotificationEnabled }
|
||||
}
|
||||
}
|
@ -427,8 +427,8 @@ object TimelineTab : Tab {
|
||||
)
|
||||
|
||||
Placeholder(
|
||||
text = stringResource(R.string.no_item),
|
||||
painter = painterResource(R.drawable.ic_rss_feed_grey)
|
||||
text = stringResource(R.string.no_article),
|
||||
painter = painterResource(R.drawable.ic_timeline),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -10,19 +10,23 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.readrops.app.util.theme.ShortSpacer
|
||||
import com.readrops.app.util.toDp
|
||||
|
||||
|
||||
@Composable
|
||||
fun CenteredColumn(
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
modifier = modifier.fillMaxSize()
|
||||
) {
|
||||
content()
|
||||
}
|
||||
@ -32,19 +36,26 @@ fun CenteredColumn(
|
||||
fun Placeholder(
|
||||
text: String,
|
||||
painter: Painter,
|
||||
modifier: Modifier = Modifier,
|
||||
textStyle: TextStyle = MaterialTheme.typography.titleLarge,
|
||||
iconSize: Dp = 48.dp,
|
||||
tint: Color = MaterialTheme.colorScheme.primary
|
||||
) {
|
||||
CenteredColumn {
|
||||
CenteredColumn(
|
||||
modifier = modifier
|
||||
) {
|
||||
Icon(
|
||||
painter = painter,
|
||||
tint = tint,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(MaterialTheme.typography.displayMedium.toDp() * 1.5f)
|
||||
modifier = Modifier.size(iconSize)
|
||||
)
|
||||
|
||||
ShortSpacer()
|
||||
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.displaySmall
|
||||
style = textStyle
|
||||
)
|
||||
}
|
||||
}
|
@ -192,4 +192,7 @@
|
||||
<string name="add_to_favorite">Ajouter aux favoris</string>
|
||||
<string name="grant_access_notifications">Autoriser l\'accès aux notifications</string>
|
||||
<string name="system_notifications_disabled">Les notfications système sont désactivées. Cliquez ici pour les activer</string>
|
||||
<string name="show_notifications_background_sync">Afficher les notifications après la synchronisation en arrière-plan</string>
|
||||
<string name="background_sync_new_articles">Soyez prévenus des nouveaux articles après la synchronisation en arrière-plan</string>
|
||||
<string name="no_article">Aucun article</string>
|
||||
</resources>
|
@ -201,4 +201,7 @@
|
||||
<string name="add_to_favorite">Add to favorites</string>
|
||||
<string name="grant_access_notifications">Grant access to Notifications</string>
|
||||
<string name="system_notifications_disabled">System notifications are currently disabled. Click here to enable them</string>
|
||||
<string name="show_notifications_background_sync">Show notifications after background synchronization</string>
|
||||
<string name="background_sync_new_articles">Be alerted of new articles after background synchronization</string>
|
||||
<string name="no_article">No article</string>
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user