mirror of
https://github.com/fromchat-messenger/app.git
synced 2026-09-22 19:15:05 +03:00
Fix blur and make window size be remembered
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
package ru.fromchat.desktop
|
||||||
|
|
||||||
|
import androidx.compose.ui.unit.DpSize
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import java.util.prefs.Preferences
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Desktop main-window size prefs.
|
||||||
|
*
|
||||||
|
* Stored in the same JVM prefs node as PlatformSettings (`ru.fromchat.settings`),
|
||||||
|
* keys `desktop_window_width` / `desktop_window_height` (float dp).
|
||||||
|
*/
|
||||||
|
internal object DesktopWindowPrefs {
|
||||||
|
private const val WIDTH_KEY = "desktop_window_width"
|
||||||
|
private const val HEIGHT_KEY = "desktop_window_height"
|
||||||
|
|
||||||
|
private val prefs: Preferences =
|
||||||
|
Preferences.userRoot().node("ru.fromchat.settings")
|
||||||
|
|
||||||
|
fun loadSize(): DpSize {
|
||||||
|
val width = prefs.getFloat(WIDTH_KEY, 0f)
|
||||||
|
val height = prefs.getFloat(HEIGHT_KEY, 0f)
|
||||||
|
return if (width <= 0f || height <= 0f) {
|
||||||
|
DpSize(800.dp, 600.dp)
|
||||||
|
} else {
|
||||||
|
DpSize(width.dp, height.dp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveSize(size: DpSize) {
|
||||||
|
prefs.putFloat(WIDTH_KEY, size.width.value)
|
||||||
|
prefs.putFloat(HEIGHT_KEY, size.height.value)
|
||||||
|
runCatching { prefs.flush() }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,6 +52,7 @@ import kotlin.concurrent.thread
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
import org.jetbrains.skia.Image
|
import org.jetbrains.skia.Image
|
||||||
@@ -232,7 +233,7 @@ fun main(args: Array<String>) {
|
|||||||
UtilsLibrary.init()
|
UtilsLibrary.init()
|
||||||
DesktopApplicationBootstrap.launchOnApplicationStart()
|
DesktopApplicationBootstrap.launchOnApplicationStart()
|
||||||
|
|
||||||
val windowState = rememberWindowState()
|
val windowState = rememberWindowState(size = remember { DesktopWindowPrefs.loadSize() })
|
||||||
val aboutWindowState = rememberWindowState(
|
val aboutWindowState = rememberWindowState(
|
||||||
position = WindowPosition.Aligned(Alignment.Center),
|
position = WindowPosition.Aligned(Alignment.Center),
|
||||||
size = DpSize(440.dp, 640.dp),
|
size = DpSize(440.dp, 640.dp),
|
||||||
@@ -249,6 +250,11 @@ fun main(args: Array<String>) {
|
|||||||
val trayShow = stringResource(Res.string.desktop_tray_show)
|
val trayShow = stringResource(Res.string.desktop_tray_show)
|
||||||
val quit = stringResource(Res.string.desktop_quit)
|
val quit = stringResource(Res.string.desktop_quit)
|
||||||
|
|
||||||
|
LaunchedEffect(windowState.size) {
|
||||||
|
delay(3_000)
|
||||||
|
DesktopWindowPrefs.saveSize(windowState.size)
|
||||||
|
}
|
||||||
|
|
||||||
DisposableEffect(trayState) {
|
DisposableEffect(trayState) {
|
||||||
DesktopNotifier.sink = { title, body ->
|
DesktopNotifier.sink = { title, body ->
|
||||||
trayState.sendNotification(
|
trayState.sendNotification(
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ import dev.chrisbanes.haze.blur.HazeBlurStyle
|
|||||||
import dev.chrisbanes.haze.blur.HazeColorEffect
|
import dev.chrisbanes.haze.blur.HazeColorEffect
|
||||||
import dev.chrisbanes.haze.blur.HazeProgressive
|
import dev.chrisbanes.haze.blur.HazeProgressive
|
||||||
import dev.chrisbanes.haze.blur.blurEffect
|
import dev.chrisbanes.haze.blur.blurEffect
|
||||||
|
import dev.chrisbanes.haze.blur.materials.HazeMaterials
|
||||||
import dev.chrisbanes.haze.hazeEffect
|
import dev.chrisbanes.haze.hazeEffect
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
import ru.fromchat.Res
|
import ru.fromchat.Res
|
||||||
@@ -425,8 +426,9 @@ fun ChatTopBar(
|
|||||||
/**
|
/**
|
||||||
* Two-pane chat chrome: separate back pill + title pill. Matches [ChatInput] composer chrome
|
* Two-pane chat chrome: separate back pill + title pill. Matches [ChatInput] composer chrome
|
||||||
* ([rememberChatSurfaceContainerHazeStyle] + [androidx.compose.material3.ColorScheme.surfaceContainer]).
|
* ([rememberChatSurfaceContainerHazeStyle] + [androidx.compose.material3.ColorScheme.surfaceContainer]).
|
||||||
* Full-bleed progressive haze strip behind the pills (high at top → fade toward bottom); pills keep
|
* Full-bleed progressive haze strip behind the pills uses [HazeMaterials.thin] (high at top → fade
|
||||||
* their own surfaceContainer + [hazeEffect]. Horizontal inset matches [ChatInput].
|
* toward bottom); pills keep surfaceContainer + [rememberChatSurfaceContainerHazeStyle].
|
||||||
|
* Horizontal inset matches [ChatInput].
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
private fun ChatTopBarPill(
|
private fun ChatTopBarPill(
|
||||||
@@ -441,6 +443,7 @@ private fun ChatTopBarPill(
|
|||||||
hazeBlurEnabled: Boolean = true,
|
hazeBlurEnabled: Boolean = true,
|
||||||
) {
|
) {
|
||||||
val hazeStyle = rememberChatSurfaceContainerHazeStyle()
|
val hazeStyle = rememberChatSurfaceContainerHazeStyle()
|
||||||
|
val progressiveStripHazeStyle = HazeMaterials.thin()
|
||||||
val chromeColor = MaterialTheme.colorScheme.surfaceContainer
|
val chromeColor = MaterialTheme.colorScheme.surfaceContainer
|
||||||
val pillShape = RoundedCornerShape(28.dp)
|
val pillShape = RoundedCornerShape(28.dp)
|
||||||
|
|
||||||
@@ -452,7 +455,7 @@ private fun ChatTopBarPill(
|
|||||||
.hazeEffect(state = hazeState) {
|
.hazeEffect(state = hazeState) {
|
||||||
blurEffect {
|
blurEffect {
|
||||||
blurEnabled = hazeBlurEnabled
|
blurEnabled = hazeBlurEnabled
|
||||||
style = hazeStyle
|
style = progressiveStripHazeStyle
|
||||||
progressive = HazeProgressive.verticalGradient(
|
progressive = HazeProgressive.verticalGradient(
|
||||||
startIntensity = 1f,
|
startIntensity = 1f,
|
||||||
endIntensity = 0f,
|
endIntensity = 0f,
|
||||||
|
|||||||
@@ -442,11 +442,15 @@ private fun ChatContextMenuBlurLayer(
|
|||||||
blurProgress: Float,
|
blurProgress: Float,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val blurRadius = 12.dp * blurProgress
|
val progress = blurProgress.coerceIn(0f, 1f)
|
||||||
|
val blurRadius = 12.dp * progress
|
||||||
if (blurRadius <= 0.dp) return
|
if (blurRadius <= 0.dp) return
|
||||||
|
|
||||||
|
// Opaque enough background so rounded chrome corners don't stay razor-sharp while
|
||||||
|
// interiors look frosted (Transparent + no tint left original AA edges unblurred).
|
||||||
// In-tree under the overlay (zIndex). Never use a Popup here: platform popups stack above
|
// In-tree under the overlay (zIndex). Never use a Popup here: platform popups stack above
|
||||||
// the sharp row/menu, blur them, and intercept dismiss taps.
|
// the sharp row/menu, blur them, and intercept dismiss taps.
|
||||||
|
val surface = MaterialTheme.colorScheme.surfaceContainerLowest
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
@@ -454,10 +458,12 @@ private fun ChatContextMenuBlurLayer(
|
|||||||
blurEffect {
|
blurEffect {
|
||||||
style = HazeBlurStyle(
|
style = HazeBlurStyle(
|
||||||
blurRadius = blurRadius,
|
blurRadius = blurRadius,
|
||||||
colorEffects = emptyList(),
|
backgroundColor = surface,
|
||||||
backgroundColor = Color.Transparent,
|
colorEffects = listOf(
|
||||||
|
HazeColorEffect.tint(surface.copy(alpha = 0.4f * progress)),
|
||||||
|
),
|
||||||
noiseFactor = 0f,
|
noiseFactor = 0f,
|
||||||
fallbackColorEffect = HazeColorEffect.tint(Color.Transparent),
|
fallbackColorEffect = HazeColorEffect.tint(surface.copy(alpha = 0.4f * progress)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -268,7 +268,6 @@ internal fun ChatConversationsList(
|
|||||||
publicChatSelected: Boolean,
|
publicChatSelected: Boolean,
|
||||||
selectedOtherUserIds: Set<Int>,
|
selectedOtherUserIds: Set<Int>,
|
||||||
contextMenuState: ChatContextMenuState,
|
contextMenuState: ChatContextMenuState,
|
||||||
overlayCloneReady: Boolean,
|
|
||||||
rowRevealProgress: Float,
|
rowRevealProgress: Float,
|
||||||
listContentPadding: PaddingValues = PaddingValues(0.dp),
|
listContentPadding: PaddingValues = PaddingValues(0.dp),
|
||||||
showSearchBar: Boolean = false,
|
showSearchBar: Boolean = false,
|
||||||
@@ -380,11 +379,11 @@ internal fun ChatConversationsList(
|
|||||||
selectionTransitionProgress = selectionTransitionProgress,
|
selectionTransitionProgress = selectionTransitionProgress,
|
||||||
isSelected = publicChatSelected,
|
isSelected = publicChatSelected,
|
||||||
isHiddenForOverlay = contextMenuState.listIndex == ChatListLayout.PUBLIC_CHAT_ROW &&
|
isHiddenForOverlay = contextMenuState.listIndex == ChatListLayout.PUBLIC_CHAT_ROW &&
|
||||||
contextMenuState.isOverlayReplicaActive &&
|
contextMenuState.isOverlayReplicaActive,
|
||||||
overlayCloneReady,
|
|
||||||
isPressingForContextMenu = contextMenuState.listIndex == ChatListLayout.PUBLIC_CHAT_ROW &&
|
isPressingForContextMenu = contextMenuState.listIndex == ChatListLayout.PUBLIC_CHAT_ROW &&
|
||||||
contextMenuState.phase == ChatContextMenuPhase.Pressing,
|
contextMenuState.phase == ChatContextMenuPhase.Pressing,
|
||||||
contextMenuPressScaleActive = contextMenuState.phase == ChatContextMenuPhase.Animating &&
|
contextMenuPressScaleActive = contextMenuState.listIndex == ChatListLayout.PUBLIC_CHAT_ROW &&
|
||||||
|
contextMenuState.phase == ChatContextMenuPhase.Animating &&
|
||||||
!contextMenuState.animatingOut,
|
!contextMenuState.animatingOut,
|
||||||
rowRevealProgress = if (contextMenuState.listIndex == ChatListLayout.PUBLIC_CHAT_ROW) {
|
rowRevealProgress = if (contextMenuState.listIndex == ChatListLayout.PUBLIC_CHAT_ROW) {
|
||||||
rowRevealProgress
|
rowRevealProgress
|
||||||
@@ -461,11 +460,11 @@ internal fun ChatConversationsList(
|
|||||||
selectionTransitionProgress = selectionTransitionProgress,
|
selectionTransitionProgress = selectionTransitionProgress,
|
||||||
isSelected = conversation.otherUserId in selectedOtherUserIds,
|
isSelected = conversation.otherUserId in selectedOtherUserIds,
|
||||||
isHiddenForOverlay = contextMenuState.listIndex == lazyIndex &&
|
isHiddenForOverlay = contextMenuState.listIndex == lazyIndex &&
|
||||||
contextMenuState.isOverlayReplicaActive &&
|
contextMenuState.isOverlayReplicaActive,
|
||||||
overlayCloneReady,
|
|
||||||
isPressingForContextMenu = contextMenuState.listIndex == lazyIndex &&
|
isPressingForContextMenu = contextMenuState.listIndex == lazyIndex &&
|
||||||
contextMenuState.phase == ChatContextMenuPhase.Pressing,
|
contextMenuState.phase == ChatContextMenuPhase.Pressing,
|
||||||
contextMenuPressScaleActive = contextMenuState.phase == ChatContextMenuPhase.Animating &&
|
contextMenuPressScaleActive = contextMenuState.listIndex == lazyIndex &&
|
||||||
|
contextMenuState.phase == ChatContextMenuPhase.Animating &&
|
||||||
!contextMenuState.animatingOut,
|
!contextMenuState.animatingOut,
|
||||||
rowRevealProgress = if (contextMenuState.listIndex == lazyIndex) {
|
rowRevealProgress = if (contextMenuState.listIndex == lazyIndex) {
|
||||||
rowRevealProgress
|
rowRevealProgress
|
||||||
|
|||||||
@@ -103,8 +103,6 @@ class ChatContextMenuOverlayController {
|
|||||||
var blurProgress by mutableFloatStateOf(0f)
|
var blurProgress by mutableFloatStateOf(0f)
|
||||||
/** Shared row scale progress (0 = pressed, 1 = full) for overlay ↔ list handoff. */
|
/** Shared row scale progress (0 = pressed, 1 = full) for overlay ↔ list handoff. */
|
||||||
var rowRevealProgress by mutableFloatStateOf(0f)
|
var rowRevealProgress by mutableFloatStateOf(0f)
|
||||||
/** True once the overlay row clone has been composed and positioned. */
|
|
||||||
var overlayCloneReady by mutableStateOf(false)
|
|
||||||
var onStateChange: (ChatContextMenuState) -> Unit = {}
|
var onStateChange: (ChatContextMenuState) -> Unit = {}
|
||||||
var onDismiss: () -> Unit = {}
|
var onDismiss: () -> Unit = {}
|
||||||
var onMessage: () -> Unit = {}
|
var onMessage: () -> Unit = {}
|
||||||
@@ -114,12 +112,10 @@ class ChatContextMenuOverlayController {
|
|||||||
var onMarkPublicRead: () -> Unit = {}
|
var onMarkPublicRead: () -> Unit = {}
|
||||||
var onDelete: (Int) -> Unit = {}
|
var onDelete: (Int) -> Unit = {}
|
||||||
var onSelect: () -> Unit = {}
|
var onSelect: () -> Unit = {}
|
||||||
var onOverlayCloneReady: () -> Unit = {}
|
|
||||||
|
|
||||||
fun clear() {
|
fun clear() {
|
||||||
uiState = null
|
uiState = null
|
||||||
blurProgress = 0f
|
blurProgress = 0f
|
||||||
rowRevealProgress = 0f
|
rowRevealProgress = 0f
|
||||||
overlayCloneReady = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -829,7 +829,6 @@ fun ChatsTab(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
val rowRevealProgress = chatContextMenuOverlay.rowRevealProgress
|
val rowRevealProgress = chatContextMenuOverlay.rowRevealProgress
|
||||||
val overlayCloneReady = chatContextMenuOverlay.overlayCloneReady
|
|
||||||
val callsEnabled = ServerConfig.callsEnabled
|
val callsEnabled = ServerConfig.callsEnabled
|
||||||
|
|
||||||
fun markSelectedChatsRead() {
|
fun markSelectedChatsRead() {
|
||||||
@@ -968,7 +967,6 @@ fun ChatsTab(
|
|||||||
publicChatSelected = publicChatSelected,
|
publicChatSelected = publicChatSelected,
|
||||||
selectedOtherUserIds = selectedOtherUserIds,
|
selectedOtherUserIds = selectedOtherUserIds,
|
||||||
contextMenuState = contextMenuState,
|
contextMenuState = contextMenuState,
|
||||||
overlayCloneReady = overlayCloneReady,
|
|
||||||
rowRevealProgress = rowRevealProgress,
|
rowRevealProgress = rowRevealProgress,
|
||||||
listContentPadding = PaddingValues(top = fixedTopBarHeight),
|
listContentPadding = PaddingValues(top = fixedTopBarHeight),
|
||||||
showSearchBar = true,
|
showSearchBar = true,
|
||||||
@@ -1033,7 +1031,6 @@ fun ChatsTab(
|
|||||||
return@ChatConversationsList
|
return@ChatConversationsList
|
||||||
}
|
}
|
||||||
haptic(HapticFeedbackEvent.ContextMenuOpened)
|
haptic(HapticFeedbackEvent.ContextMenuOpened)
|
||||||
chatContextMenuOverlay.overlayCloneReady = false
|
|
||||||
contextMenuState = ChatContextMenuState(
|
contextMenuState = ChatContextMenuState(
|
||||||
phase = ChatContextMenuPhase.Animating,
|
phase = ChatContextMenuPhase.Animating,
|
||||||
target = target,
|
target = target,
|
||||||
@@ -1049,7 +1046,6 @@ fun ChatsTab(
|
|||||||
if (suspensionState.isSuspended) return@ChatConversationsList
|
if (suspensionState.isSuspended) return@ChatConversationsList
|
||||||
haptic(HapticFeedbackEvent.ContextMenuOpened)
|
haptic(HapticFeedbackEvent.ContextMenuOpened)
|
||||||
avatarPressMark = null
|
avatarPressMark = null
|
||||||
chatContextMenuOverlay.overlayCloneReady = false
|
|
||||||
contextMenuState = ChatContextMenuState(
|
contextMenuState = ChatContextMenuState(
|
||||||
phase = ChatContextMenuPhase.Animating,
|
phase = ChatContextMenuPhase.Animating,
|
||||||
target = target,
|
target = target,
|
||||||
@@ -1185,9 +1181,6 @@ fun ChatsTab(
|
|||||||
animatingOut = true,
|
animatingOut = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
chatContextMenuOverlay.onOverlayCloneReady = {
|
|
||||||
chatContextMenuOverlay.overlayCloneReady = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val shouldPublishOverlay = isVisible &&
|
val shouldPublishOverlay = isVisible &&
|
||||||
contextMenuState.isOverlayReplicaActive &&
|
contextMenuState.isOverlayReplicaActive &&
|
||||||
@@ -1215,19 +1208,10 @@ fun ChatsTab(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
if (chatContextMenuOverlay.uiState != overlayUiState) {
|
if (chatContextMenuOverlay.uiState != overlayUiState) {
|
||||||
val previousOverlay = chatContextMenuOverlay.uiState
|
|
||||||
chatContextMenuOverlay.uiState = overlayUiState
|
chatContextMenuOverlay.uiState = overlayUiState
|
||||||
if (overlayUiState == null) {
|
if (overlayUiState == null) {
|
||||||
chatContextMenuOverlay.blurProgress = 0f
|
chatContextMenuOverlay.blurProgress = 0f
|
||||||
chatContextMenuOverlay.rowRevealProgress = 0f
|
chatContextMenuOverlay.rowRevealProgress = 0f
|
||||||
chatContextMenuOverlay.overlayCloneReady = false
|
|
||||||
} else {
|
|
||||||
val isNewOverlaySession = previousOverlay == null ||
|
|
||||||
previousOverlay.contextMenuState.listIndex != overlayUiState.contextMenuState.listIndex ||
|
|
||||||
!previousOverlay.contextMenuState.isOverlayReplicaActive
|
|
||||||
if (isNewOverlaySession) {
|
|
||||||
chatContextMenuOverlay.overlayCloneReady = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1277,7 +1261,6 @@ internal fun ChatContextMenuOverlayHost(
|
|||||||
uiState.contextMenuState.otherUserId?.let(controller.onDelete)
|
uiState.contextMenuState.otherUserId?.let(controller.onDelete)
|
||||||
},
|
},
|
||||||
onSelect = controller.onSelect,
|
onSelect = controller.onSelect,
|
||||||
onOverlayCloneReady = controller.onOverlayCloneReady,
|
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1297,7 +1280,6 @@ private fun ChatContextMenuOverlay(
|
|||||||
onMarkRead: () -> Unit,
|
onMarkRead: () -> Unit,
|
||||||
onDelete: () -> Unit,
|
onDelete: () -> Unit,
|
||||||
onSelect: () -> Unit,
|
onSelect: () -> Unit,
|
||||||
onOverlayCloneReady: () -> Unit,
|
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val contextMenuState = uiState.contextMenuState
|
val contextMenuState = uiState.contextMenuState
|
||||||
@@ -1503,17 +1485,6 @@ private fun ChatContextMenuOverlay(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(
|
|
||||||
layoutReady,
|
|
||||||
contextMenuState.listIndex,
|
|
||||||
contextMenuState.target,
|
|
||||||
contextMenuState.otherUserId,
|
|
||||||
) {
|
|
||||||
if (layoutReady && contextMenuState.isOverlayReplicaActive) {
|
|
||||||
onOverlayCloneReady()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun requestDismiss() {
|
fun requestDismiss() {
|
||||||
when (contextMenuState.phase) {
|
when (contextMenuState.phase) {
|
||||||
ChatContextMenuPhase.Open -> {
|
ChatContextMenuPhase.Open -> {
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
package ru.fromchat.ui.main.settings
|
package ru.fromchat.ui.main.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.AccountCircle
|
import androidx.compose.material.icons.filled.AccountCircle
|
||||||
import androidx.compose.material.icons.filled.Devices
|
import androidx.compose.material.icons.filled.Devices
|
||||||
import androidx.compose.material.icons.filled.Info
|
import androidx.compose.material.icons.filled.Info
|
||||||
import androidx.compose.material.icons.filled.Notifications
|
import androidx.compose.material.icons.filled.Notifications
|
||||||
import androidx.compose.material.icons.filled.Person
|
|
||||||
import androidx.compose.material.icons.outlined.BugReport
|
|
||||||
import androidx.compose.material.icons.filled.Palette
|
import androidx.compose.material.icons.filled.Palette
|
||||||
|
import androidx.compose.material.icons.filled.Person
|
||||||
import androidx.compose.material.icons.filled.Storage
|
import androidx.compose.material.icons.filled.Storage
|
||||||
|
import androidx.compose.material.icons.outlined.BugReport
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import ru.fromchat.ui.components.Text
|
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -31,12 +34,17 @@ import com.pr0gramm3r101.utils.WindowWidthSizeClass
|
|||||||
import com.pr0gramm3r101.utils.currentWindowAdaptiveInfo
|
import com.pr0gramm3r101.utils.currentWindowAdaptiveInfo
|
||||||
import com.pr0gramm3r101.utils.verticalScroll
|
import com.pr0gramm3r101.utils.verticalScroll
|
||||||
import com.pr0gramm3r101.utils.widthSizeClass
|
import com.pr0gramm3r101.utils.widthSizeClass
|
||||||
|
import dev.chrisbanes.haze.blur.blurEffect
|
||||||
|
import dev.chrisbanes.haze.hazeEffect
|
||||||
|
import dev.chrisbanes.haze.hazeSource
|
||||||
|
import dev.chrisbanes.haze.rememberHazeState
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
import ru.fromchat.Res
|
import ru.fromchat.Res
|
||||||
import ru.fromchat.about
|
import ru.fromchat.about
|
||||||
import ru.fromchat.api.ApiClient
|
import ru.fromchat.api.ApiClient
|
||||||
import ru.fromchat.change_server
|
import ru.fromchat.change_server
|
||||||
import ru.fromchat.change_server_d
|
import ru.fromchat.change_server_d
|
||||||
|
import ru.fromchat.logs_title
|
||||||
import ru.fromchat.profile
|
import ru.fromchat.profile
|
||||||
import ru.fromchat.settings
|
import ru.fromchat.settings
|
||||||
import ru.fromchat.settings_category_account
|
import ru.fromchat.settings_category_account
|
||||||
@@ -47,11 +55,12 @@ import ru.fromchat.settings_category_devices
|
|||||||
import ru.fromchat.settings_category_devices_d
|
import ru.fromchat.settings_category_devices_d
|
||||||
import ru.fromchat.settings_category_notifications
|
import ru.fromchat.settings_category_notifications
|
||||||
import ru.fromchat.settings_category_notifications_d
|
import ru.fromchat.settings_category_notifications_d
|
||||||
import ru.fromchat.logs_title
|
|
||||||
import ru.fromchat.settings_hub_about_sub
|
import ru.fromchat.settings_hub_about_sub
|
||||||
import ru.fromchat.settings_hub_logs_sub
|
import ru.fromchat.settings_hub_logs_sub
|
||||||
import ru.fromchat.settings_hub_profile_sub
|
import ru.fromchat.settings_hub_profile_sub
|
||||||
import ru.fromchat.ui.LocalNavController
|
import ru.fromchat.ui.LocalNavController
|
||||||
|
import ru.fromchat.ui.chat.rememberChatSurfaceContainerHazeStyle
|
||||||
|
import ru.fromchat.ui.components.Text
|
||||||
import ru.fromchat.ui.extraStatusBars
|
import ru.fromchat.ui.extraStatusBars
|
||||||
import ru.fromchat.ui.main.LocalMainChromeInsets
|
import ru.fromchat.ui.main.LocalMainChromeInsets
|
||||||
import ru.fromchat.ui.main.mainPagerBottomInset
|
import ru.fromchat.ui.main.mainPagerBottomInset
|
||||||
@@ -64,6 +73,9 @@ val SettingsStepHorizontalPadding = 24.dp
|
|||||||
fun SettingsTab() {
|
fun SettingsTab() {
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
val isTwoPane = currentWindowAdaptiveInfo().widthSizeClass != WindowWidthSizeClass.COMPACT
|
val isTwoPane = currentWindowAdaptiveInfo().widthSizeClass != WindowWidthSizeClass.COMPACT
|
||||||
|
val topChromeHazeState = rememberHazeState()
|
||||||
|
// Same material as MainScreen bottom nav (not HazeMaterials.thin).
|
||||||
|
val topChromeHazeStyle = rememberChatSurfaceContainerHazeStyle()
|
||||||
|
|
||||||
fun openDetail(route: String) {
|
fun openDetail(route: String) {
|
||||||
navController.navigateReplacingMainDetail(
|
navController.navigateReplacingMainDetail(
|
||||||
@@ -75,6 +87,7 @@ fun SettingsTab() {
|
|||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
containerColor = Color.Transparent,
|
containerColor = Color.Transparent,
|
||||||
|
contentColor = MaterialTheme.colorScheme.onSurface,
|
||||||
contentWindowInsets = WindowInsets(0, 0, 0, 0),
|
contentWindowInsets = WindowInsets(0, 0, 0, 0),
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
@@ -89,16 +102,27 @@ fun SettingsTab() {
|
|||||||
colors = TopAppBarDefaults.topAppBarColors(
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
containerColor = Color.Transparent,
|
containerColor = Color.Transparent,
|
||||||
),
|
),
|
||||||
|
// Match MainScreen bottom chrome: surfaceContainer + hazeEffect/blurEffect.
|
||||||
|
modifier = Modifier
|
||||||
|
.background(MaterialTheme.colorScheme.surfaceContainer)
|
||||||
|
.hazeEffect(state = topChromeHazeState) {
|
||||||
|
blurEffect {
|
||||||
|
style = topChromeHazeStyle
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
Column(
|
Column(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
.hazeSource(topChromeHazeState)
|
||||||
.verticalScroll()
|
.verticalScroll()
|
||||||
.mainPagerBottomInset()
|
.mainPagerBottomInset()
|
||||||
.padding(innerPadding)
|
|
||||||
) {
|
) {
|
||||||
|
// Scrollable top inset so rows can pass under the frosted top chrome.
|
||||||
|
Spacer(Modifier.height(innerPadding.calculateTopPadding()))
|
||||||
|
|
||||||
if (isTwoPane) {
|
if (isTwoPane) {
|
||||||
Category(Modifier.padding(top = 16.dp)) {
|
Category(Modifier.padding(top = 16.dp)) {
|
||||||
ListItem(
|
ListItem(
|
||||||
|
|||||||
@@ -681,7 +681,12 @@ fun ListItem(
|
|||||||
),
|
),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
leadingContent()
|
// Material list leadingIconColor default: onSurfaceVariant
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
) {
|
||||||
|
leadingContent()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user