feat: edge to edge contents (#398)

* chore: setup

* feat: update post list

* feat: update community detail

* feat: update multi-community

* feat: update user detail

* feat: update profile

* feat: add option in settings

* feat: persistence and db migration

* chore: add translations

closes #311
This commit is contained in:
Diego Beraldin 2023-12-29 13:17:16 +01:00 committed by GitHub
parent b59e5426dd
commit 0ec23f943d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 193 additions and 20 deletions

View File

@ -39,4 +39,5 @@ data class SettingsModel(
val commentBarTheme: Int = 0,
val replyColor: Int? = null,
val searchPostTitleOnly: Boolean = false,
val edgeToEdge: Boolean = true,
) : JavaSerializable

View File

@ -45,6 +45,7 @@ private object KeyStoreKeys {
const val ReplyColor = "replyColor"
const val SearchPostTitleOnly = "searchPostTitleOnly"
const val ContentFontFamily = "contentFontFamily"
const val EdgeToEdge = "edgeToEdge"
}
internal class DefaultSettingsRepository(
@ -92,6 +93,7 @@ internal class DefaultSettingsRepository(
replyColor = settings.replyColor?.toLong(),
searchPostTitleOnly = if (settings.searchPostTitleOnly) 1 else 0,
contentFontFamily = settings.contentFontFamily.toLong(),
edgeToEdge = if (settings.edgeToEdge) 1 else 0,
)
}
@ -134,6 +136,7 @@ internal class DefaultSettingsRepository(
replyColor = if (!keyStore.containsKey(KeyStoreKeys.ReplyColor)) null else keyStore[KeyStoreKeys.ReplyColor, 0],
searchPostTitleOnly = keyStore[KeyStoreKeys.SearchPostTitleOnly, false],
contentFontFamily = keyStore[KeyStoreKeys.ContentFontFamily, 0],
edgeToEdge = keyStore[KeyStoreKeys.EdgeToEdge, true],
)
} else {
val entity = db.settingsQueries.getBy(accountId).executeAsOneOrNull()
@ -220,6 +223,7 @@ internal class DefaultSettingsRepository(
settings.searchPostTitleOnly,
)
keyStore.save(KeyStoreKeys.ContentFontFamily, settings.contentFontFamily)
keyStore.save(KeyStoreKeys.EdgeToEdge, settings.edgeToEdge)
} else {
db.settingsQueries.update(
theme = settings.theme?.toLong(),
@ -255,6 +259,7 @@ internal class DefaultSettingsRepository(
replyColor = settings.replyColor?.toLong(),
searchPostTitleOnly = if (settings.searchPostTitleOnly) 1L else 0L,
contentFontFamily = settings.contentFontFamily.toLong(),
edgeToEdge = if (settings.edgeToEdge) 1L else 0L,
)
}
}
@ -298,4 +303,5 @@ private fun GetBy.toModel() = SettingsModel(
replyColor = replyColor?.toInt(),
searchPostTitleOnly = searchPostTitleOnly != 0L,
contentFontFamily = contentFontFamily.toInt(),
edgeToEdge = edgeToEdge != 0L,
)

View File

@ -32,6 +32,7 @@ CREATE TABLE SettingsEntity (
replyColor INTEGER DEFAULT NULL,
searchPostTitleOnly INTEGER NOT NULL DEFAULT 0,
contentFontFamily INTEGER NOT NULL DEFAULT 0,
edgeToEdge INTEGER NOT NULL DEFAULT 1,
account_id INTEGER,
FOREIGN KEY (account_id) REFERENCES AccountEntity(id) ON DELETE CASCADE,
UNIQUE(account_id)
@ -71,6 +72,7 @@ INSERT OR IGNORE INTO SettingsEntity (
replyColor,
searchPostTitleOnly,
contentFontFamily,
edgeToEdge,
account_id
) VALUES (
?,
@ -105,6 +107,7 @@ INSERT OR IGNORE INTO SettingsEntity (
?,
?,
?,
?,
?
);
@ -141,7 +144,8 @@ SET theme = ?,
commentBarTheme = ?,
replyColor = ?,
searchPostTitleOnly = ?,
contentFontFamily = ?
contentFontFamily = ?,
edgeToEdge = ?
WHERE account_id = ?;
getBy:
@ -178,6 +182,7 @@ SELECT
commentBarTheme,
replyColor,
searchPostTitleOnly,
contentFontFamily
contentFontFamily,
edgeToEdge
FROM SettingsEntity
WHERE account_id = ?;

View File

@ -0,0 +1,2 @@
ALTER TABLE SettingsEntity
ADD COLUMN edgeToEdge INTEGER NOT NULL DEFAULT 1;

View File

@ -3,6 +3,7 @@ package com.github.diegoberaldin.raccoonforlemmy.feature.profile.main
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
@ -15,6 +16,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
@ -22,6 +24,8 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
@ -32,6 +36,7 @@ import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
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.appearance.theme.Dimensions
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.di.getDrawerCoordinator
@ -65,7 +70,8 @@ internal object ProfileMainScreen : Tab {
val model = getScreenModel<ProfileMainMviModel>()
model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState()
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
val topAppBarState = rememberTopAppBarState()
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)
val drawerCoordinator = remember { getDrawerCoordinator() }
val navigationCoordinator = remember { getNavigationCoordinator() }
val settingsRepository = remember { getSettingsRepository() }
@ -80,7 +86,18 @@ internal object ProfileMainScreen : Tab {
val title by remember(lang) {
mutableStateOf(staticString(MR.strings.navigation_profile.desc()))
}
val maxTopInset = Dimensions.topBarHeight.value.toInt()
var topInset by remember { mutableStateOf(maxTopInset) }
snapshotFlow { topAppBarState.collapsedFraction }.onEach {
topInset = (maxTopInset * (1 - it)).toInt()
}.launchIn(scope)
TopAppBar(
windowInsets = if (settings.edgeToEdge) {
WindowInsets(0, topInset, 0, 0)
} else {
TopAppBarDefaults.windowInsets
},
scrollBehavior = scrollBehavior,
navigationIcon = {
Image(

View File

@ -51,6 +51,7 @@ interface SettingsMviModel :
data class ChangeMarkAsReadWhileScrolling(val value: Boolean) : Intent
data class ChangeDefaultInboxUnreadOnly(val value: Boolean) : Intent
data class ChangeSearchPostTitleOnly(val value: Boolean) : Intent
data class ChangeEdgeToEdge(val value: Boolean) : Intent
}
data class UiState(
@ -91,6 +92,7 @@ interface SettingsMviModel :
val availableSortTypesForComments: List<SortType> = emptyList(),
val commentBarTheme: CommentBarTheme = CommentBarTheme.Blue,
val searchPostTitleOnly: Boolean = false,
val edgeToEdge: Boolean = true,
)
sealed interface Effect

View File

@ -442,6 +442,17 @@ class SettingsScreen : Screen {
title = stringResource(MR.strings.settings_section_behaviour),
)
// edge to edge
SettingsSwitchRow(
title = stringResource(MR.strings.settings_edge_to_edge),
value = uiState.edgeToEdge,
onValueChanged = rememberCallbackArgs(model) { value ->
model.reduce(
SettingsMviModel.Intent.ChangeEdgeToEdge(value)
)
},
)
// mark as read while scrolling
SettingsSwitchRow(
title = stringResource(MR.strings.settings_mark_as_read_while_scrolling),

View File

@ -212,6 +212,7 @@ class SettingsViewModel(
zombieModeScrollAmount = settings.zombieModeScrollAmount,
markAsReadWhileScrolling = settings.markAsReadWhileScrolling,
searchPostTitleOnly = settings.searchPostTitleOnly,
edgeToEdge = settings.edgeToEdge,
)
}
}
@ -345,6 +346,10 @@ class SettingsViewModel(
is SettingsMviModel.Intent.ChangeSearchPostTitleOnly -> {
changeSearchPostTitleOnly(intent.value)
}
is SettingsMviModel.Intent.ChangeEdgeToEdge -> {
changeEdgeToEdge(intent.value)
}
}
}
@ -678,6 +683,16 @@ class SettingsViewModel(
}
}
private fun changeEdgeToEdge(value: Boolean) {
mvi.updateState { it.copy(edgeToEdge = value) }
mvi.scope?.launch(Dispatchers.IO) {
val settings = settingsRepository.currentSettings.value.copy(
edgeToEdge = value
)
saveSettings(settings)
}
}
private suspend fun saveSettings(settings: SettingsModel) {
val accountId = accountRepository.getActive()?.id
settingsRepository.updateSettings(settings, accountId)

View File

@ -303,4 +303,5 @@
<string name="settings_manage_ban">الحظر والمرشحات</string>
<string name="settings_manage_ban_action_unban">إزالة الحظر</string>
<string name="settings_manage_ban_section_instances">المثيلات</string>
<string name="settings_edge_to_edge">محتويات الحافة إلى الحافة</string>
</resources>

View File

@ -334,4 +334,5 @@
<string name="settings_manage_ban">Bans and filters</string>
<string name="settings_manage_ban_action_unban">Unban</string>
<string name="settings_manage_ban_section_instances">Instances</string>
<string name="settings_edge_to_edge">Edge to edge contents</string>
</resources>

View File

@ -313,4 +313,5 @@
<string name="settings_manage_ban">Забрани и филтри</string>
<string name="settings_manage_ban_action_unban">Премахване на забраната</string>
<string name="settings_manage_ban_section_instances">Инстанции</string>
<string name="settings_edge_to_edge">Съдържание от край до край</string>
</resources>

View File

@ -305,4 +305,5 @@
<string name="settings_manage_ban">Zákazy a filtry</string>
<string name="settings_manage_ban_action_unban">Odstranit zákaz</string>
<string name="settings_manage_ban_section_instances">Instance</string>
<string name="settings_edge_to_edge">Obsah od okraje k okraji</string>
</resources>

View File

@ -305,4 +305,5 @@
<string name="settings_manage_ban">Forbud og filtre</string>
<string name="settings_manage_ban_action_unban">Fjern forbuddet</string>
<string name="settings_manage_ban_section_instances">Forekomster</string>
<string name="settings_edge_to_edge">Indhold fra kant til kant</string>
</resources>

View File

@ -313,4 +313,5 @@
<string name="settings_manage_ban">Verbote und Filter</string>
<string name="settings_manage_ban_action_unban">Verbot aufheben</string>
<string name="settings_manage_ban_section_instances">Instanzen</string>
<string name="settings_edge_to_edge">Rand-zu-Rand-Inhalte</string>
</resources>

View File

@ -316,4 +316,5 @@
<string name="settings_manage_ban">Απαγορεύσεις και φίλτρα</string>
<string name="settings_manage_ban_action_unban">Κατάργηση απαγόρευσης</string>
<string name="settings_manage_ban_section_instances">Περιπτώσεις</string>
<string name="settings_edge_to_edge">Περιεχόμενα από άκρη σε άκρη</string>
</resources>

View File

@ -304,4 +304,5 @@
<string name="settings_manage_ban">Malpermesoj kaj filtriloj</string>
<string name="settings_manage_ban_action_unban">Forigi malpermeson</string>
<string name="settings_manage_ban_section_instances">Ekzemploj</string>
<string name="settings_edge_to_edge">Enhavo de rando al rando</string>
</resources>

View File

@ -310,4 +310,5 @@
<string name="settings_manage_ban">Prohibiciones y filtros</string>
<string name="settings_manage_ban_action_unban">Eliminar prohibición</string>
<string name="settings_manage_ban_section_instances">Instancias</string>
<string name="settings_edge_to_edge">Contenidos de borde a borde</string>
</resources>

View File

@ -305,4 +305,5 @@
<string name="settings_manage_ban">Keelud ja filtrid</string>
<string name="settings_manage_ban_action_unban">Eemalda keeld</string>
<string name="settings_manage_ban_section_instances">Juhtumid</string>
<string name="settings_edge_to_edge">Servast servani sisu</string>
</resources>

View File

@ -305,4 +305,5 @@
<string name="settings_manage_ban">Kiellot ja suodattimet</string>
<string name="settings_manage_ban_action_unban">Poista kielto</string>
<string name="settings_manage_ban_section_instances">Esineet</string>
<string name="settings_edge_to_edge">Reunasta reunaan sisältö</string>
</resources>

View File

@ -310,4 +310,5 @@
<string name="settings_manage_ban">Interdictions et filtres</string>
<string name="settings_manage_ban_action_unban">Supprimer interdiction</string>
<string name="settings_manage_ban_section_instances">Instances</string>
<string name="settings_edge_to_edge">Contenu bord à bord</string>
</resources>

View File

@ -314,4 +314,5 @@
<string name="settings_manage_ban">Toirmisc agus scagairí</string>
<string name="settings_manage_ban_action_unban">Bain toirmeasc</string>
<string name="settings_manage_ban_section_instances">Cásanna</string>
<string name="settings_edge_to_edge">Ábhar imeall go himeall</string>
</resources>

View File

@ -310,4 +310,5 @@
<string name="settings_manage_ban">Zabrane i filteri</string>
<string name="settings_manage_ban_action_unban">Ukloni zabranu</string>
<string name="settings_manage_ban_section_instances">Instance</string>
<string name="settings_edge_to_edge">Sadržaj od ruba do ruba</string>
</resources>

View File

@ -309,4 +309,5 @@
<string name="settings_manage_ban">Tiltások és szűrők</string>
<string name="settings_manage_ban_action_unban">Távolítsa el a tiltást</string>
<string name="settings_manage_ban_section_instances">Példányok</string>
<string name="settings_edge_to_edge">Éltől szélig tartalom</string>
</resources>

View File

@ -309,4 +309,5 @@
<string name="settings_manage_ban">Ban e filtri</string>
<string name="settings_manage_ban_action_unban">Rimuovi ban</string>
<string name="settings_manage_ban_section_instances">Istanze</string>
<string name="settings_edge_to_edge">Contenuti da margine a margine</string>
</resources>

View File

@ -307,4 +307,5 @@
<string name="settings_manage_ban">Draudimai ir filtrai</string>
<string name="settings_manage_ban_action_unban">Pašalinti draudimą</string>
<string name="settings_manage_ban_section_instances">Atvejai</string>
<string name="settings_edge_to_edge">Turinys nuo krašto iki krašto</string>
</resources>

View File

@ -309,4 +309,5 @@
<string name="settings_manage_ban">Aizliegumi un filtri</string>
<string name="settings_manage_ban_action_unban">Noņemt aizliegumu</string>
<string name="settings_manage_ban_section_instances">Gadījumi</string>
<string name="settings_edge_to_edge">Saturs no malas līdz malai</string>
</resources>

View File

@ -310,4 +310,5 @@
<string name="settings_manage_ban">Projbizzjonijiet u filtri</string>
<string name="settings_manage_ban_action_unban">Neħħi l-projbizzjoni</string>
<string name="settings_manage_ban_section_instances">Każijiet</string>
<string name="settings_edge_to_edge">Kontenut tarf sa tarf</string>
</resources>

View File

@ -308,4 +308,5 @@
<string name="settings_manage_ban">Verboden en filters</string>
<string name="settings_manage_ban_action_unban">Verwijder verbod</string>
<string name="settings_manage_ban_section_instances">Instanties</string>
<string name="settings_edge_to_edge">Inhoud van rand tot rand</string>
</resources>

View File

@ -307,4 +307,5 @@
<string name="settings_manage_ban">Forbud og filtre</string>
<string name="settings_manage_ban_action_unban">Fjern forbudet</string>
<string name="settings_manage_ban_section_instances">Forekomster</string>
<string name="settings_edge_to_edge">Kant til kant innhold</string>
</resources>

View File

@ -308,4 +308,5 @@
<string name="settings_manage_ban">Zakazy i filtry</string>
<string name="settings_manage_ban_action_unban">Usuń zakaz</string>
<string name="settings_manage_ban_section_instances">Instancje</string>
<string name="settings_edge_to_edge">Zawartość od krawędzi do krawędzi</string>
</resources>

View File

@ -307,4 +307,5 @@
<string name="settings_manage_ban">Proibições e filtros</string>
<string name="settings_manage_ban_action_unban">Remover proibição</string>
<string name="settings_manage_ban_section_instances">Instâncias</string>
<string name="settings_edge_to_edge">Conteúdo de ponta a ponta</string>
</resources>

View File

@ -306,4 +306,5 @@
<string name="settings_manage_ban">Interdicții și filtre</string>
<string name="settings_manage_ban_action_unban">Elimină interdicția</string>
<string name="settings_manage_ban_section_instances">Instanțe</string>
<string name="settings_edge_to_edge">Conținut de la margine la margine</string>
</resources>

View File

@ -309,4 +309,5 @@
<string name="settings_manage_ban">Баны и фильтры</string>
<string name="settings_manage_ban_action_unban">Снять бан</string>
<string name="settings_manage_ban_section_instances">Экземпляры</string>
<string name="settings_edge_to_edge">Содержимое от края до края</string>
</resources>

View File

@ -306,4 +306,5 @@
<string name="settings_manage_ban">Förbud och filter</string>
<string name="settings_manage_ban_action_unban">Ta bort förbudet</string>
<string name="settings_manage_ban_section_instances">Instanser</string>
<string name="settings_edge_to_edge">Kant till kant innehåll</string>
</resources>

View File

@ -307,4 +307,5 @@
<string name="settings_manage_ban">Zákazy a filtre</string>
<string name="settings_manage_ban_action_unban">Odstrániť zákaz</string>
<string name="settings_manage_ban_section_instances">Inštancie</string>
<string name="settings_edge_to_edge">Obsah od okraja k okraju</string>
</resources>

View File

@ -305,4 +305,5 @@
<string name="settings_manage_ban">Prepovedi in filtri</string>
<string name="settings_manage_ban_action_unban">Odstrani prepoved</string>
<string name="settings_manage_ban_section_instances">Primerki</string>
<string name="settings_edge_to_edge">Vsebina od roba do roba</string>
</resources>

View File

@ -311,4 +311,5 @@
<string name="settings_manage_ban">Ndalimet dhe filtrat</string>
<string name="settings_manage_ban_action_unban">Hiq ndalimin</string>
<string name="settings_manage_ban_section_instances">Instancat</string>
<string name="settings_edge_to_edge">Përmbajtja buzë në skaj</string>
</resources>

View File

@ -308,4 +308,5 @@
<string name="settings_manage_ban">Yasaklar ve filtreler</string>
<string name="settings_manage_ban_action_unban">Yasağı kaldır</string>
<string name="settings_manage_ban_section_instances">Örnekler</string>
<string name="settings_edge_to_edge">Uçtan uca içerikler</string>
</resources>

View File

@ -307,4 +307,5 @@
<string name="settings_manage_ban">Заборони та фільтри</string>
<string name="settings_manage_ban_action_unban">Зняти бан</string>
<string name="settings_manage_ban_section_instances">Примірники</string>
<string name="settings_edge_to_edge">Вміст від краю до краю</string>
</resources>

View File

@ -223,6 +223,7 @@ fun App(onLoadingFinished: () -> Unit = {}) {
theme = currentTheme,
contentFontScale = fontScale,
useDynamicColors = useDynamicColors,
transparent = true,
) {
val lang by languageRepository.currentLanguage.collectAsState()
LaunchedEffect(lang) {}

View File

@ -32,6 +32,7 @@ import cafe.adriel.voyager.koin.getScreenModel
import cafe.adriel.voyager.navigator.tab.CurrentTab
import cafe.adriel.voyager.navigator.tab.TabNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.DrawerEvent
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.TabNavigationSection
@ -188,7 +189,12 @@ internal object MainScreen : Screen {
y = -uiState.bottomBarOffsetHeightPx.roundToInt()
)
},
contentPadding = PaddingValues(0.dp),
contentPadding = PaddingValues(
start = 0.dp,
top = 0.dp,
end = 0.dp,
bottom = Spacing.m,
),
backgroundColor = MaterialTheme.colorScheme.background,
) {
TabNavigationItem(HomeTab, withText = titleVisible)

View File

@ -10,6 +10,7 @@ import androidx.compose.foundation.gestures.animateScrollBy
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@ -57,6 +58,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
@ -72,6 +74,7 @@ import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.core.screen.ScreenKey
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Dimensions
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CustomDropDown
@ -208,7 +211,18 @@ class CommunityDetailScreen(
.background(MaterialTheme.colorScheme.background)
.padding(Spacing.xs),
topBar = {
val maxTopInset = Dimensions.topBarHeight.value.toInt()
var topInset by remember { mutableStateOf(maxTopInset) }
snapshotFlow { topAppBarState.collapsedFraction }.onEach {
topInset = (maxTopInset * (1 - it)).toInt()
}.launchIn(scope)
TopAppBar(
windowInsets = if (settings.edgeToEdge) {
WindowInsets(0, topInset, 0, 0)
} else {
TopAppBarDefaults.windowInsets
},
scrollBehavior = scrollBehavior,
title = {
Text(

View File

@ -7,6 +7,7 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@ -42,8 +43,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@ -56,6 +60,7 @@ import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.koin.getScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Dimensions
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.FloatingActionButtonMenu
@ -83,6 +88,8 @@ import com.github.diegoberaldin.raccoonforlemmy.unit.createreport.CreateReportSc
import com.github.diegoberaldin.raccoonforlemmy.unit.web.WebViewScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.zoomableimage.ZoomableImageScreen
import dev.icerock.moko.resources.compose.stringResource
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
class MultiCommunityScreen(
@ -116,7 +123,17 @@ class MultiCommunityScreen(
Scaffold(
topBar = {
val sortType = uiState.sortType
val maxTopInset = Dimensions.topBarHeight.value.toInt()
var topInset by remember { mutableStateOf(maxTopInset) }
snapshotFlow { topAppBarState.collapsedFraction }.onEach {
topInset = (maxTopInset * (1 - it)).toInt()
}.launchIn(scope)
TopAppBar(
windowInsets = if (settings.edgeToEdge) {
WindowInsets(0, topInset, 0, 0)
} else {
TopAppBarDefaults.windowInsets
},
title = {
Text(
text = community.name,

View File

@ -69,7 +69,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.PostCardPl
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.di.getFabNestedScrollConnection
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.BlockBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.ListingTypeBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.RawContentDialog
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.ShareBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.SortBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.TabNavigationSection
@ -84,6 +83,7 @@ import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import com.github.diegoberaldin.raccoonforlemmy.unit.createcomment.CreateCommentScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.createpost.CreatePostScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.createreport.CreateReportScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.rawcontent.RawContentDialog
import com.github.diegoberaldin.raccoonforlemmy.unit.web.WebViewScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.zoomableimage.ZoomableImageScreen
import dev.icerock.moko.resources.compose.stringResource
@ -165,6 +165,8 @@ class PostListScreen : Screen {
listingType = uiState.listingType,
sortType = uiState.sortType,
scrollBehavior = scrollBehavior,
topAppBarState = topAppBarState,
edgeToEdge = settings.edgeToEdge,
onHamburgerTapped = rememberCallback {
scope.launch {
drawerCoordinator.toggleDrawer()

View File

@ -4,6 +4,7 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
@ -14,10 +15,19 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.TopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Dimensions
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
@ -29,29 +39,46 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toIcon
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.toReadableName
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import dev.icerock.moko.resources.compose.stringResource
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@OptIn(ExperimentalMaterial3Api::class)
@Composable
internal fun PostsTopBar(
scrollBehavior: TopAppBarScrollBehavior? = null,
topAppBarState: TopAppBarState,
currentInstance: String,
listingType: ListingType?,
sortType: SortType?,
edgeToEdge: Boolean = true,
onSelectListingType: (() -> Unit)? = null,
onSelectSortType: (() -> Unit)? = null,
onHamburgerTapped: (() -> Unit)? = null,
) {
val scope = rememberCoroutineScope()
val maxTopInset = Dimensions.topBarHeight.value.toInt()
var topInset by remember { mutableStateOf(maxTopInset) }
snapshotFlow { topAppBarState.collapsedFraction }.onEach {
topInset = (maxTopInset * (1 - it)).toInt()
}.launchIn(scope)
TopAppBar(
windowInsets = if (edgeToEdge) {
WindowInsets(0, topInset, 0, 0)
} else {
TopAppBarDefaults.windowInsets
},
scrollBehavior = scrollBehavior,
navigationIcon = {
when {
onHamburgerTapped != null -> {
Image(
modifier = Modifier.onClick(
onClick = rememberCallback {
onHamburgerTapped()
},
),
modifier = Modifier
.onClick(
onClick = rememberCallback {
onHamburgerTapped()
},
),
imageVector = Icons.Default.Menu,
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
@ -60,11 +87,12 @@ internal fun PostsTopBar(
listingType != null -> {
Image(
modifier = Modifier.onClick(
onClick = rememberCallback {
onSelectListingType?.invoke()
},
),
modifier = Modifier
.onClick(
onClick = rememberCallback {
onSelectListingType?.invoke()
},
),
imageVector = listingType.toIcon(),
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
@ -116,11 +144,12 @@ internal fun PostsTopBar(
}
if (sortType != null) {
Image(
modifier = Modifier.onClick(
onClick = rememberCallback {
onSelectSortType?.invoke()
},
),
modifier = Modifier
.onClick(
onClick = rememberCallback {
onSelectSortType?.invoke()
},
),
imageVector = sortType.toIcon(),
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),

View File

@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@ -51,6 +52,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
@ -67,6 +69,7 @@ import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.core.screen.ScreenKey
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Dimensions
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CustomDropDown
@ -185,7 +188,18 @@ class UserDetailScreen(
topBar = {
val userName = user.name
val userHost = user.host
val maxTopInset = Dimensions.topBarHeight.value.toInt()
var topInset by remember { mutableStateOf(maxTopInset) }
snapshotFlow { topAppBarState.collapsedFraction }.onEach {
topInset = (maxTopInset * (1 - it)).toInt()
}.launchIn(scope)
TopAppBar(
windowInsets = if (settings.edgeToEdge) {
WindowInsets(0, topInset, 0, 0)
} else {
TopAppBarDefaults.windowInsets
},
scrollBehavior = scrollBehavior,
title = {
Text(