mirror of
https://github.com/LiveFastEatTrashRaccoon/RaccoonForLemmy.git
synced 2025-02-01 22:26:56 +01:00
feat: configurable bottom navigation • part 3 (#1117)
This commit is contained in:
parent
29ecfe8e1c
commit
3f99e68764
@ -0,0 +1,84 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHeader
|
||||
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.getNavigationCoordinator
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toInt
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toReadableName
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
|
||||
|
||||
class SelectTabNavigationSectionBottomSheet(
|
||||
private val values: List<TabNavigationSection>,
|
||||
) : Screen {
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val navigationCoordinator = remember { getNavigationCoordinator() }
|
||||
val notificationCenter = remember { getNotificationCenter() }
|
||||
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||
.padding(
|
||||
top = Spacing.s,
|
||||
start = Spacing.s,
|
||||
end = Spacing.s,
|
||||
bottom = Spacing.m,
|
||||
),
|
||||
verticalArrangement = Arrangement.spacedBy(Spacing.s),
|
||||
) {
|
||||
BottomSheetHeader(LocalStrings.current.selectTabNavigationTitle)
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.spacedBy(Spacing.xxs),
|
||||
) {
|
||||
for (value in values) {
|
||||
Row(
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(
|
||||
horizontal = Spacing.s,
|
||||
vertical = Spacing.s,
|
||||
).fillMaxWidth()
|
||||
.onClick(
|
||||
onClick = {
|
||||
notificationCenter.send(
|
||||
NotificationCenterEvent.TabNavigationSectionSelected(value.toInt()),
|
||||
)
|
||||
navigationCoordinator.hideBottomSheet()
|
||||
},
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = value.toReadableName(),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -429,4 +429,6 @@ internal open class DefaultStrings : Strings {
|
||||
override val settingsSubtitleOpenPostWebPageOnImageClick =
|
||||
"If a post has an URL, open web page on image click"
|
||||
override val settingsItemAlternateMarkdownRendering = "Enable alternate Markdown rendering"
|
||||
override val settingsItemConfigureBottomNavigationBar = "Configure navigation bar"
|
||||
override val selectTabNavigationTitle = "Select a section"
|
||||
}
|
||||
|
@ -427,6 +427,8 @@ interface Strings {
|
||||
val settingsItemOpenPostWebPageOnImageClick: String
|
||||
val settingsSubtitleOpenPostWebPageOnImageClick: String
|
||||
val settingsItemAlternateMarkdownRendering: String
|
||||
val settingsItemConfigureBottomNavigationBar: String
|
||||
val selectTabNavigationTitle: String
|
||||
}
|
||||
|
||||
object Locales {
|
||||
|
@ -42,6 +42,7 @@ kotlin {
|
||||
implementation(libs.voyager.screenmodel)
|
||||
implementation(libs.voyager.koin)
|
||||
|
||||
implementation(projects.core.l10n)
|
||||
implementation(projects.core.persistence)
|
||||
implementation(projects.core.preferences)
|
||||
implementation(projects.domain.lemmy.data)
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.navigation.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.BottomNavItemsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.DrawerCoordinator
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.NavigationCoordinator
|
||||
import org.koin.java.KoinJavaComponent.inject
|
||||
@ -13,3 +14,8 @@ actual fun getDrawerCoordinator(): DrawerCoordinator {
|
||||
val res: DrawerCoordinator by inject(DrawerCoordinator::class.java)
|
||||
return res
|
||||
}
|
||||
|
||||
actual fun getBottomNavItemsRepository(): BottomNavItemsRepository {
|
||||
val res: BottomNavItemsRepository by inject(BottomNavItemsRepository::class.java)
|
||||
return res
|
||||
}
|
||||
|
@ -79,8 +79,18 @@ class DefaultBottomNavItemsRepositoryTest {
|
||||
runTest {
|
||||
val otherAccountId = 1L
|
||||
val accountId = 2L
|
||||
every { keyStore.get("BottomNavItemsRepository.$otherAccountId.items", any<List<String>>()) } returns ITEMS_IDS
|
||||
every { keyStore.get("BottomNavItemsRepository.$accountId.items", any<List<String>>()) } returns emptyList()
|
||||
every {
|
||||
keyStore.get(
|
||||
"BottomNavItemsRepository.$otherAccountId.items",
|
||||
any<List<String>>(),
|
||||
)
|
||||
} returns ITEMS_IDS
|
||||
every {
|
||||
keyStore.get(
|
||||
"BottomNavItemsRepository.$accountId.items",
|
||||
any<List<String>>(),
|
||||
)
|
||||
} returns emptyList()
|
||||
|
||||
val res = sut.get(accountId)
|
||||
|
||||
@ -94,8 +104,18 @@ class DefaultBottomNavItemsRepositoryTest {
|
||||
fun givenDataForOtherUser_whenGetForAnonymousAccount_thenResultAndInteractionsIsAsExpected() =
|
||||
runTest {
|
||||
val otherAccountId = 1
|
||||
every { keyStore.get("BottomNavItemsRepository.$otherAccountId.items", any<List<String>>()) } returns ITEMS_IDS
|
||||
every { keyStore.get("BottomNavItemsRepository.items", any<List<String>>()) } returns emptyList()
|
||||
every {
|
||||
keyStore.get(
|
||||
"BottomNavItemsRepository.$otherAccountId.items",
|
||||
any<List<String>>(),
|
||||
)
|
||||
} returns ITEMS_IDS
|
||||
every {
|
||||
keyStore.get(
|
||||
"BottomNavItemsRepository.items",
|
||||
any<List<String>>(),
|
||||
)
|
||||
} returns emptyList()
|
||||
|
||||
val res = sut.get(null)
|
||||
|
||||
@ -105,6 +125,28 @@ class DefaultBottomNavItemsRepositoryTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenUpdateAnonymousUser_thenInteractionsAreAsExpected() =
|
||||
runTest {
|
||||
sut.update(accountId = null, items = ITEMS)
|
||||
|
||||
coVerify {
|
||||
keyStore.save("BottomNavItemsRepository.items", ITEMS_IDS)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenUpdateLoggedUser_thenInteractionsAreAsExpected() =
|
||||
runTest {
|
||||
val accountId = 1L
|
||||
|
||||
sut.update(accountId = accountId, items = ITEMS)
|
||||
|
||||
coVerify {
|
||||
keyStore.save("BottomNavItemsRepository.1.items", ITEMS_IDS)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val ITEMS_IDS = listOf("0", "1", "3", "2", "4")
|
||||
private val ITEMS =
|
||||
|
@ -11,7 +11,7 @@ internal class DefaultBottomNavItemsRepository(
|
||||
override suspend fun get(accountId: Long?): List<TabNavigationSection> =
|
||||
withContext(Dispatchers.IO) {
|
||||
val key = getKey(accountId)
|
||||
val itemIds = keyStore.get(key, emptyList())
|
||||
val itemIds = keyStore.get(key, emptyList()).mapNotNull { it.toIntOrNull() }
|
||||
val res = itemIds.mapNotNull { it.toTabNavigationSection() }.takeUnless { it.isEmpty() }
|
||||
res ?: BottomNavItemsRepository.DEFAULT_ITEMS
|
||||
}
|
||||
@ -21,7 +21,7 @@ internal class DefaultBottomNavItemsRepository(
|
||||
items: List<TabNavigationSection>,
|
||||
) = withContext(Dispatchers.IO) {
|
||||
val key = getKey(accountId)
|
||||
val itemIds = items.map { it.toTabNavigationId() }
|
||||
val itemIds = items.map { it.toInt().toString() }
|
||||
keyStore.save(key, itemIds)
|
||||
}
|
||||
|
||||
@ -35,24 +35,3 @@ internal class DefaultBottomNavItemsRepository(
|
||||
append(".items")
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.toTabNavigationSection(): TabNavigationSection? =
|
||||
when (this) {
|
||||
"0" -> TabNavigationSection.Home
|
||||
"1" -> TabNavigationSection.Explore
|
||||
"2" -> TabNavigationSection.Inbox
|
||||
"3" -> TabNavigationSection.Profile
|
||||
"4" -> TabNavigationSection.Settings
|
||||
"5" -> TabNavigationSection.Bookmarks
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun TabNavigationSection.toTabNavigationId(): String =
|
||||
when (this) {
|
||||
TabNavigationSection.Home -> "0"
|
||||
TabNavigationSection.Explore -> "1"
|
||||
TabNavigationSection.Inbox -> "2"
|
||||
TabNavigationSection.Profile -> "3"
|
||||
TabNavigationSection.Settings -> "4"
|
||||
TabNavigationSection.Bookmarks -> "5"
|
||||
}
|
||||
|
@ -11,20 +11,6 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlin.time.Duration
|
||||
|
||||
sealed interface TabNavigationSection {
|
||||
data object Home : TabNavigationSection
|
||||
|
||||
data object Explore : TabNavigationSection
|
||||
|
||||
data object Profile : TabNavigationSection
|
||||
|
||||
data object Inbox : TabNavigationSection
|
||||
|
||||
data object Settings : TabNavigationSection
|
||||
|
||||
data object Bookmarks : TabNavigationSection
|
||||
}
|
||||
|
||||
sealed interface ComposeEvent {
|
||||
data class WithUrl(
|
||||
val url: String,
|
||||
|
@ -0,0 +1,54 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.navigation
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.LocalStrings
|
||||
|
||||
sealed interface TabNavigationSection {
|
||||
data object Home : TabNavigationSection
|
||||
|
||||
data object Explore : TabNavigationSection
|
||||
|
||||
data object Profile : TabNavigationSection
|
||||
|
||||
data object Inbox : TabNavigationSection
|
||||
|
||||
data object Settings : TabNavigationSection
|
||||
|
||||
data object Bookmarks : TabNavigationSection
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TabNavigationSection.toReadableName(): String =
|
||||
when (this) {
|
||||
TabNavigationSection.Bookmarks -> LocalStrings.current.navigationDrawerTitleBookmarks
|
||||
TabNavigationSection.Explore -> LocalStrings.current.navigationSearch
|
||||
TabNavigationSection.Home -> LocalStrings.current.navigationHome
|
||||
TabNavigationSection.Inbox -> LocalStrings.current.navigationInbox
|
||||
TabNavigationSection.Profile -> LocalStrings.current.navigationProfile
|
||||
TabNavigationSection.Settings -> LocalStrings.current.navigationSettings
|
||||
}
|
||||
|
||||
fun Int.toTabNavigationSection(): TabNavigationSection? =
|
||||
when (this) {
|
||||
0 -> TabNavigationSection.Home
|
||||
1 -> TabNavigationSection.Explore
|
||||
2 -> TabNavigationSection.Inbox
|
||||
3 -> TabNavigationSection.Profile
|
||||
4 -> TabNavigationSection.Settings
|
||||
5 -> TabNavigationSection.Bookmarks
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun TabNavigationSection.toInt(): Int =
|
||||
when (this) {
|
||||
TabNavigationSection.Home -> 0
|
||||
TabNavigationSection.Explore -> 1
|
||||
TabNavigationSection.Inbox -> 2
|
||||
TabNavigationSection.Profile -> 3
|
||||
TabNavigationSection.Settings -> 4
|
||||
TabNavigationSection.Bookmarks -> 5
|
||||
}
|
||||
|
||||
fun List<Int>.toTabNavigationSections(): List<TabNavigationSection> = mapNotNull { it.toTabNavigationSection() }
|
||||
|
||||
fun List<TabNavigationSection>.toInts(): List<Int> = map { it.toInt() }
|
@ -1,8 +1,11 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.navigation.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.BottomNavItemsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.DrawerCoordinator
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.NavigationCoordinator
|
||||
|
||||
expect fun getNavigationCoordinator(): NavigationCoordinator
|
||||
|
||||
expect fun getDrawerCoordinator(): DrawerCoordinator
|
||||
|
||||
expect fun getBottomNavItemsRepository(): BottomNavItemsRepository
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.core.navigation.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.BottomNavItemsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.DrawerCoordinator
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.NavigationCoordinator
|
||||
import org.koin.core.component.KoinComponent
|
||||
@ -9,7 +10,10 @@ actual fun getNavigationCoordinator() = CoreNavigationHelper.navigationCoordinat
|
||||
|
||||
actual fun getDrawerCoordinator() = CoreNavigationHelper.drawerCoordinator
|
||||
|
||||
actual fun getBottomNavItemsRepository() = CoreNavigationHelper.bottomNavItemsRepository
|
||||
|
||||
object CoreNavigationHelper : KoinComponent {
|
||||
val navigationCoordinator: NavigationCoordinator by inject()
|
||||
val drawerCoordinator: DrawerCoordinator by inject()
|
||||
val bottomNavItemsRepository: BottomNavItemsRepository by inject()
|
||||
}
|
||||
|
@ -245,4 +245,8 @@ sealed interface NotificationCenterEvent {
|
||||
data object FavoritesUpdated : NotificationCenterEvent
|
||||
|
||||
data object OpenSearchInExplore : NotificationCenterEvent
|
||||
|
||||
data class TabNavigationSectionSelected(
|
||||
val sectionId: Int,
|
||||
) : NotificationCenterEvent
|
||||
}
|
||||
|
@ -90,6 +90,15 @@ class DefaultSettingsRepositoryTest {
|
||||
assertEquals(model, value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenChangeCurrentBottomBarSections_thenValueIsUpdated() =
|
||||
runTest {
|
||||
val sectionIds = listOf(0, 1, 2)
|
||||
sut.changeCurrentBottomBarSections(sectionIds)
|
||||
val value = sut.currentBottomBarSections.value
|
||||
assertEquals(sectionIds, value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenCreateSettings_thenResultIsAsExpected() =
|
||||
runTest {
|
||||
|
@ -13,6 +13,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.preferences.TemporaryKeySto
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
@ -77,6 +78,7 @@ internal class DefaultSettingsRepository(
|
||||
private val db = provider.getDatabase()
|
||||
|
||||
override val currentSettings = MutableStateFlow(SettingsModel())
|
||||
override val currentBottomBarSections = MutableStateFlow<List<Int>>(emptyList())
|
||||
|
||||
override suspend fun createSettings(
|
||||
settings: SettingsModel,
|
||||
@ -375,7 +377,10 @@ internal class DefaultSettingsRepository(
|
||||
settings.defaultExploreResultType,
|
||||
)
|
||||
keyStore.save(KeyStoreKeys.RANDOM_THEME_COLOR, settings.randomThemeColor)
|
||||
keyStore.save(KeyStoreKeys.OPEN_POST_WEB_PAGE_ON_IMAGE_CLICK, settings.openPostWebPageOnImageClick)
|
||||
keyStore.save(
|
||||
KeyStoreKeys.OPEN_POST_WEB_PAGE_ON_IMAGE_CLICK,
|
||||
settings.openPostWebPageOnImageClick,
|
||||
)
|
||||
} else {
|
||||
db.settingsQueries.update(
|
||||
theme = settings.theme?.toLong(),
|
||||
@ -466,7 +471,11 @@ internal class DefaultSettingsRepository(
|
||||
}
|
||||
|
||||
override fun changeCurrentSettings(settings: SettingsModel) {
|
||||
currentSettings.value = settings
|
||||
currentSettings.update { settings }
|
||||
}
|
||||
|
||||
override fun changeCurrentBottomBarSections(sectionIds: List<Int>) {
|
||||
currentBottomBarSections.update { sectionIds }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
@Stable
|
||||
interface SettingsRepository {
|
||||
val currentSettings: StateFlow<SettingsModel>
|
||||
val currentBottomBarSections: StateFlow<List<Int>>
|
||||
|
||||
suspend fun createSettings(
|
||||
settings: SettingsModel,
|
||||
@ -21,4 +22,6 @@ interface SettingsRepository {
|
||||
)
|
||||
|
||||
fun changeCurrentSettings(settings: SettingsModel)
|
||||
|
||||
fun changeCurrentBottomBarSections(sectionIds: List<Int>)
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"alternateMarkdownRenderingSettingsItemEnabled": true
|
||||
"alternateMarkdownRenderingSettingsItemEnabled": false
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ kotlin {
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.core.appearance)
|
||||
implementation(projects.core.persistence)
|
||||
implementation(projects.core.navigation)
|
||||
implementation(projects.core.notifications)
|
||||
implementation(projects.domain.lemmy.repository)
|
||||
implementation(projects.domain.lemmy.data)
|
||||
@ -58,8 +59,14 @@ kotlin {
|
||||
|
||||
android {
|
||||
namespace = "com.github.diegoberaldin.raccoonforlemmy.domain.identity"
|
||||
compileSdk = libs.versions.android.targetSdk.get().toInt()
|
||||
compileSdk =
|
||||
libs.versions.android.targetSdk
|
||||
.get()
|
||||
.toInt()
|
||||
defaultConfig {
|
||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
||||
minSdk =
|
||||
libs.versions.android.minSdk
|
||||
.get()
|
||||
.toInt()
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.dto.LoginResponse
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.BottomNavItemsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.AccountModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.SettingsModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.AccountRepository
|
||||
@ -40,6 +41,10 @@ class DefaultLoginUseCaseTest {
|
||||
private val communitySortRepository = mockk<CommunitySortRepository>(relaxUnitFun = true)
|
||||
private val communityPreferredLanguageRepository =
|
||||
mockk<CommunityPreferredLanguageRepository>(relaxUnitFun = true)
|
||||
private val bottomNavItemsRepository =
|
||||
mockk<BottomNavItemsRepository>(relaxUnitFun = true) {
|
||||
coEvery { get(accountId = any()) } returns BottomNavItemsRepository.DEFAULT_ITEMS
|
||||
}
|
||||
private val lemmyValueCache = mockk<LemmyValueCache>(relaxUnitFun = true)
|
||||
private val sut =
|
||||
DefaultLoginUseCase(
|
||||
@ -51,6 +56,7 @@ class DefaultLoginUseCaseTest {
|
||||
siteRepository = siteRepository,
|
||||
communitySortRepository = communitySortRepository,
|
||||
communityPreferredLanguageRepository = communityPreferredLanguageRepository,
|
||||
bottomNavItemsRepository = bottomNavItemsRepository,
|
||||
lemmyValueCache = lemmyValueCache,
|
||||
)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.BottomNavItemsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.AccountModel
|
||||
@ -27,6 +28,10 @@ class DefaultLogoutUseCaseTest {
|
||||
private val notificationCenter = mockk<NotificationCenter>(relaxUnitFun = true)
|
||||
private val communitySortRepository = mockk<CommunitySortRepository>(relaxUnitFun = true)
|
||||
private val lemmyValueCache = mockk<LemmyValueCache>(relaxUnitFun = true)
|
||||
private val bottomNavItemsRepository =
|
||||
mockk<BottomNavItemsRepository>(relaxUnitFun = true) {
|
||||
coEvery { get(accountId = any()) } returns BottomNavItemsRepository.DEFAULT_ITEMS
|
||||
}
|
||||
private val sut =
|
||||
DefaultLogoutUseCase(
|
||||
identityRepository = identityRepository,
|
||||
@ -34,6 +39,7 @@ class DefaultLogoutUseCaseTest {
|
||||
settingsRepository = settingsRepository,
|
||||
notificationCenter = notificationCenter,
|
||||
communitySortRepository = communitySortRepository,
|
||||
bottomNavItemsRepository = bottomNavItemsRepository,
|
||||
lemmyValueCache = lemmyValueCache,
|
||||
)
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.provider.ServiceProvider
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.BottomNavItemsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.AccountModel
|
||||
@ -32,6 +33,10 @@ class DefaultSwitchAccountUseCaseTest {
|
||||
private val communityPreferredLanguageRepository =
|
||||
mockk<CommunityPreferredLanguageRepository>(relaxUnitFun = true)
|
||||
private val lemmyValueCache = mockk<LemmyValueCache>(relaxUnitFun = true)
|
||||
private val bottomNavItemsRepository =
|
||||
mockk<BottomNavItemsRepository>(relaxUnitFun = true) {
|
||||
coEvery { get(accountId = any()) } returns BottomNavItemsRepository.DEFAULT_ITEMS
|
||||
}
|
||||
private val sut =
|
||||
DefaultSwitchAccountUseCase(
|
||||
identityRepository = identityRepository,
|
||||
@ -41,6 +46,7 @@ class DefaultSwitchAccountUseCaseTest {
|
||||
notificationCenter = notificationCenter,
|
||||
communitySortRepository = communitySortRepository,
|
||||
communityPreferredLanguageRepository = communityPreferredLanguageRepository,
|
||||
bottomNavItemsRepository = bottomNavItemsRepository,
|
||||
lemmyValueCache = lemmyValueCache,
|
||||
)
|
||||
|
||||
|
@ -47,6 +47,7 @@ val coreIdentityModule =
|
||||
siteRepository = get(),
|
||||
communitySortRepository = get(),
|
||||
communityPreferredLanguageRepository = get(),
|
||||
bottomNavItemsRepository = get(),
|
||||
lemmyValueCache = get(),
|
||||
)
|
||||
}
|
||||
@ -57,6 +58,7 @@ val coreIdentityModule =
|
||||
notificationCenter = get(),
|
||||
settingsRepository = get(),
|
||||
communitySortRepository = get(),
|
||||
bottomNavItemsRepository = get(),
|
||||
lemmyValueCache = get(),
|
||||
)
|
||||
}
|
||||
@ -69,6 +71,7 @@ val coreIdentityModule =
|
||||
notificationCenter = get(),
|
||||
communitySortRepository = get(),
|
||||
communityPreferredLanguageRepository = get(),
|
||||
bottomNavItemsRepository = get(),
|
||||
lemmyValueCache = get(),
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.VoteFormat
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.BottomNavItemsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toInts
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.AccountModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.AccountRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.CommunityPreferredLanguageRepository
|
||||
@ -21,6 +23,7 @@ internal class DefaultLoginUseCase(
|
||||
private val siteRepository: SiteRepository,
|
||||
private val communitySortRepository: CommunitySortRepository,
|
||||
private val communityPreferredLanguageRepository: CommunityPreferredLanguageRepository,
|
||||
private val bottomNavItemsRepository: BottomNavItemsRepository,
|
||||
private val lemmyValueCache: LemmyValueCache,
|
||||
) : LoginUseCase {
|
||||
override suspend operator fun invoke(
|
||||
@ -106,6 +109,9 @@ internal class DefaultLoginUseCase(
|
||||
|
||||
val newSettings = settingsRepository.getSettings(accountId)
|
||||
settingsRepository.changeCurrentSettings(newSettings)
|
||||
|
||||
val bottomBarSections = bottomNavItemsRepository.get(accountId)
|
||||
settingsRepository.changeCurrentBottomBarSections(bottomBarSections.toInts())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.BottomNavItemsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toInts
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.AccountRepository
|
||||
@ -14,6 +16,7 @@ internal class DefaultLogoutUseCase(
|
||||
private val notificationCenter: NotificationCenter,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val communitySortRepository: CommunitySortRepository,
|
||||
private val bottomNavItemsRepository: BottomNavItemsRepository,
|
||||
private val lemmyValueCache: LemmyValueCache,
|
||||
) : LogoutUseCase {
|
||||
override suspend operator fun invoke() {
|
||||
@ -31,5 +34,8 @@ internal class DefaultLogoutUseCase(
|
||||
}
|
||||
val anonSettings = settingsRepository.getSettings(null)
|
||||
settingsRepository.changeCurrentSettings(anonSettings)
|
||||
|
||||
val bottomBarSections = bottomNavItemsRepository.get(null)
|
||||
settingsRepository.changeCurrentBottomBarSections(bottomBarSections.toInts())
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.api.provider.ServiceProvider
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.BottomNavItemsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toInts
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.AccountModel
|
||||
@ -19,6 +21,7 @@ internal class DefaultSwitchAccountUseCase(
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val communitySortRepository: CommunitySortRepository,
|
||||
private val communityPreferredLanguageRepository: CommunityPreferredLanguageRepository,
|
||||
private val bottomNavItemsRepository: BottomNavItemsRepository,
|
||||
private val lemmyValueCache: LemmyValueCache,
|
||||
) : SwitchAccountUseCase {
|
||||
override suspend fun invoke(account: AccountModel) {
|
||||
@ -44,5 +47,8 @@ internal class DefaultSwitchAccountUseCase(
|
||||
|
||||
val newSettings = settingsRepository.getSettings(accountId)
|
||||
settingsRepository.changeCurrentSettings(newSettings)
|
||||
|
||||
val bottomBarSections = bottomNavItemsRepository.get(accountId)
|
||||
settingsRepository.changeCurrentBottomBarSections(bottomBarSections.toInts())
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ 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.core.navigation.TabNavigationSection
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toInt
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.postlist.PostListScreen
|
||||
|
||||
object HomeTab : Tab {
|
||||
@ -18,7 +20,7 @@ object HomeTab : Tab {
|
||||
val title = LocalStrings.current.navigationHome
|
||||
|
||||
return TabOptions(
|
||||
index = 0u,
|
||||
index = TabNavigationSection.Home.toInt().toUShort(),
|
||||
title = title,
|
||||
icon = icon,
|
||||
)
|
||||
|
@ -8,6 +8,8 @@ import cafe.adriel.voyager.navigator.tab.Tab
|
||||
import cafe.adriel.voyager.navigator.tab.TabNavigator
|
||||
import cafe.adriel.voyager.navigator.tab.TabOptions
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.LocalStrings
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.TabNavigationSection
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toInt
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.inbox.main.InboxScreen
|
||||
|
||||
object InboxTab : Tab {
|
||||
@ -17,7 +19,7 @@ object InboxTab : Tab {
|
||||
val icon = rememberVectorPainter(Icons.Default.Inbox)
|
||||
val title = LocalStrings.current.navigationInbox
|
||||
return TabOptions(
|
||||
index = 3u,
|
||||
index = TabNavigationSection.Inbox.toInt().toUShort(),
|
||||
title = title,
|
||||
icon = icon,
|
||||
)
|
||||
|
@ -31,6 +31,7 @@ val profileTabModule =
|
||||
}
|
||||
factory<ProfileSideMenuMviModel> {
|
||||
ProfileSideMenuViewModel(
|
||||
settingsRepository = get(),
|
||||
lemmyValueCache = get(),
|
||||
)
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ internal fun ProfileMenuContent(
|
||||
modifier: Modifier = Modifier,
|
||||
isModerator: Boolean = false,
|
||||
canCreateCommunity: Boolean = false,
|
||||
isBookmarksVisible: Boolean = true,
|
||||
) {
|
||||
val notificationCenter = remember { getNotificationCenter() }
|
||||
|
||||
@ -42,14 +43,16 @@ internal fun ProfileMenuContent(
|
||||
notificationCenter.send(NotificationCenterEvent.ProfileSideMenuAction.ManageSubscriptions)
|
||||
},
|
||||
)
|
||||
SettingsRow(
|
||||
title = LocalStrings.current.navigationDrawerTitleBookmarks,
|
||||
icon = Icons.Default.Bookmark,
|
||||
onTap =
|
||||
rememberCallback {
|
||||
notificationCenter.send(NotificationCenterEvent.ProfileSideMenuAction.Bookmarks)
|
||||
},
|
||||
)
|
||||
if (isBookmarksVisible) {
|
||||
SettingsRow(
|
||||
title = LocalStrings.current.navigationDrawerTitleBookmarks,
|
||||
icon = Icons.Default.Bookmark,
|
||||
onTap =
|
||||
rememberCallback {
|
||||
notificationCenter.send(NotificationCenterEvent.ProfileSideMenuAction.Bookmarks)
|
||||
},
|
||||
)
|
||||
}
|
||||
SettingsRow(
|
||||
title = LocalStrings.current.navigationDrawerTitleDrafts,
|
||||
icon = Icons.Default.Drafts,
|
||||
|
@ -11,6 +11,7 @@ interface ProfileSideMenuMviModel :
|
||||
data class State(
|
||||
val isModerator: Boolean = false,
|
||||
val canCreateCommunity: Boolean = false,
|
||||
val isBookmarksVisible: Boolean = true,
|
||||
)
|
||||
|
||||
sealed interface Effect
|
||||
|
@ -70,6 +70,7 @@ class ProfileSideMenuScreen : Screen {
|
||||
),
|
||||
isModerator = uiState.isModerator,
|
||||
canCreateCommunity = uiState.canCreateCommunity,
|
||||
isBookmarksVisible = uiState.isBookmarksVisible,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,9 @@ package com.github.diegoberaldin.raccoonforlemmy.feature.profile.menu
|
||||
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.TabNavigationSection
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toTabNavigationSections
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.SettingsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.LemmyValueCache
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@ -9,6 +12,7 @@ import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ProfileSideMenuViewModel(
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val lemmyValueCache: LemmyValueCache,
|
||||
) : DefaultMviModel<ProfileSideMenuMviModel.Intent, ProfileSideMenuMviModel.State, ProfileSideMenuMviModel.Effect>(
|
||||
ProfileSideMenuMviModel.State(),
|
||||
@ -39,6 +43,16 @@ class ProfileSideMenuViewModel(
|
||||
)
|
||||
}
|
||||
}.launchIn(this)
|
||||
settingsRepository.currentBottomBarSections
|
||||
.onEach { sectionIds ->
|
||||
val isBookmarksInBottomBar =
|
||||
sectionIds
|
||||
.toTabNavigationSections()
|
||||
.contains(TabNavigationSection.Bookmarks)
|
||||
updateState {
|
||||
it.copy(isBookmarksVisible = !isBookmarksInBottomBar)
|
||||
}
|
||||
}.launchIn(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import cafe.adriel.voyager.navigator.tab.Tab
|
||||
import cafe.adriel.voyager.navigator.tab.TabNavigator
|
||||
import cafe.adriel.voyager.navigator.tab.TabOptions
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.LocalStrings
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.TabNavigationSection
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toInt
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.profile.main.ProfileMainScreen
|
||||
|
||||
object ProfileTab : Tab {
|
||||
@ -16,7 +18,7 @@ object ProfileTab : Tab {
|
||||
val icon = rememberVectorPainter(Icons.Default.AccountCircle)
|
||||
val title = LocalStrings.current.navigationProfile
|
||||
return TabOptions(
|
||||
index = 2u,
|
||||
index = TabNavigationSection.Profile.toInt().toUShort(),
|
||||
title = title,
|
||||
icon = icon,
|
||||
)
|
||||
|
@ -8,6 +8,8 @@ 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.core.navigation.TabNavigationSection
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toInt
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.explore.ExploreScreen
|
||||
|
||||
object ExploreTab : Tab {
|
||||
@ -16,7 +18,7 @@ object ExploreTab : Tab {
|
||||
val icon = rememberVectorPainter(Icons.Default.Explore)
|
||||
val title = LocalStrings.current.navigationSearch
|
||||
return TabOptions(
|
||||
index = 1u,
|
||||
index = TabNavigationSection.Explore.toInt().toUShort(),
|
||||
title = title,
|
||||
icon = icon,
|
||||
)
|
||||
|
@ -67,6 +67,7 @@ kotlin {
|
||||
implementation(projects.unit.choosecolor)
|
||||
implementation(projects.unit.choosefont)
|
||||
implementation(projects.unit.configureswipeactions)
|
||||
implementation(projects.unit.configurenavbar)
|
||||
implementation(projects.unit.configurecontentview)
|
||||
implementation(projects.unit.filteredcontents)
|
||||
implementation(projects.unit.medialist)
|
||||
@ -82,8 +83,14 @@ kotlin {
|
||||
|
||||
android {
|
||||
namespace = "com.github.diegoberaldin.raccoonforlemmy.feature.settings"
|
||||
compileSdk = libs.versions.android.targetSdk.get().toInt()
|
||||
compileSdk =
|
||||
libs.versions.android.targetSdk
|
||||
.get()
|
||||
.toInt()
|
||||
defaultConfig {
|
||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
||||
minSdk =
|
||||
libs.versions.android.minSdk
|
||||
.get()
|
||||
.toInt()
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ 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.core.navigation.TabNavigationSection
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toInt
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.settings.main.SettingsScreen
|
||||
|
||||
object SettingsTab : Tab {
|
||||
@ -18,7 +20,7 @@ object SettingsTab : Tab {
|
||||
val title = LocalStrings.current.navigationSettings
|
||||
|
||||
return TabOptions(
|
||||
index = 4u,
|
||||
index = TabNavigationSection.Settings.toInt().toUShort(),
|
||||
title = title,
|
||||
icon = icon,
|
||||
)
|
||||
|
@ -69,6 +69,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.utils.datetime.getPrettyDur
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.fs.getFileSystemManager
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.toLocalDp
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toReadableName
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.configurenavbar.ConfigureNavBarScreen
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
@ -159,6 +160,7 @@ class AdvancedSettingsScreen : Screen {
|
||||
Modifier
|
||||
.padding(
|
||||
top = padding.calculateTopPadding(),
|
||||
bottom = padding.calculateBottomPadding(),
|
||||
).nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
) {
|
||||
Column(
|
||||
@ -495,6 +497,14 @@ class AdvancedSettingsScreen : Screen {
|
||||
title = LocalStrings.current.settingsTitleExperimental,
|
||||
icon = Icons.Default.Science,
|
||||
)
|
||||
SettingsRow(
|
||||
title = LocalStrings.current.settingsItemConfigureBottomNavigationBar,
|
||||
disclosureIndicator = true,
|
||||
onTap =
|
||||
rememberCallback {
|
||||
navigationCoordinator.pushScreen(ConfigureNavBarScreen())
|
||||
},
|
||||
)
|
||||
if (uiState.alternateMarkdownRenderingItemVisible) {
|
||||
// alternate Markdown rendering
|
||||
SettingsSwitchRow(
|
||||
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
@ -154,8 +155,8 @@ class SettingsScreen : Screen {
|
||||
Modifier
|
||||
.padding(
|
||||
top = padding.calculateTopPadding(),
|
||||
bottom = padding.calculateBottomPadding(),
|
||||
).nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
).navigationBarsPadding()
|
||||
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize().verticalScroll(scrollState),
|
||||
|
@ -61,6 +61,7 @@ include(":unit:choosefont")
|
||||
include(":unit:communitydetail")
|
||||
include(":unit:communityinfo")
|
||||
include(":unit:configurecontentview")
|
||||
include(":unit:configurenavbar")
|
||||
include(":unit:configureswipeactions")
|
||||
include(":unit:createcomment")
|
||||
include(":unit:createpost")
|
||||
|
@ -76,6 +76,7 @@ kotlin {
|
||||
implementation(projects.unit.communitydetail)
|
||||
implementation(projects.unit.communityinfo)
|
||||
implementation(projects.unit.configurecontentview)
|
||||
implementation(projects.unit.configurenavbar)
|
||||
implementation(projects.unit.configureswipeactions)
|
||||
implementation(projects.unit.createcomment)
|
||||
implementation(projects.unit.createpost)
|
||||
|
@ -35,6 +35,7 @@ import com.github.diegoberaldin.raccoonforlemmy.unit.chat.di.chatModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.communitydetail.di.communityDetailModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.communityinfo.di.communityInfoModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.configurecontentview.di.configureContentViewModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.configurenavbar.di.configureNavBarModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.configureswipeactions.di.configureSwipeActionsModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createcomment.di.createCommentModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createpost.di.createPostModule
|
||||
@ -119,5 +120,6 @@ val sharedHelperModule =
|
||||
moderateWithReasonModule,
|
||||
acknowledgementsModule,
|
||||
mediaListModule,
|
||||
configureNavBarModule,
|
||||
)
|
||||
}
|
||||
|
@ -57,8 +57,10 @@ import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.ProvideString
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.ComposeEvent
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.DrawerEvent
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.SideMenuEvents
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getBottomNavItemsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getDrawerCoordinator
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toInts
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getAccountRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.preferences.di.getAppConfigStore
|
||||
@ -108,9 +110,12 @@ fun App(onLoadingFinished: () -> Unit = {}) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val subscriptionsCache = remember { getSubscriptionsCache() }
|
||||
val appConfigStore = remember { getAppConfigStore() }
|
||||
val bottomNavItemsRepository = remember { getBottomNavItemsRepository() }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
val accountId = accountRepository.getActive()?.id
|
||||
val lastActiveAccount = accountRepository.getActive()
|
||||
val lastInstance = lastActiveAccount?.instance?.takeIf { it.isNotEmpty() }
|
||||
val accountId = lastActiveAccount?.id
|
||||
val currentSettings = settingsRepository.getSettings(accountId)
|
||||
val seedColor =
|
||||
if (currentSettings.randomThemeColor) {
|
||||
@ -122,8 +127,8 @@ fun App(onLoadingFinished: () -> Unit = {}) {
|
||||
currentSettings.customSeedColor
|
||||
}
|
||||
settingsRepository.changeCurrentSettings(currentSettings.copy(customSeedColor = seedColor))
|
||||
val lastActiveAccount = accountRepository.getActive()
|
||||
val lastInstance = lastActiveAccount?.instance?.takeIf { it.isNotEmpty() }
|
||||
val bottomBarSections = bottomNavItemsRepository.get(accountId)
|
||||
settingsRepository.changeCurrentBottomBarSections(bottomBarSections.toInts())
|
||||
if (lastInstance != null) {
|
||||
apiConfigurationRepository.changeInstance(lastInstance)
|
||||
}
|
||||
@ -132,6 +137,7 @@ fun App(onLoadingFinished: () -> Unit = {}) {
|
||||
appConfigStore.initialize()
|
||||
|
||||
hasBeenInitialized = true
|
||||
|
||||
launch {
|
||||
delay(50)
|
||||
onLoadingFinished()
|
||||
|
@ -43,10 +43,10 @@ import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getDrawerCoor
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallbackArgs
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.home.ui.HomeTab
|
||||
import com.github.diegoberaldin.raccoonforlemmy.feature.settings.main.SettingsScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.navigation.TabNavigationItem
|
||||
import com.github.diegoberaldin.raccoonforlemmy.navigation.toTab
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.manageaccounts.ManageAccountsScreen
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.drop
|
||||
@ -277,7 +277,8 @@ internal object MainScreen : Screen {
|
||||
),
|
||||
tonalElevation = 0.dp,
|
||||
) {
|
||||
for (section in uiState.bottomBarSections) {
|
||||
// it must be done so (indexed), otherwise section gets remembered in tap callbacks
|
||||
uiState.bottomBarSections.forEachIndexed { idx, section ->
|
||||
TabNavigationItem(
|
||||
section = section,
|
||||
withText = titleVisible,
|
||||
@ -287,15 +288,17 @@ internal object MainScreen : Screen {
|
||||
} else {
|
||||
null
|
||||
},
|
||||
onClick =
|
||||
rememberCallbackArgs { tab ->
|
||||
tabNavigator.current = tab
|
||||
navigationCoordinator.setCurrentSection(section)
|
||||
},
|
||||
onLongPress =
|
||||
rememberCallbackArgs { tab ->
|
||||
handleOnLongPress(tab, section)
|
||||
},
|
||||
onClick = {
|
||||
val section = uiState.bottomBarSections[idx]
|
||||
val tab = section.toTab()
|
||||
tabNavigator.current = tab
|
||||
navigationCoordinator.setCurrentSection(section)
|
||||
},
|
||||
onLongPress = {
|
||||
val section = uiState.bottomBarSections[idx]
|
||||
val tab = section.toTab()
|
||||
handleOnLongPress(tab, section)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy
|
||||
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.BottomNavItemsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.AccountRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toTabNavigationSections
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.SettingsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.inbox.InboxCoordinator
|
||||
@ -21,8 +20,6 @@ class MainViewModel(
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val settingRepository: SettingsRepository,
|
||||
private val userRepository: UserRepository,
|
||||
private val accountRepository: AccountRepository,
|
||||
private val bottomNavItemsRepository: BottomNavItemsRepository,
|
||||
private val notificationChecker: InboxNotificationChecker,
|
||||
private val lemmyValueCache: LemmyValueCache,
|
||||
) : DefaultMviModel<MainMviModel.Intent, MainMviModel.UiState, MainMviModel.Effect>(
|
||||
@ -53,17 +50,20 @@ class MainViewModel(
|
||||
notificationChecker.stop()
|
||||
}
|
||||
}.launchIn(this)
|
||||
|
||||
settingRepository.currentSettings
|
||||
.onEach {
|
||||
updateCustomProfileIcon()
|
||||
}.launchIn(this)
|
||||
settingRepository.currentBottomBarSections
|
||||
.onEach { sectionIds ->
|
||||
val sections = sectionIds.toTabNavigationSections()
|
||||
updateState { it.copy(bottomBarSections = sections) }
|
||||
}.launchIn(this)
|
||||
|
||||
identityRepository.isLogged
|
||||
.onEach { isLogged ->
|
||||
updateState { it.copy(isLogged = isLogged ?: false) }
|
||||
updateCustomProfileIcon()
|
||||
refreshBottomNavigationItems()
|
||||
}.launchIn(this)
|
||||
}
|
||||
}
|
||||
@ -106,12 +106,4 @@ class MainViewModel(
|
||||
emitEffect(MainMviModel.Effect.ReadAllInboxSuccess)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun refreshBottomNavigationItems() {
|
||||
val accountId = accountRepository.getActive()?.id
|
||||
val sections = bottomNavItemsRepository.get(accountId)
|
||||
updateState {
|
||||
it.copy(bottomBarSections = sections)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,6 @@ internal val internalSharedModule =
|
||||
identityRepository = get(),
|
||||
settingRepository = get(),
|
||||
userRepository = get(),
|
||||
accountRepository = get(),
|
||||
bottomNavItemsRepository = get(),
|
||||
notificationChecker = get(),
|
||||
lemmyValueCache = get(),
|
||||
)
|
||||
|
@ -8,6 +8,8 @@ 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.core.navigation.TabNavigationSection
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toInt
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.filteredcontents.FilteredContentsScreen
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.filteredcontents.FilteredContentsType
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.filteredcontents.toInt
|
||||
@ -20,7 +22,7 @@ object BookmarksTab : Tab {
|
||||
val title = LocalStrings.current.navigationDrawerTitleBookmarks
|
||||
|
||||
return TabOptions(
|
||||
index = 5u,
|
||||
index = TabNavigationSection.Bookmarks.toInt().toUShort(),
|
||||
title = title,
|
||||
icon = icon,
|
||||
)
|
||||
|
@ -42,8 +42,8 @@ internal fun RowScope.TabNavigationItem(
|
||||
section: TabNavigationSection,
|
||||
withText: Boolean = true,
|
||||
customIconUrl: String? = null,
|
||||
onClick: ((Tab) -> Unit)? = null,
|
||||
onLongPress: ((Tab) -> Unit)? = null,
|
||||
onClick: (() -> Unit)? = null,
|
||||
onLongPress: (() -> Unit)? = null,
|
||||
) {
|
||||
val navigationCoordinator = remember { getNavigationCoordinator() }
|
||||
val unread by navigationCoordinator.inboxUnread.collectAsState()
|
||||
@ -51,10 +51,6 @@ internal fun RowScope.TabNavigationItem(
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val tab = section.toTab()
|
||||
|
||||
fun handleClick() {
|
||||
onClick?.invoke(tab)
|
||||
}
|
||||
|
||||
val pointerInputModifier =
|
||||
Modifier.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
@ -65,16 +61,18 @@ internal fun RowScope.TabNavigationItem(
|
||||
interactionSource.emit(PressInteraction.Release(press))
|
||||
},
|
||||
onTap = {
|
||||
handleClick()
|
||||
onClick?.invoke()
|
||||
},
|
||||
onLongPress = {
|
||||
onLongPress?.invoke(tab)
|
||||
onLongPress?.invoke()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
NavigationBarItem(
|
||||
onClick = ::handleClick,
|
||||
onClick = {
|
||||
onClick?.invoke()
|
||||
},
|
||||
selected = section == currentSection,
|
||||
interactionSource = interactionSource,
|
||||
icon = {
|
||||
@ -136,7 +134,7 @@ internal fun RowScope.TabNavigationItem(
|
||||
)
|
||||
}
|
||||
|
||||
private fun TabNavigationSection.toTab(): Tab =
|
||||
internal fun TabNavigationSection.toTab(): Tab =
|
||||
when (this) {
|
||||
TabNavigationSection.Explore -> ExploreTab
|
||||
TabNavigationSection.Profile -> ProfileTab
|
||||
|
@ -36,6 +36,7 @@ import com.github.diegoberaldin.raccoonforlemmy.unit.chat.di.chatModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.communitydetail.di.communityDetailModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.communityinfo.di.communityInfoModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.configurecontentview.di.configureContentViewModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.configurenavbar.di.configureNavBarModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.configureswipeactions.di.configureSwipeActionsModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createcomment.di.createCommentModule
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.createpost.di.createPostModule
|
||||
@ -122,6 +123,7 @@ fun initKoin() {
|
||||
moderateWithReasonModule,
|
||||
acknowledgementsModule,
|
||||
mediaListModule,
|
||||
configureNavBarModule,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
@ -110,17 +111,18 @@ class AccountSettingsScreen : Screen {
|
||||
var confirmBackWithUnsavedChangesDialog by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(model) {
|
||||
model.effects.onEach { evt ->
|
||||
when (evt) {
|
||||
AccountSettingsMviModel.Effect.Failure -> {
|
||||
snackbarHostState.showSnackbar(errorMessage)
|
||||
}
|
||||
model.effects
|
||||
.onEach { evt ->
|
||||
when (evt) {
|
||||
AccountSettingsMviModel.Effect.Failure -> {
|
||||
snackbarHostState.showSnackbar(errorMessage)
|
||||
}
|
||||
|
||||
AccountSettingsMviModel.Effect.Success -> {
|
||||
snackbarHostState.showSnackbar(successMessage)
|
||||
AccountSettingsMviModel.Effect.Success -> {
|
||||
snackbarHostState.showSnackbar(successMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.launchIn(this)
|
||||
}.launchIn(this)
|
||||
}
|
||||
|
||||
DisposableEffect(key) {
|
||||
@ -214,8 +216,7 @@ class AccountSettingsScreen : Screen {
|
||||
Modifier
|
||||
.padding(
|
||||
top = padding.calculateTopPadding(),
|
||||
bottom = Spacing.m,
|
||||
)
|
||||
).navigationBarsPadding()
|
||||
.then(
|
||||
if (settings.hideNavigationBarWhileScrolling) {
|
||||
Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||
|
78
unit/configurenavbar/build.gradle.kts
Normal file
78
unit/configurenavbar/build.gradle.kts
Normal file
@ -0,0 +1,78 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.multiplatform)
|
||||
alias(libs.plugins.android.library)
|
||||
alias(libs.plugins.jetbrains.compose)
|
||||
alias(libs.plugins.compose.compiler)
|
||||
alias(libs.plugins.detekt)
|
||||
}
|
||||
|
||||
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
|
||||
kotlin {
|
||||
applyDefaultHierarchyTemplate()
|
||||
androidTarget {
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_1_8)
|
||||
}
|
||||
}
|
||||
listOf(
|
||||
iosX64(),
|
||||
iosArm64(),
|
||||
iosSimulatorArm64(),
|
||||
).forEach {
|
||||
it.binaries.framework {
|
||||
baseName = "unit.configurenavbar"
|
||||
isStatic = true
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
implementation(compose.runtime)
|
||||
implementation(compose.foundation)
|
||||
implementation(compose.material)
|
||||
implementation(compose.material3)
|
||||
implementation(compose.materialIconsExtended)
|
||||
|
||||
implementation(libs.koin.core)
|
||||
implementation(libs.reorderable)
|
||||
implementation(libs.voyager.navigator)
|
||||
implementation(libs.voyager.screenmodel)
|
||||
implementation(libs.voyager.koin)
|
||||
|
||||
implementation(projects.core.appearance)
|
||||
implementation(projects.core.architecture)
|
||||
implementation(projects.core.commonui.components)
|
||||
implementation(projects.core.commonui.modals)
|
||||
implementation(projects.core.l10n)
|
||||
implementation(projects.core.navigation)
|
||||
implementation(projects.core.notifications)
|
||||
implementation(projects.core.persistence)
|
||||
implementation(projects.core.utils)
|
||||
|
||||
implementation(projects.domain.identity)
|
||||
}
|
||||
}
|
||||
val commonTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.github.diegoberaldin.raccoonforlemmy.unit.configurenavbar"
|
||||
compileSdk =
|
||||
libs.versions.android.targetSdk
|
||||
.get()
|
||||
.toInt()
|
||||
defaultConfig {
|
||||
minSdk =
|
||||
libs.versions.android.minSdk
|
||||
.get()
|
||||
.toInt()
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.unit.configurenavbar
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.TabNavigationSection
|
||||
|
||||
@Stable
|
||||
interface ConfigureNavBarMviModel :
|
||||
MviModel<ConfigureNavBarMviModel.Intent, ConfigureNavBarMviModel.UiState, ConfigureNavBarMviModel.Effect>,
|
||||
ScreenModel {
|
||||
sealed interface Intent {
|
||||
data object Reset : Intent
|
||||
|
||||
data object HapticFeedback : Intent
|
||||
|
||||
data class SwapItems(
|
||||
val from: Int,
|
||||
val to: Int,
|
||||
) : Intent
|
||||
|
||||
data class Delete(
|
||||
val section: TabNavigationSection,
|
||||
) : Intent
|
||||
|
||||
data object Save : Intent
|
||||
}
|
||||
|
||||
data class UiState(
|
||||
val sections: List<TabNavigationSection> = emptyList(),
|
||||
val availableSections: List<TabNavigationSection> = emptyList(),
|
||||
val hasUnsavedChanges: Boolean = false,
|
||||
)
|
||||
|
||||
sealed interface Effect
|
||||
}
|
@ -0,0 +1,279 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.unit.configurenavbar
|
||||
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.koin.getScreenModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SelectTabNavigationSectionBottomSheet
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.LocalStrings
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getNavigationCoordinator
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toInt
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toReadableName
|
||||
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.unit.configurenavbar.composable.ConfigureAddAction
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.configurenavbar.composable.ConfigureNavBarItem
|
||||
import sh.calvin.reorderable.ReorderableItem
|
||||
import sh.calvin.reorderable.rememberReorderableLazyListState
|
||||
|
||||
class ConfigureNavBarScreen : Screen {
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val model = getScreenModel<ConfigureNavBarMviModel>()
|
||||
val uiState by model.uiState.collectAsState()
|
||||
val navigationCoordinator = remember { getNavigationCoordinator() }
|
||||
val topAppBarState = rememberTopAppBarState()
|
||||
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)
|
||||
val settingsRepository = remember { getSettingsRepository() }
|
||||
val settings by settingsRepository.currentSettings.collectAsState()
|
||||
val lazyListState = rememberLazyListState()
|
||||
val reorderableLazyColumnState =
|
||||
rememberReorderableLazyListState(lazyListState) { from, to ->
|
||||
model.reduce(
|
||||
ConfigureNavBarMviModel.Intent.SwapItems(
|
||||
from = from.index - 1,
|
||||
to = to.index - 1,
|
||||
),
|
||||
)
|
||||
}
|
||||
var confirmBackWithUnsavedChangesDialog by remember { mutableStateOf(false) }
|
||||
|
||||
DisposableEffect(key) {
|
||||
navigationCoordinator.setCanGoBackCallback {
|
||||
if (uiState.hasUnsavedChanges) {
|
||||
confirmBackWithUnsavedChangesDialog = true
|
||||
return@setCanGoBackCallback false
|
||||
}
|
||||
true
|
||||
}
|
||||
onDispose {
|
||||
navigationCoordinator.setCanGoBackCallback(null)
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier =
|
||||
Modifier
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.padding(Spacing.xs),
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
scrollBehavior = scrollBehavior,
|
||||
title = {
|
||||
Text(
|
||||
modifier = Modifier.padding(horizontal = Spacing.s),
|
||||
text = LocalStrings.current.settingsItemConfigureBottomNavigationBar,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
if (navigationCoordinator.canPop.value) {
|
||||
Image(
|
||||
modifier =
|
||||
Modifier.onClick(
|
||||
onClick = {
|
||||
if (uiState.hasUnsavedChanges) {
|
||||
confirmBackWithUnsavedChangesDialog = true
|
||||
} else {
|
||||
navigationCoordinator.popScreen()
|
||||
}
|
||||
},
|
||||
),
|
||||
imageVector = Icons.AutoMirrored.Default.ArrowBack,
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
|
||||
)
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
TextButton(
|
||||
contentPadding =
|
||||
PaddingValues(
|
||||
horizontal = Spacing.xs,
|
||||
vertical = Spacing.xxs,
|
||||
),
|
||||
onClick = {
|
||||
model.reduce(ConfigureNavBarMviModel.Intent.Reset)
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
text = LocalStrings.current.buttonReset,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
) { padding ->
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(
|
||||
top = padding.calculateTopPadding(),
|
||||
).navigationBarsPadding()
|
||||
.then(
|
||||
if (settings.hideNavigationBarWhileScrolling) {
|
||||
Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||
} else {
|
||||
Modifier
|
||||
},
|
||||
),
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.weight(1f).fillMaxWidth(),
|
||||
state = lazyListState,
|
||||
verticalArrangement = Arrangement.spacedBy(Spacing.xs),
|
||||
) {
|
||||
if (uiState.sections.isEmpty()) {
|
||||
item {
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth().padding(top = Spacing.xs),
|
||||
textAlign = TextAlign.Center,
|
||||
text = LocalStrings.current.messageEmptyList,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
item {
|
||||
// workaround for https://github.com/Calvin-LL/Reorderable/issues/4
|
||||
ReorderableItem(
|
||||
state = reorderableLazyColumnState,
|
||||
key = "dummy",
|
||||
enabled = false,
|
||||
modifier = Modifier.fillMaxWidth().height(Dp.Hairline),
|
||||
) {}
|
||||
}
|
||||
}
|
||||
items(
|
||||
items = uiState.sections,
|
||||
key = { it.toInt().toString() },
|
||||
) { section ->
|
||||
ReorderableItem(
|
||||
state = reorderableLazyColumnState,
|
||||
key = section.toInt().toString(),
|
||||
) { isDragging ->
|
||||
val elevation by animateDpAsState(if (isDragging) 4.dp else 0.dp)
|
||||
Surface(
|
||||
shadowElevation = elevation,
|
||||
) {
|
||||
ConfigureNavBarItem(
|
||||
reorderableScope = this,
|
||||
title = section.toReadableName(),
|
||||
onDragStarted =
|
||||
rememberCallback(model) {
|
||||
model.reduce(ConfigureNavBarMviModel.Intent.HapticFeedback)
|
||||
},
|
||||
onDelete =
|
||||
rememberCallback(model) {
|
||||
model.reduce(ConfigureNavBarMviModel.Intent.Delete(section))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uiState.availableSections.isNotEmpty() && uiState.sections.size < 5) {
|
||||
item {
|
||||
ConfigureAddAction(
|
||||
onAdd =
|
||||
rememberCallback {
|
||||
val available = model.uiState.value.availableSections
|
||||
val sheet =
|
||||
SelectTabNavigationSectionBottomSheet(values = available)
|
||||
navigationCoordinator.showBottomSheet(sheet)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = Spacing.m),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Button(
|
||||
enabled = uiState.hasUnsavedChanges,
|
||||
onClick = {
|
||||
model.reduce(ConfigureNavBarMviModel.Intent.Save)
|
||||
},
|
||||
) {
|
||||
Text(text = LocalStrings.current.actionSave)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (confirmBackWithUnsavedChangesDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
confirmBackWithUnsavedChangesDialog = false
|
||||
},
|
||||
dismissButton = {
|
||||
Button(
|
||||
onClick = {
|
||||
confirmBackWithUnsavedChangesDialog = false
|
||||
},
|
||||
) {
|
||||
Text(text = LocalStrings.current.buttonNoStay)
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
Button(
|
||||
onClick = {
|
||||
confirmBackWithUnsavedChangesDialog = false
|
||||
navigationCoordinator.popScreen()
|
||||
},
|
||||
) {
|
||||
Text(text = LocalStrings.current.buttonYesQuit)
|
||||
}
|
||||
},
|
||||
text = {
|
||||
Text(text = LocalStrings.current.messageUnsavedChanges)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.unit.configurenavbar
|
||||
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.BottomNavItemsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.TabNavigationSection
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toInts
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toTabNavigationSection
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.AccountRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.SettingsRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.vibrate.HapticFeedback
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
internal class ConfigureNavBarViewModel(
|
||||
private val accountRepository: AccountRepository,
|
||||
private val identityRepository: IdentityRepository,
|
||||
private val bottomNavItemsRepository: BottomNavItemsRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val hapticFeedback: HapticFeedback,
|
||||
private val notificationCenter: NotificationCenter,
|
||||
) : DefaultMviModel<ConfigureNavBarMviModel.Intent, ConfigureNavBarMviModel.UiState, ConfigureNavBarMviModel.Effect>(
|
||||
initialState = ConfigureNavBarMviModel.UiState(),
|
||||
),
|
||||
ConfigureNavBarMviModel {
|
||||
init {
|
||||
screenModelScope.launch {
|
||||
notificationCenter
|
||||
.subscribe(NotificationCenterEvent.TabNavigationSectionSelected::class)
|
||||
.onEach { evt ->
|
||||
evt.sectionId.toTabNavigationSection()?.also { section ->
|
||||
handleAdd(section)
|
||||
}
|
||||
}.launchIn(this)
|
||||
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
|
||||
override fun reduce(intent: ConfigureNavBarMviModel.Intent) {
|
||||
when (intent) {
|
||||
ConfigureNavBarMviModel.Intent.HapticFeedback -> hapticFeedback.vibrate()
|
||||
ConfigureNavBarMviModel.Intent.Reset -> handleReset()
|
||||
is ConfigureNavBarMviModel.Intent.Delete -> handleDelete(intent.section)
|
||||
is ConfigureNavBarMviModel.Intent.SwapItems -> handleSwap(intent.from, intent.to)
|
||||
ConfigureNavBarMviModel.Intent.Save -> save()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun refresh() {
|
||||
val accountId = accountRepository.getActive()?.id
|
||||
val currentSections = bottomNavItemsRepository.get(accountId)
|
||||
updateState {
|
||||
it.copy(
|
||||
sections = currentSections,
|
||||
availableSections = getAvailableSections(currentSections),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAvailableSections(excludeSections: List<TabNavigationSection> = emptyList()): List<TabNavigationSection> {
|
||||
val availableSections =
|
||||
buildList {
|
||||
this += TabNavigationSection.Home
|
||||
this += TabNavigationSection.Explore
|
||||
this += TabNavigationSection.Inbox
|
||||
this += TabNavigationSection.Profile
|
||||
this += TabNavigationSection.Settings
|
||||
if (identityRepository.isLogged.value == true) {
|
||||
this += TabNavigationSection.Bookmarks
|
||||
}
|
||||
}
|
||||
return availableSections.filter { section -> section !in excludeSections }
|
||||
}
|
||||
|
||||
private fun handleReset() {
|
||||
screenModelScope.launch {
|
||||
val oldSections = uiState.value.sections
|
||||
val newSections = BottomNavItemsRepository.DEFAULT_ITEMS
|
||||
updateState {
|
||||
it.copy(
|
||||
sections = newSections,
|
||||
availableSections = getAvailableSections(newSections),
|
||||
hasUnsavedChanges = newSections != oldSections,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleAdd(section: TabNavigationSection) {
|
||||
val newSections = uiState.value.sections + section
|
||||
screenModelScope.launch {
|
||||
updateState {
|
||||
it.copy(
|
||||
sections = newSections,
|
||||
availableSections = getAvailableSections(newSections),
|
||||
hasUnsavedChanges = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDelete(section: TabNavigationSection) {
|
||||
val newSections = uiState.value.sections - section
|
||||
screenModelScope.launch {
|
||||
updateState {
|
||||
it.copy(
|
||||
sections = newSections,
|
||||
availableSections = getAvailableSections(newSections),
|
||||
hasUnsavedChanges = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSwap(
|
||||
from: Int,
|
||||
to: Int,
|
||||
) {
|
||||
val newSections =
|
||||
uiState.value.sections.toMutableList().apply {
|
||||
val element = removeAt(from)
|
||||
add(to, element)
|
||||
}
|
||||
screenModelScope.launch {
|
||||
updateState {
|
||||
it.copy(
|
||||
sections = newSections,
|
||||
hasUnsavedChanges = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun save() {
|
||||
screenModelScope.launch {
|
||||
val currentSections = uiState.value.sections
|
||||
val accountId = accountRepository.getActive()?.id
|
||||
bottomNavItemsRepository.update(accountId, currentSections)
|
||||
updateState {
|
||||
it.copy(hasUnsavedChanges = false)
|
||||
}
|
||||
settingsRepository.changeCurrentBottomBarSections(currentSections.toInts())
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.unit.configurenavbar.composable
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Add
|
||||
import androidx.compose.material3.Icon
|
||||
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 com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.ancillaryTextAlpha
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.LocalStrings
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
|
||||
|
||||
@Composable
|
||||
internal fun ConfigureAddAction(onAdd: () -> Unit) {
|
||||
val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha)
|
||||
Row(
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(
|
||||
horizontal = Spacing.s,
|
||||
vertical = Spacing.xs,
|
||||
).onClick(onClick = onAdd),
|
||||
horizontalArrangement = Arrangement.SpaceAround,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(IconSize.m),
|
||||
imageVector = Icons.Outlined.Add,
|
||||
contentDescription = null,
|
||||
tint = ancillaryColor,
|
||||
)
|
||||
Spacer(modifier = Modifier.width(Spacing.xs))
|
||||
Text(
|
||||
text = LocalStrings.current.buttonAdd,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.unit.configurenavbar.composable
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
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.MoreVert
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.layout.positionInParent
|
||||
import androidx.compose.ui.unit.DpOffset
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.ancillaryTextAlpha
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CustomDropDown
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.l10n.messages.LocalStrings
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.toLocalDp
|
||||
import sh.calvin.reorderable.ReorderableCollectionItemScope
|
||||
|
||||
@Composable
|
||||
internal fun ConfigureNavBarItem(
|
||||
modifier: Modifier = Modifier,
|
||||
reorderableScope: ReorderableCollectionItemScope,
|
||||
title: String,
|
||||
onDragStarted: (() -> Unit)? = null,
|
||||
onDelete: (() -> Unit)? = null,
|
||||
) {
|
||||
var optionsOffset by remember { mutableStateOf(Offset.Zero) }
|
||||
var optionsMenuOpen by remember { mutableStateOf(false) }
|
||||
val fullColor = MaterialTheme.colorScheme.onBackground
|
||||
val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha)
|
||||
|
||||
Row(
|
||||
modifier =
|
||||
modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
horizontal = Spacing.m,
|
||||
vertical = Spacing.s,
|
||||
),
|
||||
horizontalArrangement = Arrangement.spacedBy(Spacing.s),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
color = fullColor,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Box {
|
||||
Icon(
|
||||
modifier =
|
||||
Modifier
|
||||
.size(IconSize.m)
|
||||
.padding(Spacing.xs)
|
||||
.then(
|
||||
with(reorderableScope) {
|
||||
Modifier.draggableHandle(
|
||||
onDragStarted = {
|
||||
onDragStarted?.invoke()
|
||||
},
|
||||
)
|
||||
},
|
||||
).onGloballyPositioned {
|
||||
optionsOffset = it.positionInParent()
|
||||
}.onClick(
|
||||
onClick = {
|
||||
optionsMenuOpen = true
|
||||
},
|
||||
),
|
||||
imageVector = Icons.Default.MoreVert,
|
||||
contentDescription = null,
|
||||
tint = ancillaryColor,
|
||||
)
|
||||
|
||||
CustomDropDown(
|
||||
expanded = optionsMenuOpen,
|
||||
onDismiss = {
|
||||
optionsMenuOpen = false
|
||||
},
|
||||
offset =
|
||||
DpOffset(
|
||||
x = optionsOffset.x.toLocalDp(),
|
||||
y = optionsOffset.y.toLocalDp(),
|
||||
),
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(LocalStrings.current.commentActionDelete)
|
||||
},
|
||||
onClick = {
|
||||
optionsMenuOpen = false
|
||||
onDelete?.invoke()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.github.diegoberaldin.raccoonforlemmy.unit.configurenavbar.di
|
||||
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.configurenavbar.ConfigureNavBarMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.unit.configurenavbar.ConfigureNavBarViewModel
|
||||
import org.koin.dsl.module
|
||||
|
||||
val configureNavBarModule =
|
||||
module {
|
||||
single<ConfigureNavBarMviModel> {
|
||||
ConfigureNavBarViewModel(
|
||||
accountRepository = get(),
|
||||
identityRepository = get(),
|
||||
bottomNavItemsRepository = get(),
|
||||
settingsRepository = get(),
|
||||
hapticFeedback = get(),
|
||||
notificationCenter = get(),
|
||||
)
|
||||
}
|
||||
}
|
@ -205,22 +205,24 @@ 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)
|
||||
if (uiState.isSettingsVisible) {
|
||||
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)
|
||||
}
|
||||
},
|
||||
)
|
||||
coordinator.sendEvent(DrawerEvent.OpenSettings)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ interface ModalDrawerMviModel :
|
||||
val searchText: String = "",
|
||||
val isFiltering: Boolean = false,
|
||||
val enableToggleFavorite: Boolean = false,
|
||||
val isSettingsVisible: Boolean = true,
|
||||
)
|
||||
|
||||
sealed interface Effect
|
||||
|
@ -4,6 +4,8 @@ import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import com.diegoberaldin.raccoonforlemmy.domain.lemmy.pagination.CommunityPaginationManager
|
||||
import com.diegoberaldin.raccoonforlemmy.domain.lemmy.pagination.CommunityPaginationSpecification
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.TabNavigationSection
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.toTabNavigationSections
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.FavoriteCommunityModel
|
||||
@ -98,6 +100,14 @@ class ModalDrawerViewModel(
|
||||
)
|
||||
}
|
||||
}.launchIn(this)
|
||||
settingsRepository.currentBottomBarSections
|
||||
.onEach { sectionIds ->
|
||||
val isSettingsInBottomBar =
|
||||
sectionIds.toTabNavigationSections().contains(TabNavigationSection.Settings)
|
||||
updateState {
|
||||
it.copy(isSettingsVisible = !isSettingsInBottomBar)
|
||||
}
|
||||
}.launchIn(this)
|
||||
|
||||
uiState
|
||||
.map { it.searchText }
|
||||
|
Loading…
x
Reference in New Issue
Block a user