From 4c99423826df3aaf9bb192f18f0e1bf2636a9b46 Mon Sep 17 00:00:00 2001 From: Avently <7953703+avently@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:34:35 +0700 Subject: [PATCH] changes --- .../platform/ScrollableColumn.android.kt | 54 +------ .../kotlin/chat/simplex/common/App.kt | 6 +- .../common/platform/ScrollableColumn.kt | 3 +- .../chat/simplex/common/ui/theme/Theme.kt | 20 ++- .../chat/simplex/common/views/WelcomeView.kt | 7 +- .../simplex/common/views/chat/ChatView.kt | 26 ++-- .../common/views/chatlist/ChatListView.kt | 1 - .../common/views/helpers/BlurModifier.kt | 147 ++++++++++++++++++ .../common/views/helpers/ChatWallpaper.kt | 93 ++++++----- .../common/views/helpers/CollapsingAppBar.kt | 59 ++++++- .../common/views/helpers/DefaultTopAppBar.kt | 27 +--- .../simplex/common/views/helpers/ModalView.kt | 18 +-- .../views/onboarding/CreateSimpleXAddress.kt | 95 ++++++----- .../views/onboarding/LinkAMobileView.kt | 2 +- .../views/onboarding/SetNotificationsMode.kt | 7 +- .../onboarding/SetupDatabasePassphrase.kt | 7 +- .../common/views/onboarding/SimpleXInfo.kt | 18 ++- .../common/views/usersettings/Appearance.kt | 9 +- .../kotlin/chat/simplex/common/DesktopApp.kt | 4 +- .../platform/ScrollableColumn.desktop.kt | 51 +----- 20 files changed, 371 insertions(+), 283 deletions(-) create mode 100644 apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/BlurModifier.kt diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/ScrollableColumn.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/ScrollableColumn.android.kt index f55565e525..e54839d102 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/ScrollableColumn.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/ScrollableColumn.android.kt @@ -7,15 +7,11 @@ import androidx.compose.foundation.lazy.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawWithContent -import androidx.compose.ui.graphics.layer.drawLayer -import androidx.compose.ui.graphics.rememberGraphicsLayer import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.ui.theme.DEFAULT_PADDING -import chat.simplex.common.ui.theme.themedBackground import chat.simplex.common.views.chatlist.NavigationBarBackground import chat.simplex.common.views.helpers.* import kotlinx.coroutines.flow.filter @@ -24,7 +20,6 @@ import kotlin.math.absoluteValue @Composable actual fun LazyColumnWithScrollBar( modifier: Modifier, - backgroundModifier: Modifier, state: LazyListState?, contentPadding: PaddingValues, reverseLayout: Boolean, @@ -65,24 +60,11 @@ actual fun LazyColumnWithScrollBar( } } } - val graphicsLayer = rememberGraphicsLayer() - val blurRadius = remember { appPrefs.appearanceBarsBlurRadius.state } - val drawScreenshot = remember(blurRadius.value > 0, backgroundModifier) { - if (blurRadius.value > 0) { - Modifier.drawWithContent { - graphicsLayer.record { - this@drawWithContent.drawContent() - } - drawLayer(graphicsLayer) - handler.graphicsLayerSize.value = graphicsLayer.size - }.then(backgroundModifier) - } else Modifier - } LazyColumn( if (fillMaxSize) { - Modifier.fillMaxSize().then(modifier).then(drawScreenshot).nestedScroll(connection) + Modifier.fillMaxSize().copyViewToAppBar(LocalAppBarHandler.current?.graphicsLayer).then(modifier).nestedScroll(connection) } else { - modifier.then(drawScreenshot).nestedScroll(connection) + Modifier.copyViewToAppBar(LocalAppBarHandler.current?.graphicsLayer).then(modifier).nestedScroll(connection) }, state, contentPadding, @@ -94,13 +76,6 @@ actual fun LazyColumnWithScrollBar( ) { content() } - /** setting it in composition scope because in Disposable effect it comes too late and other side [DefaultTopAppBar] doesn't see it in time */ - handler.graphicsLayer = graphicsLayer - DisposableEffect(Unit) { - onDispose { - handler.graphicsLayer = null - } - } } @@ -126,7 +101,6 @@ actual fun LazyColumnWithScrollBarNoAppBar( @Composable actual fun ColumnWithScrollBar( modifier: Modifier, - backgroundModifier: Modifier, verticalArrangement: Arrangement.Vertical, horizontalAlignment: Alignment.Horizontal, state: ScrollState?, @@ -152,31 +126,11 @@ actual fun ColumnWithScrollBar( } val oneHandUI = remember { appPrefs.oneHandUI.state } Box(Modifier.fillMaxHeight()) { - val graphicsLayer = rememberGraphicsLayer() - val blurRadius = remember { appPrefs.appearanceBarsBlurRadius.state } - val drawScreenshot = remember(blurRadius.value > 0, backgroundModifier) { - if (blurRadius.value > 0) { - Modifier.drawWithContent { - graphicsLayer.record { - this@drawWithContent.drawContent() - } - drawLayer(graphicsLayer) - handler.graphicsLayerSize.value = graphicsLayer.size - }.then(backgroundModifier) - } else Modifier - } - /** setting it in composition scope because in Disposable effect it comes too late and other side [DefaultTopAppBar] doesn't see it in time */ - handler.graphicsLayer = graphicsLayer - DisposableEffect(Unit) { - onDispose { - handler.graphicsLayer = null - } - } Column( if (maxIntrinsicSize) { - modifier.then(drawScreenshot).nestedScroll(connection).verticalScroll(state).height(IntrinsicSize.Max) + Modifier.copyViewToAppBar(LocalAppBarHandler.current?.graphicsLayer).then(modifier).nestedScroll(connection).verticalScroll(state).height(IntrinsicSize.Max) } else { - modifier.then(drawScreenshot).nestedScroll(connection).verticalScroll(state) + Modifier.copyViewToAppBar(LocalAppBarHandler.current?.graphicsLayer).then(modifier).nestedScroll(connection).verticalScroll(state) }, verticalArrangement, horizontalAlignment ) { if (oneHandUI.value) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt index 8ca0da0d21..3c61c99fbc 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt @@ -349,17 +349,17 @@ fun AndroidScreen(userPickerState: MutableStateFlow) { @Composable fun StartPartOfScreen(userPickerState: MutableStateFlow) { if (chatModel.setDeliveryReceipts.value) { - CompositionLocalProvider(LocalAppBarHandler provides remember { AppBarHandler() }) { + CompositionLocalProvider(LocalAppBarHandler provides rememberAppBarHandler()) { SetDeliveryReceiptsView(chatModel) } } else { val stopped = chatModel.chatRunning.value == false if (chatModel.sharedContent.value == null) { - CompositionLocalProvider(LocalAppBarHandler provides remember { AppBarHandler() }) { + CompositionLocalProvider(LocalAppBarHandler provides rememberAppBarHandler()) { ChatListView(chatModel, userPickerState, AppLock::setPerformLA, stopped) } } else { - CompositionLocalProvider(LocalAppBarHandler provides remember { AppBarHandler() }) { + CompositionLocalProvider(LocalAppBarHandler provides rememberAppBarHandler()) { ShareListView(chatModel, stopped) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/ScrollableColumn.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/ScrollableColumn.kt index 6abef86bf4..5e6e43af6a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/ScrollableColumn.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/ScrollableColumn.kt @@ -11,11 +11,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import chat.simplex.common.ui.theme.themedBackground +import chat.simplex.common.views.helpers.LocalAppBarHandler @Composable expect fun LazyColumnWithScrollBar( modifier: Modifier = Modifier, - backgroundModifier: Modifier = Modifier.themedBackground(), state: LazyListState? = null, contentPadding: PaddingValues = PaddingValues(0.dp), reverseLayout: Boolean = false, @@ -49,7 +49,6 @@ expect fun LazyColumnWithScrollBarNoAppBar( @Composable expect fun ColumnWithScrollBar( modifier: Modifier = Modifier, - backgroundModifier: Modifier = Modifier.themedBackground(), verticalArrangement: Arrangement.Vertical = Arrangement.Top, horizontalAlignment: Alignment.Horizontal = Alignment.Start, state: ScrollState? = null, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt index ba421b7720..80542ced02 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/ui/theme/Theme.kt @@ -1,14 +1,14 @@ package chat.simplex.common.ui.theme -import androidx.compose.foundation.background import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.* +import androidx.compose.ui.graphics.layer.GraphicsLayer import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.unit.Density -import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.* import chat.simplex.common.model.ChatController import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.platform.* @@ -587,11 +587,15 @@ data class ThemeModeOverride ( } } -fun Modifier.themedBackground(baseTheme: DefaultTheme = CurrentColors.value.base, shape: Shape = RectangleShape): Modifier { - return if (baseTheme == DefaultTheme.SIMPLEX) { - this.background(brush = themedBackgroundBrush(), shape = shape) - } else { - this.background(color = CurrentColors.value.colors.background, shape = shape) +fun Modifier.themedBackground(baseTheme: DefaultTheme = CurrentColors.value.base, bgLayerSize: MutableState?, bgLayer: GraphicsLayer?/*, shape: Shape = RectangleShape*/): Modifier { + return drawBehind { + copyBackgroundToAppBar(bgLayerSize, bgLayer) { + if (baseTheme == DefaultTheme.SIMPLEX) { + drawRect(brush = themedBackgroundBrush()) + } else { + drawRect(CurrentColors.value.colors.background) + } + } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt index 7d5d5354f0..fadb873773 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt @@ -106,14 +106,11 @@ fun CreateFirstProfile(chatModel: ChatModel, close: () -> Unit) { val scrollState = rememberScrollState() val keyboardState by getKeyboardState() var savedKeyboardState by remember { mutableStateOf(keyboardState) } - val handler = remember { AppBarHandler() } - CompositionLocalProvider( - LocalAppBarHandler provides handler - ) { + CompositionLocalProvider(LocalAppBarHandler provides rememberAppBarHandler()) { Column( modifier = Modifier .fillMaxSize() - .themedBackground(), + .themedBackground(bgLayerSize = LocalAppBarHandler.current?.backgroundGraphicsLayerSize, bgLayer = LocalAppBarHandler.current?.backgroundGraphicsLayer), horizontalAlignment = Alignment.CenterHorizontally ) { DefaultTopAppBar( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index 527a99a487..c139d4645b 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -12,9 +12,9 @@ import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.* -import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.drawWithCache +import androidx.compose.ui.draw.* import androidx.compose.ui.graphics.* +import androidx.compose.ui.graphics.layer.GraphicsLayer import androidx.compose.ui.layout.layoutId import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.* @@ -109,7 +109,7 @@ fun ChatView(staleChatId: State, onComposed: suspend (chatId: String) - } } val clipboard = LocalClipboardManager.current - CompositionLocalProvider(LocalAppBarHandler provides remember(chatInfo.chatType) { AppBarHandler() }) { + CompositionLocalProvider(LocalAppBarHandler provides rememberAppBarHandler(chatInfo.id, keyboardCoversBar = false)) { when (chatInfo) { is ChatInfo.Direct, is ChatInfo.Group, is ChatInfo.Local -> { val perChatTheme = remember(chatInfo, CurrentColors.value.base) { if (chatInfo is ChatInfo.Direct) chatInfo.contact.uiThemes?.preferredMode(!CurrentColors.value.colors.isLight) else if (chatInfo is ChatInfo.Group) chatInfo.groupInfo.uiThemes?.preferredMode(!CurrentColors.value.colors.isLight) else null } @@ -642,11 +642,7 @@ fun ChatLayout( ) { println("LALAL RELOAD MODAL") val composeViewHeight = remember { mutableStateOf(0.dp) } - Box( - Modifier - .fillMaxSize() - .chatViewBackgroundModifier(MaterialTheme.colors, MaterialTheme.wallpaper) - ) { + Box(Modifier.fillMaxSize().chatViewBackgroundModifier(MaterialTheme.colors, MaterialTheme.wallpaper, LocalAppBarHandler.current?.backgroundGraphicsLayerSize, LocalAppBarHandler.current?.backgroundGraphicsLayer)) { val remoteHostId = remember { remoteHostId }.value val chatInfo = remember { chatInfo }.value AdaptingBottomPaddingLayout(Modifier, CHAT_COMPOSE_LAYOUT_ID, composeViewHeight) { @@ -1000,7 +996,6 @@ fun BoxScope.ChatItemsList( ) LazyColumnWithScrollBar( Modifier.align(Alignment.BottomCenter), - backgroundModifier = Modifier.chatViewBackgroundModifier(MaterialTheme.colors, MaterialTheme.wallpaper), state = listState, reverseLayout = true, contentPadding = PaddingValues( @@ -1849,17 +1844,22 @@ private fun memberNames(member: GroupMember, prevMember: GroupMember?, memCount: } } -fun Modifier.chatViewBackgroundModifier(colors: Colors, wallpaper: AppWallpaper): Modifier { +fun Modifier.chatViewBackgroundModifier( + colors: Colors, + wallpaper: AppWallpaper, + backgroundGraphicsLayerSize: MutableState?, + backgroundGraphicsLayer: GraphicsLayer? +): Modifier { val wallpaperImage = wallpaper.type.image val wallpaperType = wallpaper.type val backgroundColor = wallpaper.background ?: wallpaperType.defaultBackgroundColor(CurrentColors.value.base, colors.background) val tintColor = wallpaper.tint ?: wallpaperType.defaultTintColor(CurrentColors.value.base) - return this.background(colors.background) + return this .then(if (wallpaperImage != null) - Modifier.drawWithCache { chatViewBackground(wallpaperImage, wallpaperType, backgroundColor, tintColor) } + Modifier.drawWithCache { chatViewBackground(wallpaperImage, wallpaperType, backgroundColor, tintColor, backgroundGraphicsLayerSize, backgroundGraphicsLayer) } else - Modifier + Modifier.drawWithCache { onDrawBehind { copyBackgroundToAppBar(backgroundGraphicsLayerSize, backgroundGraphicsLayer) { drawRect(backgroundColor) } } } ) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt index 7057eca8b7..d36324f870 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt @@ -667,7 +667,6 @@ private fun BoxScope.ChatList(searchText: MutableState, listStat val blankSpaceSize = if (oneHandUI.value) WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + AppBarHeight * fontSizeSqrtMultiplier else topPaddingToContent LazyColumnWithScrollBar( if (!oneHandUI.value) Modifier.imePadding() else Modifier, - backgroundModifier = Modifier.background(MaterialTheme.colors.background), listState, reverseLayout = oneHandUI.value ) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/BlurModifier.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/BlurModifier.kt new file mode 100644 index 0000000000..e52a8dacea --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/BlurModifier.kt @@ -0,0 +1,147 @@ +package chat.simplex.common.views.helpers + +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.* +import androidx.compose.ui.graphics.drawscope.clipRect +import androidx.compose.ui.graphics.drawscope.translate +import androidx.compose.ui.graphics.layer.GraphicsLayer +import androidx.compose.ui.graphics.layer.drawLayer +import androidx.compose.ui.unit.* +import chat.simplex.common.platform.appPlatform +import chat.simplex.common.ui.theme.CurrentColors + +@Composable +fun Modifier.blurredBackgroundModifier( + keyboardInset: WindowInsets, + handler: AppBarHandler?, + blurRadius: State, + prefAlpha: Float, + keyboardCoversBar: Boolean, + onTop: Boolean, + density: Density +): Modifier { + val graphicsLayer = handler?.graphicsLayer + val backgroundGraphicsLayer = handler?.backgroundGraphicsLayer + val backgroundGraphicsLayerSize = handler?.backgroundGraphicsLayerSize + if (!(handler != null && graphicsLayer != null && backgroundGraphicsLayer != null && blurRadius.value > 0 && prefAlpha < 1f && backgroundGraphicsLayerSize != null)) + return this + + return if (appPlatform.isAndroid) { + this.androidBlurredModifier(keyboardInset, blurRadius, keyboardCoversBar, onTop, graphicsLayer, backgroundGraphicsLayer, backgroundGraphicsLayerSize, density) + } else { + this.desktopBlurredModifier(keyboardInset, blurRadius, keyboardCoversBar, onTop, graphicsLayer, backgroundGraphicsLayer, backgroundGraphicsLayerSize, density) + } +} + +@Composable +fun Modifier.androidBlurredModifier( + keyboardInset: WindowInsets, + blurRadius: State, + keyboardCoversBar: Boolean, + onTop: Boolean, + graphicsLayer: GraphicsLayer, + backgroundGraphicsLayer: GraphicsLayer, + backgroundGraphicsLayerSize: State, + density: Density +): Modifier = this + .graphicsLayer { + renderEffect = if (blurRadius.value > 0) BlurEffect(blurRadius.value.dp.toPx(), blurRadius.value.dp.toPx()) else null + clip = blurRadius.value > 0 + } + .graphicsLayer { + if (!onTop) { + val bgSize = when { + backgroundGraphicsLayerSize.value.height == 0 && backgroundGraphicsLayer.size.height != 0 -> backgroundGraphicsLayer.size.height + backgroundGraphicsLayerSize.value.height == 0 -> graphicsLayer.size.height + else -> backgroundGraphicsLayerSize.value.height + } + println("LALAL GRAPHICSLAYER ${graphicsLayer.size.height} ${backgroundGraphicsLayer.size.height} ${backgroundGraphicsLayerSize.value.height}") + val keyboardHeightCovered = if (!keyboardCoversBar) keyboardInset.getBottom(density) else 0 + translationY = -bgSize + size.height + keyboardHeightCovered + } + } + .drawBehind { + drawRect(Color.Black) + if (onTop) { + println("LALAL DRAWBEHIND0") + clipRect { + if (backgroundGraphicsLayer.size != IntSize.Zero) { + drawLayer(backgroundGraphicsLayer) + } else { + drawRect(CurrentColors.value.colors.background, size = Size(graphicsLayer.size.width.toFloat(), graphicsLayer.size.height.toFloat())) + } + drawLayer(graphicsLayer) + } + } else { + println("LALAL DRAWBEHIND1 ${graphicsLayer.size.height} ${backgroundGraphicsLayer.size.height} ${backgroundGraphicsLayerSize.value}") + if (backgroundGraphicsLayer.size != IntSize.Zero) { + drawLayer(backgroundGraphicsLayer) + } else { + drawRect(CurrentColors.value.colors.background, size = Size(graphicsLayer.size.width.toFloat(), graphicsLayer.size.height.toFloat())) + } + drawLayer(graphicsLayer) + } + } + +@Composable +fun Modifier.desktopBlurredModifier( + keyboardInset: WindowInsets, + blurRadius: State, + keyboardCoversBar: Boolean, + onTop: Boolean, + graphicsLayer: GraphicsLayer, + backgroundGraphicsLayer: GraphicsLayer, + backgroundGraphicsLayerSize: State, + density: Density +): Modifier = this + .graphicsLayer { + renderEffect = if (blurRadius.value > 0) BlurEffect(blurRadius.value.dp.toPx(), blurRadius.value.dp.toPx()) else null + clip = blurRadius.value > 0 + } +// .graphicsLayer { +// if (!onTop) { +// val bgSize = when { +// backgroundGraphicsLayerSize.value.height == 0 && backgroundGraphicsLayer.size.height != 0 -> backgroundGraphicsLayer.size.height +// backgroundGraphicsLayerSize.value.height == 0 -> graphicsLayer.size.height +// else -> backgroundGraphicsLayerSize.value.height +// } +// println("LALAL GRAPHICSLAYER ${graphicsLayer.size.height} ${backgroundGraphicsLayer.size.height} ${backgroundGraphicsLayerSize.value.height}") +// val keyboardHeightCovered = if (keyboardCoversBar) keyboardInset.getBottom(density) else 0 +// translationY = -bgSize + size.height + keyboardHeightCovered +// } +// } + .drawBehind { + drawRect(Color.Black) + if (onTop) { + println("LALAL DRAWBEHIND0") + clipRect { + if (backgroundGraphicsLayer.size != IntSize.Zero) { + drawLayer(backgroundGraphicsLayer) + } else { + drawRect(CurrentColors.value.colors.background, size = Size(graphicsLayer.size.width.toFloat(), graphicsLayer.size.height.toFloat())) + } + drawLayer(graphicsLayer) + } + } else { + val bgSize = when { + backgroundGraphicsLayerSize.value.height == 0 && backgroundGraphicsLayer.size.height != 0 -> backgroundGraphicsLayer.size.height + backgroundGraphicsLayerSize.value.height == 0 -> graphicsLayer.size.height + else -> backgroundGraphicsLayerSize.value.height + } + println("LALAL DRAWBEHIND1 ${graphicsLayer.size.height} ${backgroundGraphicsLayer.size.height} ${backgroundGraphicsLayerSize.value}") + val keyboardHeightCovered = if (!keyboardCoversBar) keyboardInset.getBottom(density) else 0 + translate(top = -bgSize + size.height + keyboardHeightCovered) { + if (backgroundGraphicsLayer.size != IntSize.Zero) { + drawLayer(backgroundGraphicsLayer) + } else { + drawRect(CurrentColors.value.colors.background, size = Size(graphicsLayer.size.width.toFloat(), graphicsLayer.size.height.toFloat())) + } + drawLayer(graphicsLayer) + } + } + } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatWallpaper.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatWallpaper.kt index 2941b748c7..c1a76d7bf8 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatWallpaper.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatWallpaper.kt @@ -1,11 +1,13 @@ package chat.simplex.common.views.helpers +import androidx.compose.runtime.* import androidx.compose.ui.draw.CacheDrawScope import androidx.compose.ui.draw.DrawResult import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.* import androidx.compose.ui.graphics.drawscope.* +import androidx.compose.ui.graphics.layer.GraphicsLayer import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.* import chat.simplex.common.model.ChatController.appPrefs @@ -381,7 +383,14 @@ private fun drawToBitmap(image: ImageBitmap, imageScale: Float, tint: Color, siz return bitmap } -fun CacheDrawScope.chatViewBackground(image: ImageBitmap, imageType: WallpaperType, background: Color, tint: Color): DrawResult { +fun CacheDrawScope.chatViewBackground( + image: ImageBitmap, + imageType: WallpaperType, + background: Color, + tint: Color, + graphicsLayerSize: MutableState? = null, + backgroundGraphicsLayer: GraphicsLayer? = null +): DrawResult { val imageScale = if (imageType is WallpaperType.Preset) { (imageType.scale ?: 1f) * imageType.predefinedImageScale } else if (imageType is WallpaperType.Image && imageType.scaleType == WallpaperScaleType.REPEAT) { @@ -396,53 +405,55 @@ fun CacheDrawScope.chatViewBackground(image: ImageBitmap, imageType: WallpaperTy } return onDrawBehind { - val quality = if (appPlatform.isAndroid) FilterQuality.High else FilterQuality.Low - drawRect(background) - when (imageType) { - is WallpaperType.Preset -> drawImage(image) - is WallpaperType.Image -> when (val scaleType = imageType.scaleType ?: WallpaperScaleType.FILL) { - WallpaperScaleType.REPEAT -> drawImage(image) - WallpaperScaleType.FILL, WallpaperScaleType.FIT -> { - clipRect { - val scale = scaleType.contentScale.computeScaleFactor(Size(image.width.toFloat(), image.height.toFloat()), Size(size.width, size.height)) - val scaledWidth = (image.width * scale.scaleX).roundToInt() - val scaledHeight = (image.height * scale.scaleY).roundToInt() - // Large image will cause freeze - if (image.width > 4320 || image.height > 4320) return@clipRect + copyBackgroundToAppBar(graphicsLayerSize, backgroundGraphicsLayer) { + val quality = if (appPlatform.isAndroid) FilterQuality.High else FilterQuality.Low + drawRect(background) + when (imageType) { + is WallpaperType.Preset -> drawImage(image) + is WallpaperType.Image -> when (val scaleType = imageType.scaleType ?: WallpaperScaleType.FILL) { + WallpaperScaleType.REPEAT -> drawImage(image) + WallpaperScaleType.FILL, WallpaperScaleType.FIT -> { + clipRect { + val scale = scaleType.contentScale.computeScaleFactor(Size(image.width.toFloat(), image.height.toFloat()), Size(size.width, size.height)) + val scaledWidth = (image.width * scale.scaleX).roundToInt() + val scaledHeight = (image.height * scale.scaleY).roundToInt() + // Large image will cause freeze + if (image.width > 4320 || image.height > 4320) return@clipRect - drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality) - if (scaleType == WallpaperScaleType.FIT) { - if (scaledWidth < size.width) { - // has black lines at left and right sides - var x = (size.width - scaledWidth) / 2 - while (x > 0) { - drawImage(image, dstOffset = IntOffset(x = (x - scaledWidth).roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality) - x -= scaledWidth - } - x = size.width - (size.width - scaledWidth) / 2 - while (x < size.width) { - drawImage(image, dstOffset = IntOffset(x = x.roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality) - x += scaledWidth - } - } else { - // has black lines at top and bottom sides - var y = (size.height - scaledHeight) / 2 - while (y > 0) { - drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = (y - scaledHeight).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality) - y -= scaledHeight - } - y = size.height - (size.height - scaledHeight) / 2 - while (y < size.height) { - drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = y.roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality) - y += scaledHeight + drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality) + if (scaleType == WallpaperScaleType.FIT) { + if (scaledWidth < size.width) { + // has black lines at left and right sides + var x = (size.width - scaledWidth) / 2 + while (x > 0) { + drawImage(image, dstOffset = IntOffset(x = (x - scaledWidth).roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality) + x -= scaledWidth + } + x = size.width - (size.width - scaledWidth) / 2 + while (x < size.width) { + drawImage(image, dstOffset = IntOffset(x = x.roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality) + x += scaledWidth + } + } else { + // has black lines at top and bottom sides + var y = (size.height - scaledHeight) / 2 + while (y > 0) { + drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = (y - scaledHeight).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality) + y -= scaledHeight + } + y = size.height - (size.height - scaledHeight) / 2 + while (y < size.height) { + drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = y.roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality) + y += scaledHeight + } } } } + drawRect(tint) } - drawRect(tint) } + is WallpaperType.Empty -> {} } - is WallpaperType.Empty -> {} } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CollapsingAppBar.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CollapsingAppBar.kt index 2143c71076..906ce621c4 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CollapsingAppBar.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/CollapsingAppBar.kt @@ -3,16 +3,72 @@ package chat.simplex.common.views.helpers import androidx.compose.foundation.ScrollState import androidx.compose.foundation.lazy.LazyListState import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.CacheDrawScope +import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.drawscope.DrawScope import androidx.compose.ui.graphics.layer.GraphicsLayer +import androidx.compose.ui.graphics.layer.drawLayer +import androidx.compose.ui.graphics.rememberGraphicsLayer import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.unit.IntSize +import chat.simplex.common.model.ChatController.appPrefs val LocalAppBarHandler: ProvidableCompositionLocal = staticCompositionLocalOf { null } +@Composable +fun rememberAppBarHandler(key1: Any? = null, key2: Any? = null, keyboardCoversBar: Boolean = true): AppBarHandler { + val graphicsLayer = rememberGraphicsLayer() + val backgroundGraphicsLayer = rememberGraphicsLayer() + return remember(key1, key2) { AppBarHandler(graphicsLayer, backgroundGraphicsLayer, keyboardCoversBar) } +} + +@Composable +fun adjustAppBarHandler(handler: AppBarHandler): AppBarHandler { + println("LALAL HANDLER IS ${handler.graphicsLayer?.isReleased}") + val graphicsLayer = rememberGraphicsLayer() + val backgroundGraphicsLayer = rememberGraphicsLayer() + if (handler.graphicsLayer == null || handler.graphicsLayer?.isReleased == true || handler.backgroundGraphicsLayer?.isReleased == true) { + handler.graphicsLayer = graphicsLayer + handler.backgroundGraphicsLayer = backgroundGraphicsLayer + } + return handler +} + +fun Modifier.copyViewToAppBar(graphicsLayer: GraphicsLayer?): Modifier { + val blurRadius = appPrefs.appearanceBarsBlurRadius.get() + return if (blurRadius > 0 && graphicsLayer != null) { + this.drawWithContent { + graphicsLayer.record { + this@drawWithContent.drawContent() + } + drawLayer(graphicsLayer) + } + } else this +} + +fun DrawScope.copyBackgroundToAppBar(graphicsLayerSize: MutableState?, backgroundGraphicsLayer: GraphicsLayer?, scope: DrawScope.() -> Unit) { + println("LALAL MODIF2") + val blurRadius = appPrefs.appearanceBarsBlurRadius.get() + if (blurRadius > 0 && graphicsLayerSize != null && backgroundGraphicsLayer != null) { + backgroundGraphicsLayer.record { + scope() + } + graphicsLayerSize.value = backgroundGraphicsLayer.size + drawLayer(backgroundGraphicsLayer) + println("LALAL graphics SIZE ${backgroundGraphicsLayer.size}") + } else { + scope() + } +} + @Stable class AppBarHandler( + var graphicsLayer: GraphicsLayer?, + var backgroundGraphicsLayer: GraphicsLayer?, + val keyboardCoversBar: Boolean = true, listState: LazyListState = LazyListState(0, 0), scrollState: ScrollState = ScrollState(initial = 0) ) { @@ -25,8 +81,7 @@ class AppBarHandler( val connection = CollapsingAppBarNestedScrollConnection() - var graphicsLayer: GraphicsLayer? = null - var graphicsLayerSize: MutableState = mutableStateOf(IntSize.Zero) + val backgroundGraphicsLayerSize: MutableState = mutableStateOf(IntSize.Zero) companion object { var appBarMaxHeightPx: Int = 0 diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt index 4beae76cf2..64608c622c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DefaultTopAppBar.kt @@ -8,8 +8,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.* import androidx.compose.ui.graphics.* -import androidx.compose.ui.graphics.drawscope.* -import androidx.compose.ui.graphics.layer.drawLayer +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.* @@ -49,28 +48,12 @@ fun DefaultTopAppBar( } } Box(modifier) { - val graphicsLayer = handler?.graphicsLayer - val blurRadius = remember { appPrefs.appearanceBarsBlurRadius.state } + val density = LocalDensity.current + val keyboardInset = WindowInsets.ime + SideEffect { println("LALAL RELOAD ${keyboardInset.getBottom(density)}") } Box(Modifier .matchParentSize() - .then(if (graphicsLayer != null && blurRadius.value > 0 && prefAlpha < 1f) - Modifier - .graphicsLayer { - renderEffect = if (blurRadius.value > 0) BlurEffect(blurRadius.value.toFloat(), blurRadius.value.toFloat()) else null - clip = blurRadius.value > 0 - } - .drawWithCache { - // keep it here, forces redraw block to restart when size of the layer changes (in ChatView, for example) - handler.graphicsLayerSize.value - onDrawBehind { - //drawRect(Color.Black) - clipRect { - translate(top = if (!onTop) size.height - graphicsLayer.size.height else 0f) { - drawLayer(graphicsLayer) - } - } - } - } else Modifier) + .blurredBackgroundModifier(keyboardInset, handler, remember { appPrefs.appearanceBarsBlurRadius.state }, prefAlpha, handler?.keyboardCoversBar == true, onTop, density) .drawWithCache { val backgroundColor = if (title != null || fixedTitleText != null || connection == null || !onTop) { themeBackgroundMix.copy(prefAlpha) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt index 36713106bc..4bbccbd817 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt @@ -38,7 +38,7 @@ fun ModalView( } val oneHandUI = remember { appPrefs.oneHandUI.state } Surface(Modifier.fillMaxSize(), contentColor = LocalContentColor.current) { - Box(if (background != Color.Unspecified) Modifier.background(background) else Modifier.themedBackground()) { + Box(if (background != Color.Unspecified) Modifier.background(background) else Modifier.themedBackground(bgLayerSize = LocalAppBarHandler.current?.backgroundGraphicsLayerSize, bgLayer = LocalAppBarHandler.current?.backgroundGraphicsLayer)) { Box(modifier = modifier) { content() } @@ -73,7 +73,7 @@ class ModalData() { fun stateGetOrPutNullable (key: String, default: () -> T?): MutableState = state.getOrPut(key) { mutableStateOf(default() as Any?) } as MutableState - val appBarHandler = AppBarHandler() + val appBarHandler = AppBarHandler(null, null) } class ModalManager(private val placement: ModalPlacement? = null) { @@ -88,16 +88,14 @@ class ModalManager(private val placement: ModalPlacement? = null) { private var onTimePasscodeView: MutableStateFlow<(@Composable (close: () -> Unit) -> Unit)?> = MutableStateFlow(null) fun showModal(settings: Boolean = false, showClose: Boolean = true, endButtons: List<@Composable RowScope.() -> Unit> = emptyList(), content: @Composable ModalData.() -> Unit) { - val data = ModalData() showCustomModal { close -> - ModalView(close, showClose = showClose, endButtons = endButtons, content = { data.content() }) + ModalView(close, showClose = showClose, endButtons = endButtons, content = { content() }) } } fun showModalCloseable(settings: Boolean = false, showClose: Boolean = true, endButtons: List<@Composable RowScope.() -> Unit> = emptyList(), content: @Composable ModalData.(close: () -> Unit) -> Unit) { - val data = ModalData() showCustomModal { close -> - ModalView(close, showClose = showClose, endButtons = endButtons, content = { data.content(close) }) + ModalView(close, showClose = showClose, endButtons = endButtons, content = { content(close) }) } } @@ -164,9 +162,7 @@ class ModalManager(private val placement: ModalPlacement? = null) { // Without animation if (modalCount.value > 0 && modalViews.lastOrNull()?.first == false) { modalViews.lastOrNull()?.let { - CompositionLocalProvider( - LocalAppBarHandler provides it.second.appBarHandler - ) { + CompositionLocalProvider(LocalAppBarHandler provides adjustAppBarHandler(it.second.appBarHandler)) { it.third(it.second, ::closeModal) } } @@ -182,9 +178,7 @@ class ModalManager(private val placement: ModalPlacement? = null) { } ) { modalViews.getOrNull(it - 1)?.let { - CompositionLocalProvider( - LocalAppBarHandler provides it.second.appBarHandler - ) { + CompositionLocalProvider(LocalAppBarHandler provides adjustAppBarHandler(it.second.appBarHandler)) { it.third(it.second, ::closeModal) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt index 272053c995..2fd1e47f22 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt @@ -76,59 +76,54 @@ private fun CreateSimpleXAddressLayout( createAddress: () -> Unit, nextStep: () -> Unit, ) { - val handler = remember { AppBarHandler() } - CompositionLocalProvider( - LocalAppBarHandler provides handler - ) { - ModalView({}, showClose = false) { - ColumnWithScrollBar( - Modifier.themedBackground(), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - AppBarTitle(stringResource(MR.strings.simplex_address)) + ModalView({}, showClose = false) { + ColumnWithScrollBarNoAppBar( + Modifier.themedBackground(bgLayerSize = LocalAppBarHandler.current?.backgroundGraphicsLayerSize, bgLayer = LocalAppBarHandler.current?.backgroundGraphicsLayer), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + AppBarTitle(stringResource(MR.strings.simplex_address)) + Spacer(Modifier.weight(1f)) + + if (userAddress != null) { + SimpleXLinkQRCode(userAddress.connReqContact) + Spacer(Modifier.height(DEFAULT_PADDING_HALF)) + Row { + ShareAddressButton { share(simplexChatLink(userAddress.connReqContact)) } + Spacer(Modifier.width(DEFAULT_PADDING * 2)) + ShareViaEmailButton { sendEmail(userAddress) } + } + Spacer(Modifier.height(DEFAULT_PADDING)) + Spacer(Modifier.weight(1f)) + Column(Modifier.widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) { + OnboardingActionButton( + modifier = if (appPlatform.isAndroid) Modifier.padding(horizontal = DEFAULT_PADDING * 2).fillMaxWidth() else Modifier.widthIn(min = 300.dp), + labelId = MR.strings.continue_to_next_step, + onboarding = null, + onclick = nextStep + ) + // Reserve space + TextButtonBelowOnboardingButton("", null) + } + } else { + Button(createAddress, Modifier, shape = CircleShape, contentPadding = PaddingValues()) { + Icon(painterResource(MR.images.ic_mail_filled), null, Modifier.size(100.dp).background(MaterialTheme.colors.primary, CircleShape).padding(25.dp), tint = Color.White) + } + Spacer(Modifier.height(DEFAULT_PADDING)) + Spacer(Modifier.weight(1f)) + Text(stringResource(MR.strings.create_simplex_address), style = MaterialTheme.typography.h3, fontWeight = FontWeight.Bold) + TextBelowButton(stringResource(MR.strings.you_can_make_address_visible_via_settings)) + Spacer(Modifier.height(DEFAULT_PADDING)) Spacer(Modifier.weight(1f)) - if (userAddress != null) { - SimpleXLinkQRCode(userAddress.connReqContact) - Spacer(Modifier.height(DEFAULT_PADDING_HALF)) - Row { - ShareAddressButton { share(simplexChatLink(userAddress.connReqContact)) } - Spacer(Modifier.width(DEFAULT_PADDING * 2)) - ShareViaEmailButton { sendEmail(userAddress) } - } - Spacer(Modifier.height(DEFAULT_PADDING)) - Spacer(Modifier.weight(1f)) - Column(Modifier.widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) { - OnboardingActionButton( - modifier = if (appPlatform.isAndroid) Modifier.padding(horizontal = DEFAULT_PADDING * 2).fillMaxWidth() else Modifier.widthIn(min = 300.dp), - labelId = MR.strings.continue_to_next_step, - onboarding = null, - onclick = nextStep - ) - // Reserve space - TextButtonBelowOnboardingButton("", null) - } - } else { - Button(createAddress, Modifier, shape = CircleShape, contentPadding = PaddingValues()) { - Icon(painterResource(MR.images.ic_mail_filled), null, Modifier.size(100.dp).background(MaterialTheme.colors.primary, CircleShape).padding(25.dp), tint = Color.White) - } - Spacer(Modifier.height(DEFAULT_PADDING)) - Spacer(Modifier.weight(1f)) - Text(stringResource(MR.strings.create_simplex_address), style = MaterialTheme.typography.h3, fontWeight = FontWeight.Bold) - TextBelowButton(stringResource(MR.strings.you_can_make_address_visible_via_settings)) - Spacer(Modifier.height(DEFAULT_PADDING)) - Spacer(Modifier.weight(1f)) - - Column(Modifier.widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) { - OnboardingActionButton( - modifier = if (appPlatform.isAndroid) Modifier.padding(horizontal = DEFAULT_PADDING * 2).fillMaxWidth() else Modifier.widthIn(min = 300.dp), - labelId = MR.strings.create_address_button, - onboarding = null, - onclick = createAddress - ) - TextButtonBelowOnboardingButton(stringResource(MR.strings.dont_create_address), nextStep) - } + Column(Modifier.widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) { + OnboardingActionButton( + modifier = if (appPlatform.isAndroid) Modifier.padding(horizontal = DEFAULT_PADDING * 2).fillMaxWidth() else Modifier.widthIn(min = 300.dp), + labelId = MR.strings.create_address_button, + onboarding = null, + onclick = createAddress + ) + TextButtonBelowOnboardingButton(stringResource(MR.strings.dont_create_address), nextStep) } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/LinkAMobileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/LinkAMobileView.kt index e52db7bc02..5f1bbfc7d5 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/LinkAMobileView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/LinkAMobileView.kt @@ -59,7 +59,7 @@ private fun LinkAMobileLayout( staleQrCode: MutableState, updateDeviceName: (String) -> Unit, ) { - Column(Modifier.themedBackground()) { + Column(Modifier.themedBackground(bgLayerSize = LocalAppBarHandler.current?.backgroundGraphicsLayerSize, bgLayer = LocalAppBarHandler.current?.backgroundGraphicsLayer)) { DefaultTopAppBar( navigationButton = { NavigationButtonBack(onButtonClicked = { appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) } ) }, onTop = true diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetNotificationsMode.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetNotificationsMode.kt index 33e00cd9ba..e480d4330b 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetNotificationsMode.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetNotificationsMode.kt @@ -25,12 +25,9 @@ import chat.simplex.res.MR @Composable fun SetNotificationsMode(m: ChatModel) { - val handler = remember { AppBarHandler() } - CompositionLocalProvider( - LocalAppBarHandler provides handler - ) { + CompositionLocalProvider(LocalAppBarHandler provides rememberAppBarHandler()) { ModalView({}, showClose = false) { - ColumnWithScrollBar(Modifier.themedBackground()) { + ColumnWithScrollBar(Modifier.themedBackground(bgLayerSize = LocalAppBarHandler.current?.backgroundGraphicsLayerSize, bgLayer = LocalAppBarHandler.current?.backgroundGraphicsLayer)) { Box(Modifier.align(Alignment.CenterHorizontally)) { AppBarTitle(stringResource(MR.strings.onboarding_notifications_mode_title)) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetupDatabasePassphrase.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetupDatabasePassphrase.kt index cb624681b0..d0a3e601d2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetupDatabasePassphrase.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetupDatabasePassphrase.kt @@ -104,13 +104,10 @@ private fun SetupDatabasePassphraseLayout( onConfirmEncrypt: () -> Unit, nextStep: () -> Unit, ) { - val handler = remember { AppBarHandler() } - CompositionLocalProvider( - LocalAppBarHandler provides handler - ) { + CompositionLocalProvider(LocalAppBarHandler provides rememberAppBarHandler()) { ModalView({}, showClose = false) { ColumnWithScrollBar( - Modifier.themedBackground().padding(bottom = DEFAULT_PADDING * 2), + Modifier.themedBackground(bgLayerSize = LocalAppBarHandler.current?.backgroundGraphicsLayerSize, bgLayer = LocalAppBarHandler.current?.backgroundGraphicsLayer).padding(bottom = DEFAULT_PADDING * 2), horizontalAlignment = Alignment.CenterHorizontally, ) { AppBarTitle(stringResource(MR.strings.setup_database_passphrase)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.kt index 331476ba8f..d3b0f699a3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.kt @@ -31,15 +31,17 @@ import dev.icerock.moko.resources.StringResource @Composable fun SimpleXInfo(chatModel: ChatModel, onboarding: Boolean = true) { if (onboarding) { - ModalView({}, showClose = false, endButtons = listOf { - IconButton({ ModalManager.fullscreen.showModal { HowItWorks(chatModel.currentUser.value, null) }}) { - Icon(painterResource(MR.images.ic_info), null, Modifier.size(28.dp), tint = MaterialTheme.colors.primary) + CompositionLocalProvider(LocalAppBarHandler provides rememberAppBarHandler()) { + ModalView({}, showClose = false, endButtons = listOf { + IconButton({ ModalManager.fullscreen.showModal { HowItWorks(chatModel.currentUser.value, null) } }) { + Icon(painterResource(MR.images.ic_info), null, Modifier.size(28.dp), tint = MaterialTheme.colors.primary) + } + }) { + SimpleXInfoLayout( + user = chatModel.currentUser.value, + onboardingStage = chatModel.controller.appPrefs.onboardingStage + ) } - }) { - SimpleXInfoLayout( - user = chatModel.currentUser.value, - onboardingStage = chatModel.controller.appPrefs.onboardingStage - ) } } else { SimpleXInfoLayout( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt index 4b544cd6c4..872cc154a6 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt @@ -228,10 +228,11 @@ object AppearanceScope { Spacer(Modifier.width(15.dp)) Slider( prefValue.toFloat(), - valueRange = 0f..100f, - steps = 101, + valueRange = 0f..200f, + steps = 41, onValueChange = { - pref.set(it.roundToInt()) + val int = it.roundToInt() + pref.set(int - int % 5) }, colors = SliderDefaults.colors( activeTickColor = Color.Transparent, @@ -257,7 +258,7 @@ object AppearanceScope { Column(Modifier .drawWithCache { if (wallpaperImage != null && wallpaperType != null && backgroundColor != null && tintColor != null) { - chatViewBackground(wallpaperImage, wallpaperType, backgroundColor, tintColor) + chatViewBackground(wallpaperImage, wallpaperType, backgroundColor, tintColor, null, null) } else { onDrawBehind { drawRect(themeBackgroundColor) diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt index 2f5e20e445..25d85a6b7d 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt @@ -200,9 +200,7 @@ private fun ApplicationScope.AppWindow(closedByError: MutableState) { Window(state = cWindowState, onCloseRequest = { hiddenUntilRestart = true }, title = stringResource(MR.strings.chat_console)) { val data = remember { ModalData() } SimpleXTheme { - CompositionLocalProvider( - LocalAppBarHandler provides data.appBarHandler - ) { + CompositionLocalProvider(LocalAppBarHandler provides data.appBarHandler) { ModalView({ hiddenUntilRestart = true }) { TerminalView(true) } diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/ScrollableColumn.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/ScrollableColumn.desktop.kt index 2d008493f7..a989c2391a 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/ScrollableColumn.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/ScrollableColumn.desktop.kt @@ -12,10 +12,7 @@ import androidx.compose.material.MaterialTheme import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.graphics.layer.drawLayer -import androidx.compose.ui.graphics.rememberGraphicsLayer import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.pointer.* import androidx.compose.ui.unit.Dp @@ -30,7 +27,6 @@ import kotlin.math.* @Composable actual fun LazyColumnWithScrollBar( modifier: Modifier, - backgroundModifier: Modifier, state: LazyListState?, contentPadding: PaddingValues, reverseLayout: Boolean, @@ -63,19 +59,6 @@ actual fun LazyColumnWithScrollBar( } } } - val graphicsLayer = rememberGraphicsLayer() - val blurRadius = remember { appPrefs.appearanceBarsBlurRadius.state } - val drawScreenshot = remember(blurRadius.value > 0, backgroundModifier) { - if (blurRadius.value > 0) { - Modifier.drawWithContent { - graphicsLayer.record { - this@drawWithContent.drawContent() - } - drawLayer(graphicsLayer) - handler.graphicsLayerSize.value = graphicsLayer.size - }.then(backgroundModifier) - } else Modifier - } val state = state ?: handler.listState val connection = handler.connection // When scroll bar is dragging, there is no scroll event in nested scroll modifier. So, listen for changes on lazy column state @@ -106,17 +89,10 @@ actual fun LazyColumnWithScrollBar( } } val modifier = if (fillMaxSize) Modifier.fillMaxSize().then(modifier) else modifier - Box(Modifier.then(drawScreenshot).nestedScroll(connection)) { + Box(Modifier.copyViewToAppBar(LocalAppBarHandler.current?.graphicsLayer).nestedScroll(connection)) { LazyColumn(modifier.then(scrollModifier), state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content) ScrollBar(reverseLayout, state, scrollBarAlpha, scrollJob, scrollBarDraggingState, additionalBarOffset) } - /** setting it in composition scope because in Disposable effect it comes too late and other side [DefaultTopAppBar] doesn't see it in time */ - handler.graphicsLayer = graphicsLayer - DisposableEffect(Unit) { - onDispose { - handler.graphicsLayer = null - } - } } @Composable @@ -185,7 +161,6 @@ private fun ScrollBar( @Composable actual fun ColumnWithScrollBar( modifier: Modifier, - backgroundModifier: Modifier, verticalArrangement: Arrangement.Vertical, horizontalAlignment: Alignment.Horizontal, state: ScrollState?, @@ -199,19 +174,6 @@ actual fun ColumnWithScrollBar( val scope = rememberCoroutineScope() val scrollBarAlpha = remember { Animatable(0f) } val scrollJob: MutableState = remember { mutableStateOf(Job()) } - val graphicsLayer = rememberGraphicsLayer() - val blurRadius = remember { appPrefs.appearanceBarsBlurRadius.state } - val drawScreenshot = remember(blurRadius.value > 0, backgroundModifier) { - if (blurRadius.value > 0) { - Modifier.drawWithContent { - graphicsLayer.record { - this@drawWithContent.drawContent() - } - drawLayer(graphicsLayer) - handler.graphicsLayerSize.value = graphicsLayer.size - }.then(backgroundModifier) - } else Modifier - } val scrollModifier = remember { Modifier .pointerInput(Unit) { @@ -248,9 +210,9 @@ actual fun ColumnWithScrollBar( val padding = if (oneHandUI.value) PaddingValues(bottom = AppBarHeight * fontSizeSqrtMultiplier) else PaddingValues(top = AppBarHeight * fontSizeSqrtMultiplier) Column( if (maxIntrinsicSize) { - modifier.then(drawScreenshot).verticalScroll(state).height(IntrinsicSize.Max).then(scrollModifier) + modifier.copyViewToAppBar(LocalAppBarHandler.current?.graphicsLayer).verticalScroll(state).height(IntrinsicSize.Max).then(scrollModifier) } else { - modifier.then(scrollModifier).then(drawScreenshot).verticalScroll(state) + modifier.then(scrollModifier).copyViewToAppBar(LocalAppBarHandler.current?.graphicsLayer).verticalScroll(state) }, verticalArrangement, horizontalAlignment ) { @@ -264,13 +226,6 @@ actual fun ColumnWithScrollBar( DesktopScrollBar(rememberScrollbarAdapter(state), Modifier.fillMaxHeight(), scrollBarAlpha, scrollJob, false, scrollBarDraggingState) } } - /** setting it in composition scope because in Disposable effect it comes too late and other side [DefaultTopAppBar] doesn't see it in time */ - handler.graphicsLayer = graphicsLayer - DisposableEffect(Unit) { - onDispose { - handler.graphicsLayer = null - } - } } @Composable