feat: move Settings to navingation drawer (#1080)

This commit is contained in:
Diego Beraldin 2024-07-05 10:57:41 +02:00 committed by GitHub
parent ec431bca10
commit daf82cee84
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 148 additions and 142 deletions

View File

@ -45,10 +45,10 @@ class DefaultNavigationCoordinatorTest {
val initial = sut.currentSection.value
assertNull(initial)
sut.setCurrentSection(TabNavigationSection.Settings)
sut.setCurrentSection(TabNavigationSection.Profile)
val value = sut.currentSection.value
assertEquals(TabNavigationSection.Settings, value)
assertEquals(TabNavigationSection.Profile, value)
}
@Test

View File

@ -12,11 +12,19 @@ sealed interface DrawerEvent {
data object Close : DrawerEvent
data class OpenCommunity(val community: CommunityModel) : DrawerEvent
data class OpenCommunity(
val community: CommunityModel,
) : DrawerEvent
data class OpenMultiCommunity(val community: MultiCommunityModel) : DrawerEvent
data object OpenSettings : DrawerEvent
data class ChangeListingType(val value: ListingType) : DrawerEvent
data class OpenMultiCommunity(
val community: MultiCommunityModel,
) : DrawerEvent
data class ChangeListingType(
val value: ListingType,
) : DrawerEvent
}
@Stable

View File

@ -19,8 +19,6 @@ sealed interface TabNavigationSection {
data object Profile : TabNavigationSection
data object Inbox : TabNavigationSection
data object Settings : TabNavigationSection
}
sealed interface ComposeEvent {

View File

@ -39,6 +39,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepos
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.SettingsRow
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.SettingsSwitchRow
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.ThemeBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.LocalStrings
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
@ -131,6 +132,17 @@ class SettingsColorAndFontScreen : Screen {
modifier = Modifier.fillMaxSize().verticalScroll(scrollState),
verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) {
// theme
SettingsRow(
title = LocalStrings.current.settingsUiTheme,
value = uiState.uiTheme.toReadableName(),
onTap =
rememberCallback {
val sheet = ThemeBottomSheet()
navigationCoordinator.showBottomSheet(sheet)
},
)
// dynamic colors
if (uiState.supportsDynamicColors) {
SettingsSwitchRow(

View File

@ -5,6 +5,7 @@ import androidx.compose.ui.graphics.toArgb
import cafe.adriel.voyager.core.model.screenModelScope
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.CommentBarTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toInt
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.repository.ThemeRepository
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.ColorSchemeProvider
@ -82,6 +83,11 @@ class SettingsColorAndFontViewModel(
updateState { it.copy(isLogged = logged ?: false) }
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeTheme::class)
.onEach { evt ->
changeTheme(evt.value)
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeFontFamily::class)
.onEach { evt ->
@ -127,6 +133,17 @@ class SettingsColorAndFontViewModel(
}
}
private fun changeTheme(value: UiTheme?) {
themeRepository.changeUiTheme(value)
screenModelScope.launch {
val settings =
settingsRepository.currentSettings.value.copy(
theme = value?.toInt(),
)
saveSettings(settings)
}
}
private fun changeFontFamily(value: UiFontFamily) {
themeRepository.changeUiFontFamily(value)
screenModelScope.launch {

View File

@ -11,17 +11,21 @@ interface SettingsMviModel :
MviModel<SettingsMviModel.Intent, SettingsMviModel.UiState, SettingsMviModel.Effect>,
ScreenModel {
sealed interface Intent {
data class ChangeUiTheme(val value: UiTheme?) : Intent
data class ChangeIncludeNsfw(
val value: Boolean,
) : Intent
data class ChangeLanguage(val value: String) : Intent
data class ChangeBlurNsfw(
val value: Boolean,
) : Intent
data class ChangeIncludeNsfw(val value: Boolean) : Intent
data class ChangeEnableSwipeActions(
val value: Boolean,
) : Intent
data class ChangeBlurNsfw(val value: Boolean) : Intent
data class ChangeEnableSwipeActions(val value: Boolean) : Intent
data class ChangeCrashReportEnabled(val value: Boolean) : Intent
data class ChangeCrashReportEnabled(
val value: Boolean,
) : Intent
}
data class UiState(

View File

@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.AdminPanelSettings
import androidx.compose.material.icons.filled.BugReport
import androidx.compose.material.icons.filled.Explicit
@ -39,7 +40,6 @@ import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.buildAnnotatedString
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.koin.getScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toReadableName
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.SettingsHeader
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.SettingsRow
@ -48,10 +48,8 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.handleUrl
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.LanguageBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.ListingTypeBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.ThemeBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.UrlOpeningModeBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.LocalStrings
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.TabNavigationSection
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getDrawerCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
@ -99,18 +97,6 @@ class SettingsScreen : Screen {
val uriHandler = LocalUriHandler.current
val customTabsHelper = remember { getCustomTabsHelper() }
LaunchedEffect(Unit) {
navigationCoordinator.onDoubleTabSelection
.onEach { section ->
runCatching {
if (section == TabNavigationSection.Settings) {
scrollState.scrollTo(0)
topAppBarState.heightOffset = 0f
topAppBarState.contentOffset = 0f
}
}
}.launchIn(this)
}
LaunchedEffect(notificationCenter) {
notificationCenter
.subscribe(NotificationCenterEvent.CloseDialog::class)
@ -120,11 +106,24 @@ class SettingsScreen : Screen {
}
Scaffold(
modifier = Modifier.padding(Spacing.xs),
topBar = {
TopAppBar(
scrollBehavior = scrollBehavior,
navigationIcon = {
if (navigationCoordinator.canPop.value) {
Image(
modifier =
Modifier
.onClick(
onClick = {
navigationCoordinator.popScreen()
},
),
imageVector = Icons.AutoMirrored.Default.ArrowBack,
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
)
} else {
Image(
modifier =
Modifier.onClick(
@ -138,6 +137,7 @@ class SettingsScreen : Screen {
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
)
}
},
title = {
Text(
@ -184,17 +184,6 @@ class SettingsScreen : Screen {
},
)
// theme
SettingsRow(
title = LocalStrings.current.settingsUiTheme,
value = uiState.uiTheme.toReadableName(),
onTap =
rememberCallback {
val sheet = ThemeBottomSheet()
navigationCoordinator.showBottomSheet(sheet)
},
)
// colors and fonts
SettingsRow(
title = LocalStrings.current.settingsColorsAndFonts,

View File

@ -1,8 +1,6 @@
package com.github.diegoberaldin.raccoonforlemmy.feature.settings.main
import cafe.adriel.voyager.core.model.screenModelScope
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toInt
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.repository.ThemeRepository
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.L10nManager
@ -41,53 +39,60 @@ class SettingsViewModel(
private val customTabsHelper: CustomTabsHelper,
private val siteSupportsHiddenPosts: GetSiteSupportsHiddenPostsUseCase,
private val siteSupportsMediaListUseCase: GetSiteSupportsMediaListUseCase,
) : SettingsMviModel,
DefaultMviModel<SettingsMviModel.Intent, SettingsMviModel.UiState, SettingsMviModel.Effect>(
) : DefaultMviModel<SettingsMviModel.Intent, SettingsMviModel.UiState, SettingsMviModel.Effect>(
initialState = SettingsMviModel.UiState(),
) {
),
SettingsMviModel {
init {
screenModelScope.launch {
themeRepository.uiTheme.onEach { value ->
themeRepository.uiTheme
.onEach { value ->
updateState { it.copy(uiTheme = value) }
}.launchIn(this)
l10nManager.lyricist.state.onEach { lang ->
l10nManager.lyricist.state
.onEach { lang ->
updateState { it.copy(lang = lang.languageTag) }
}.launchIn(this)
identityRepository.isLogged.onEach { logged ->
identityRepository.isLogged
.onEach { logged ->
updateState { it.copy(isLogged = logged ?: false) }
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.Logout::class).onEach {
notificationCenter
.subscribe(NotificationCenterEvent.Logout::class)
.onEach {
handleLogout()
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeLanguage::class)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeLanguage::class)
.onEach { evt ->
changeLanguage(evt.value)
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeTheme::class).onEach { evt ->
changeTheme(evt.value)
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeFeedType::class)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeFeedType::class)
.onEach { evt ->
if (evt.screenKey == "settings") {
changeDefaultListingType(evt.value)
}
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeSortType::class)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeSortType::class)
.onEach { evt ->
if (evt.screenKey == "settings") {
changeDefaultPostSortType(evt.value)
}
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeCommentSortType::class)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeCommentSortType::class)
.onEach { evt ->
if (evt.screenKey == "settings") {
changeDefaultCommentSortType(evt.value)
}
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeUrlOpeningMode::class)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeUrlOpeningMode::class)
.onEach { evt ->
changeUrlOpeningMode(evt.value.toUrlOpeningMode())
}.launchIn(this)
@ -124,8 +129,6 @@ class SettingsViewModel(
override fun reduce(intent: SettingsMviModel.Intent) {
when (intent) {
is SettingsMviModel.Intent.ChangeUiTheme -> changeTheme(intent.value)
is SettingsMviModel.Intent.ChangeLanguage -> changeLanguage(intent.value)
is SettingsMviModel.Intent.ChangeBlurNsfw -> changeBlurNsfw(intent.value)
is SettingsMviModel.Intent.ChangeIncludeNsfw -> changeIncludeNsfw(intent.value)
is SettingsMviModel.Intent.ChangeEnableSwipeActions -> changeEnableSwipeActions(intent.value)
@ -133,17 +136,6 @@ class SettingsViewModel(
}
}
private fun changeTheme(value: UiTheme?) {
themeRepository.changeUiTheme(value)
screenModelScope.launch {
val settings =
settingsRepository.currentSettings.value.copy(
theme = value?.toInt(),
)
saveSettings(settings)
}
}
private fun changeLanguage(value: String) {
l10nManager.changeLanguage(value)
screenModelScope.launch {

View File

@ -1,29 +0,0 @@
package com.github.diegoberaldin.raccoonforlemmy.feature.settings.ui
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Settings
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabOptions
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.LocalStrings
import com.github.diegoberaldin.raccoonforlemmy.feature.settings.main.SettingsScreen
object SettingsTab : Tab {
override val options: TabOptions
@Composable get() {
val icon = rememberVectorPainter(Icons.Default.Settings)
val title = LocalStrings.current.navigationSettings
return TabOptions(
index = 4u,
title = title,
icon = icon,
)
}
@Composable
override fun Content() {
Navigator(SettingsScreen())
}
}

View File

@ -47,7 +47,7 @@ import com.github.diegoberaldin.raccoonforlemmy.feature.home.ui.HomeTab
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.ui.InboxTab
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.ui.ProfileTab
import com.github.diegoberaldin.raccoonforlemmy.feature.search.ui.ExploreTab
import com.github.diegoberaldin.raccoonforlemmy.feature.settings.ui.SettingsTab
import com.github.diegoberaldin.raccoonforlemmy.feature.settings.main.SettingsScreen
import com.github.diegoberaldin.raccoonforlemmy.ui.navigation.TabNavigationItem
import com.github.diegoberaldin.raccoonforlemmy.unit.manageaccounts.ManageAccountsScreen
import kotlinx.coroutines.delay
@ -179,6 +179,11 @@ internal object MainScreen : Screen {
}
}
DrawerEvent.OpenSettings -> {
val screen = SettingsScreen()
navigationCoordinator.pushScreen(screen)
}
else -> Unit
}
}.launchIn(this)
@ -260,18 +265,6 @@ internal object MainScreen : Screen {
}
},
)
TabNavigationItem(
tab = ProfileTab,
withText = titleVisible,
customIconUrl = uiState.customProfileUrl,
onLongPress =
rememberCallback {
if (uiState.isLogged) {
val screen = ManageAccountsScreen()
navigationCoordinator.showBottomSheet(screen)
}
},
)
TabNavigationItem(
tab = InboxTab,
withText = titleVisible,
@ -283,8 +276,16 @@ internal object MainScreen : Screen {
},
)
TabNavigationItem(
tab = SettingsTab,
tab = ProfileTab,
withText = titleVisible,
customIconUrl = uiState.customProfileUrl,
onLongPress =
rememberCallback {
if (uiState.isLogged) {
val screen = ManageAccountsScreen()
navigationCoordinator.showBottomSheet(screen)
}
},
)
}
}

View File

@ -35,7 +35,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigation
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.ui.InboxTab
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.ui.ProfileTab
import com.github.diegoberaldin.raccoonforlemmy.feature.search.ui.ExploreTab
import com.github.diegoberaldin.raccoonforlemmy.feature.settings.ui.SettingsTab
@Composable
internal fun RowScope.TabNavigationItem(
@ -63,7 +62,6 @@ internal fun RowScope.TabNavigationItem(
ExploreTab -> TabNavigationSection.Explore
ProfileTab -> TabNavigationSection.Profile
InboxTab -> TabNavigationSection.Inbox
SettingsTab -> TabNavigationSection.Settings
else -> TabNavigationSection.Home
}
navigationCoordinator.setCurrentSection(section)

View File

@ -8,6 +8,8 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
@ -203,6 +205,23 @@ object ModalDrawerContent : Tab {
)
}
}
item {
DrawerShortcut(
title = LocalStrings.current.navigationSettings,
icon = Icons.Default.Settings,
onSelected =
rememberCallback(coordinator) {
scope.launch {
focusManager.clearFocus()
navigationCoordinator.popUntilRoot()
coordinator.toggleDrawer()
delay(50)
coordinator.sendEvent(DrawerEvent.OpenSettings)
}
},
)
}
}
items(

View File

@ -72,7 +72,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.OptionId
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.di.getFabNestedScrollConnection
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.LocalStrings
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallbackArgs
@ -93,8 +92,6 @@ class ManageSubscriptionsScreen : Screen {
val topAppBarState = rememberTopAppBarState()
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)
val lazyListState = rememberLazyListState()
val settingsRepository = remember { getSettingsRepository() }
val settings by settingsRepository.currentSettings.collectAsState()
val scope = rememberCoroutineScope()
val fabNestedScrollConnection = remember { getFabNestedScrollConnection() }
val isFabVisible by fabNestedScrollConnection.isFabVisible.collectAsState()

View File

@ -112,7 +112,7 @@ class ZoomableImageViewModel(
)
}
// if done too early no image is found
delay(250)
delay(750)
updateState { it.copy(loading = false) }
if (path != null) {