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 new file mode 100644 index 0000000000..199e719703 --- /dev/null +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/ScrollableColumn.android.kt @@ -0,0 +1,35 @@ +package chat.simplex.common.platform + +import androidx.compose.foundation.* +import androidx.compose.foundation.gestures.FlingBehavior +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier + +@Composable +actual fun LazyColumnWithScrollBar( + modifier: Modifier, + state: LazyListState, + contentPadding: PaddingValues, + reverseLayout: Boolean, + verticalArrangement: Arrangement.Vertical, + horizontalAlignment: Alignment.Horizontal, + flingBehavior: FlingBehavior, + userScrollEnabled: Boolean, + content: LazyListScope.() -> Unit +) { + LazyColumn(modifier, state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content) +} + +@Composable +actual fun ColumnWithScrollBar( + modifier: Modifier, + verticalArrangement: Arrangement.Vertical, + horizontalAlignment: Alignment.Horizontal, + state: ScrollState, + content: @Composable ColumnScope.() -> Unit +) { + Column(modifier.verticalScroll(rememberScrollState()), verticalArrangement, horizontalAlignment, content) +} diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/Appearance.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/Appearance.android.kt index e02c011fac..ccb85c3982 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/Appearance.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/usersettings/Appearance.android.kt @@ -85,8 +85,8 @@ fun AppearanceScope.AppearanceLayout( showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), editColor: (ThemeColor, Color) -> Unit, ) { - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.appearance_settings)) SectionView(stringResource(MR.strings.settings_section_title_language), padding = PaddingValues()) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Platform.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Platform.kt index 03878a19d1..5ca6dbdeb3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Platform.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Platform.kt @@ -1,8 +1,14 @@ package chat.simplex.common.platform -import androidx.compose.runtime.Composable +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.AnimationVector1D +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier import chat.simplex.common.model.ChatId import chat.simplex.common.model.NotificationsMode +import kotlinx.coroutines.Job interface PlatformInterface { suspend fun androidServiceStart() {} @@ -19,6 +25,9 @@ interface PlatformInterface { fun androidCallEnded() {} @Composable fun androidLockPortraitOrientation() {} suspend fun androidAskToAllowBackgroundCalls(): Boolean = true + @Composable fun desktopScrollBarComponents(): Triple, Modifier, MutableState> = remember { Triple(Animatable(0f), Modifier, mutableStateOf(Job())) } + @Composable fun desktopScrollBar(state: LazyListState, modifier: Modifier, scrollBarAlpha: Animatable, scrollJob: MutableState, reversed: Boolean) {} + @Composable fun desktopScrollBar(state: ScrollState, modifier: Modifier, scrollBarAlpha: Animatable, scrollJob: MutableState, reversed: Boolean) {} } /** * Multiplatform project has separate directories per platform + common directory that contains directories per platform + common for all of them. 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 new file mode 100644 index 0000000000..d4fa2fe125 --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/ScrollableColumn.kt @@ -0,0 +1,34 @@ +package chat.simplex.common.platform + +import androidx.compose.foundation.* +import androidx.compose.foundation.gestures.FlingBehavior +import androidx.compose.foundation.gestures.ScrollableDefaults +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +expect fun LazyColumnWithScrollBar( + modifier: Modifier = Modifier, + state: LazyListState = rememberLazyListState(), + contentPadding: PaddingValues = PaddingValues(0.dp), + reverseLayout: Boolean = false, + verticalArrangement: Arrangement.Vertical = + if (!reverseLayout) Arrangement.Top else Arrangement.Bottom, + horizontalAlignment: Alignment.Horizontal = Alignment.Start, + flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(), + userScrollEnabled: Boolean = true, + content: LazyListScope.() -> Unit +) + +@Composable +expect fun ColumnWithScrollBar( + modifier: Modifier = Modifier, + verticalArrangement: Arrangement.Vertical = Arrangement.Top, + horizontalAlignment: Alignment.Horizontal = Alignment.Start, + state: ScrollState = rememberScrollState(), + content: @Composable ColumnScope.() -> Unit +) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt index bcdf2e8380..1cd85ae7f9 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/TerminalView.kt @@ -130,7 +130,7 @@ fun TerminalLog() { derivedStateOf { chatModel.terminalItems.value.asReversed() } } val clipboard = LocalClipboardManager.current - LazyColumn(state = listState, reverseLayout = true) { + LazyColumnWithScrollBar(state = listState, reverseLayout = true) { items(reversedTerminalItems) { item -> val rhId = item.remoteHostId val rhIdStr = if (rhId == null) "" else "$rhId " 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 c4cbe06831..aa6b22fcde 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 @@ -49,8 +49,8 @@ fun CreateProfile(chatModel: ChatModel, close: () -> Unit) { val displayName = rememberSaveable { mutableStateOf("") } val focusRequester = remember { FocusRequester() } - Column( - modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()) + ColumnWithScrollBar( + modifier = Modifier.fillMaxSize() ) { Column(Modifier.padding(horizontal = DEFAULT_PADDING)) { AppBarTitle(stringResource(MR.strings.create_profile), bottomPadding = DEFAULT_PADDING) @@ -120,8 +120,8 @@ fun CreateFirstProfile(chatModel: ChatModel, close: () -> Unit) { val displayName = rememberSaveable { mutableStateOf("") } val focusRequester = remember { FocusRequester() } - Column( - modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()) + ColumnWithScrollBar( + modifier = Modifier.fillMaxSize() ) { /*CloseSheetBar(close = { if (chatModel.users.isEmpty()) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt index bbd5d93018..9f526f3eb8 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt @@ -319,10 +319,9 @@ fun ChatInfoLayout( KeyChangeEffect(chat.id) { scope.launch { scrollState.scrollTo(0) } } - Column( + ColumnWithScrollBar( Modifier .fillMaxWidth() - .verticalScroll(scrollState) ) { Row( Modifier.fillMaxWidth(), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt index 4347623bd1..14bb3543c3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatItemInfoView.kt @@ -24,11 +24,10 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.common.model.* -import chat.simplex.common.platform.onRightClick +import chat.simplex.common.platform.* import chat.simplex.common.views.chat.item.ItemAction import chat.simplex.common.views.chat.item.MarkdownText import chat.simplex.common.views.helpers.* -import chat.simplex.common.platform.shareText import chat.simplex.common.ui.theme.* import chat.simplex.res.MR import dev.icerock.moko.resources.ImageResource @@ -186,7 +185,8 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d @Composable fun HistoryTab() { - Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) { + // LALAL SCROLLBAR DOESN'T WORK + ColumnWithScrollBar(Modifier.fillMaxWidth()) { Details() SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false) val versions = ciInfo.itemVersions @@ -210,7 +210,8 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d @Composable fun QuoteTab(qi: CIQuote) { - Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) { + // LALAL SCROLLBAR DOESN'T WORK + ColumnWithScrollBar(Modifier.fillMaxWidth()) { Details() SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false) SectionView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) { @@ -267,7 +268,8 @@ fun ChatItemInfoView(chatModel: ChatModel, ci: ChatItem, ciInfo: ChatItemInfo, d @Composable fun DeliveryTab(memberDeliveryStatuses: List) { - Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) { + // LALAL SCROLLBAR DOESN'T WORK + ColumnWithScrollBar(Modifier.fillMaxWidth()) { Details() SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false) val mss = membersStatuses(chatModel, memberDeliveryStatuses) 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 6e30bd11ca..c70511f847 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 @@ -1,5 +1,6 @@ package chat.simplex.common.views.chat +import androidx.compose.animation.core.Animatable import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.* import androidx.compose.foundation.gestures.* @@ -21,6 +22,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.input.pointer.* import androidx.compose.ui.text.* import androidx.compose.ui.unit.* import chat.simplex.common.model.* @@ -473,7 +475,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId: } is ChatInfo.InvalidJSON -> { val close = { chatModel.chatId.value = null } - ModalView(close, showClose = appPlatform.isAndroid, content = { + ModalView(close, showClose = appPlatform.isAndroid, endButtons = { ShareButton { clipboard.shareText(chat.chatInfo.json) } }, content = { InvalidJSONView(chat.chatInfo.json) }) LaunchedEffect(chat.id) { @@ -907,7 +909,7 @@ fun BoxWithConstraintsScope.ChatItemsList( VideoPlayerHolder.releaseAll() } ) - LazyColumn(Modifier.align(Alignment.BottomCenter), state = listState, reverseLayout = true) { + LazyColumnWithScrollBar(Modifier.align(Alignment.BottomCenter), state = listState, reverseLayout = true) { itemsIndexed(reversedChatItems, key = { _, item -> item.id }) { i, cItem -> CompositionLocalProvider( // Makes horizontal and vertical scrolling to coexist nicely. diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ContactPreferences.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ContactPreferences.kt index f412c02154..5ad98aa216 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ContactPreferences.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ContactPreferences.kt @@ -19,6 +19,7 @@ import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* import chat.simplex.common.views.usersettings.PreferenceToggle import chat.simplex.common.model.* +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.res.MR @Composable @@ -77,10 +78,9 @@ private fun ContactPreferencesLayout( reset: () -> Unit, savePrefs: () -> Unit, ) { - Column( + ColumnWithScrollBar( Modifier - .fillMaxWidth() - .verticalScroll(rememberScrollState()), + .fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.contact_preferences)) val timedMessages: MutableState = remember(featuresAllowed) { mutableStateOf(featuresAllowed.timedMessagesAllowed) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/VerifyCodeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/VerifyCodeView.kt index 57c469adf2..5bd707ab66 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/VerifyCodeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/VerifyCodeView.kt @@ -16,8 +16,7 @@ import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import chat.simplex.common.platform.appPlatform -import chat.simplex.common.platform.shareText +import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* import chat.simplex.common.views.newchat.QRCode @@ -57,10 +56,9 @@ private fun VerifyCodeLayout( connectionVerified: Boolean, verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit, ) { - Column( + ColumnWithScrollBar( Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()) .padding(horizontal = DEFAULT_PADDING) ) { AppBarTitle(stringResource(MR.strings.security_code), withPadding = false) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt index 3f283f704e..d546b51a93 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt @@ -125,10 +125,9 @@ fun AddGroupMembersLayout( } } - Column( + ColumnWithScrollBar( Modifier - .fillMaxWidth() - .verticalScroll(rememberScrollState()), + .fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.button_add_members)) profileText() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt index 98c0fb4679..bfd7b5d52f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt @@ -205,7 +205,8 @@ fun GroupChatInfoLayout( } val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue()) } val filteredMembers = remember(members) { derivedStateOf { members.filter { it.chatViewName.lowercase().contains(searchText.value.text.trim()) } } } - LazyColumn( + // LALAL strange scrolling + LazyColumnWithScrollBar( Modifier .fillMaxWidth(), state = listState diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupLinkView.kt index 7b198bc41a..5291520566 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupLinkView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupLinkView.kt @@ -16,6 +16,7 @@ import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.common.model.* +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.platform.shareText import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* @@ -118,9 +119,8 @@ fun GroupLinkLayout( ) } - Column( - Modifier - .verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier, ) { AppBarTitle(stringResource(MR.strings.group_link)) Text( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt index b1034b914b..ebb35a4468 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt @@ -291,10 +291,9 @@ fun GroupMemberInfoLayout( } } - Column( + ColumnWithScrollBar( Modifier - .fillMaxWidth() - .verticalScroll(rememberScrollState()), + .fillMaxWidth(), ) { Row( Modifier.fillMaxWidth(), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupPreferences.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupPreferences.kt index 694dac8898..607efb9a3b 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupPreferences.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupPreferences.kt @@ -18,6 +18,7 @@ import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* import chat.simplex.common.views.usersettings.PreferenceToggleWithIcon import chat.simplex.common.model.* +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.res.MR @Composable @@ -72,8 +73,8 @@ private fun GroupPreferencesLayout( reset: () -> Unit, savePrefs: () -> Unit, ) { - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.group_preferences)) val timedMessages = remember(preferences) { mutableStateOf(preferences.timedMessages.enable) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupProfileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupProfileView.kt index 35bec31d7b..7975a298d1 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupProfileView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupProfileView.kt @@ -95,9 +95,8 @@ fun GroupProfileLayout( sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp) ) { ModalView(close = closeWithAlert) { - Column( + ColumnWithScrollBar( Modifier - .verticalScroll(scrollState) ) { Column( Modifier.fillMaxWidth() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/WelcomeMessageView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/WelcomeMessageView.kt index 6c2c37503c..3bbeceb03c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/WelcomeMessageView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/WelcomeMessageView.kt @@ -29,6 +29,7 @@ import chat.simplex.common.views.chat.item.MarkdownText import chat.simplex.common.views.helpers.* import chat.simplex.common.model.ChatModel import chat.simplex.common.model.GroupInfo +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.platform.chatJsonLength import chat.simplex.common.ui.theme.DEFAULT_PADDING_HALF import chat.simplex.res.MR @@ -91,8 +92,8 @@ private fun GroupWelcomeLayout( linkMode: SimplexLinkMode, save: () -> Unit, ) { - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), ) { val editMode = remember { mutableStateOf(true) } AppBarTitle(stringResource(MR.strings.group_welcome_title)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIInvalidJSONView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIInvalidJSONView.kt index 21c27fa34e..d297d5ef76 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIInvalidJSONView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIInvalidJSONView.kt @@ -1,6 +1,5 @@ package chat.simplex.common.views.chat.item -import SectionView import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.material.* @@ -8,23 +7,23 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalClipboardManager -import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.unit.dp +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.platform.shareText import chat.simplex.common.ui.theme.DEFAULT_PADDING import chat.simplex.common.views.helpers.* -import chat.simplex.common.views.usersettings.SettingsActionItem import chat.simplex.res.MR @Composable fun CIInvalidJSONView(json: String) { + val clipboard = LocalClipboardManager.current Row(Modifier .clickable { ModalManager.center.closeModals() ModalManager.end.closeModals() - ModalManager.center.showModal(true) { InvalidJSONView(json) } + ModalManager.center.showModal(true, endButtons = { ShareButton { clipboard.shareText(json) } }) { InvalidJSONView(json) } } .padding(horizontal = 10.dp, vertical = 6.dp) ) { @@ -34,15 +33,8 @@ fun CIInvalidJSONView(json: String) { @Composable fun InvalidJSONView(json: String) { - Column { - Spacer(Modifier.height(DEFAULT_PADDING)) - SectionView { - val clipboard = LocalClipboardManager.current - SettingsActionItem(painterResource(MR.images.ic_share), generalGetString(MR.strings.share_verb), click = { - clipboard.shareText(json) - }) - } - Column(Modifier.padding(DEFAULT_PADDING).fillMaxWidth().verticalScroll(rememberScrollState())) { + ColumnWithScrollBar { + Column(Modifier.padding(DEFAULT_PADDING).fillMaxWidth()) { Text(json) } } 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 417050db35..d03b8a708d 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 @@ -460,7 +460,7 @@ private fun ChatList(chatModel: ChatModel, searchText: MutableState(null) } val chats = filteredChats(showUnreadAndFavorites, searchShowingSimplexLink, searchChatFilteredBySimplexLink, searchText.value.text, allChats.toList()) - LazyColumn( + LazyColumnWithScrollBar( Modifier.fillMaxWidth(), listState ) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListView.kt index 818f1c70a5..04fef25ac2 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ShareListView.kt @@ -1,7 +1,6 @@ package chat.simplex.common.views.chatlist import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.* import androidx.compose.runtime.* @@ -14,12 +13,10 @@ import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import chat.simplex.common.SettingsViewState -import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* import chat.simplex.common.model.Chat import chat.simplex.common.model.ChatModel -import chat.simplex.common.platform.BackHandler -import chat.simplex.common.platform.appPlatform +import chat.simplex.common.platform.* import chat.simplex.res.MR import kotlinx.coroutines.flow.MutableStateFlow @@ -146,7 +143,7 @@ private fun ShareList(chatModel: ChatModel, search: String) { if (search.isEmpty()) chatModel.chats.toList().filter { it.chatInfo.ready } else chatModel.chats.toList().filter { it.chatInfo.ready }.filter(filter) } } - LazyColumn( + LazyColumnWithScrollBar( modifier = Modifier.fillMaxWidth() ) { items(chats) { chat -> diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/ChatArchiveView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/ChatArchiveView.kt index 1e2f8420fd..6846d1c735 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/ChatArchiveView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/ChatArchiveView.kt @@ -46,7 +46,7 @@ fun ChatArchiveLayout( saveArchive: () -> Unit, deleteArchiveAlert: () -> Unit ) { - Column( + ColumnWithScrollBar( Modifier.fillMaxWidth(), ) { AppBarTitle(title) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseEncryptionView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseEncryptionView.kt index 7ee9442b11..ca14b19adf 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseEncryptionView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseEncryptionView.kt @@ -27,7 +27,7 @@ import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.unit.* import chat.simplex.common.model.* -import chat.simplex.common.platform.appPreferences +import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* import chat.simplex.common.views.usersettings.SettingsActionItem @@ -100,8 +100,10 @@ fun DatabaseEncryptionLayout( migration: Boolean, onConfirmEncrypt: () -> Unit, ) { + val (scrollBarAlpha, scrollModifier, scrollJob) = platform.desktopScrollBarComponents() + val scrollState = rememberScrollState() Column( - if (!migration) Modifier.fillMaxWidth().verticalScroll(rememberScrollState()) else Modifier.fillMaxWidth(), + if (!migration) Modifier.fillMaxWidth().verticalScroll(scrollState).then(if (appPlatform.isDesktop) scrollModifier else Modifier) else Modifier.fillMaxWidth(), ) { if (!migration) { AppBarTitle(stringResource(MR.strings.database_passphrase)) @@ -190,6 +192,11 @@ fun DatabaseEncryptionLayout( } SectionBottomSpacer() } + if (appPlatform.isDesktop && !migration) { + Box(Modifier.fillMaxSize()) { + platform.desktopScrollBar(scrollState, Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, false) + } + } } expect fun encryptDatabaseSavedAlert(onConfirm: () -> Unit) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseErrorView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseErrorView.kt index a22e6399f7..5f0356bb2d 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseErrorView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseErrorView.kt @@ -76,8 +76,8 @@ fun DatabaseErrorView( Text(String.format(generalGetString(MR.strings.database_migrations), ms.joinToString(", "))) } - Column( - Modifier.fillMaxSize().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, ) { val buttonEnabled = validKey(dbKey.value) && !progressIndicator.value diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt index 8d7d9f8166..023d10c539 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt @@ -7,8 +7,6 @@ import SectionItemView import SectionView import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -27,7 +25,6 @@ import chat.simplex.common.views.helpers.* import chat.simplex.common.views.usersettings.* import chat.simplex.common.platform.* import chat.simplex.res.MR -import kotlinx.coroutines.delay import kotlinx.coroutines.sync.withLock import kotlinx.datetime.* import java.io.* @@ -158,8 +155,8 @@ fun DatabaseLayout( val stopped = !runChat val operationsDisabled = (!stopped || progressIndicator) && !chatModel.desktopNoUserNoRemote - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.your_chat_database)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Section.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Section.kt index 1c3540d7f2..d930a2841e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Section.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Section.kt @@ -61,9 +61,8 @@ fun SectionViewSelectable( onSelected: (T) -> Unit, ) { SectionView(title) { - LazyColumn { - items(values.size) { index -> - val item = values[index] + Column { + values.forEach { item -> SectionItemViewSpaceBetween({ onSelected(item.value) }) { Text(item.title) if (currentValue.value == item.value) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt index da6e7181d1..10add37e54 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateFromDevice.kt @@ -145,13 +145,20 @@ private fun MigrateFromDeviceLayout( ) { val tempDatabaseFile = rememberSaveable { mutableStateOf(fileForTemporaryDatabase()) } + val (scrollBarAlpha, scrollModifier, scrollJob) = platform.desktopScrollBarComponents() + val scrollState = rememberScrollState() Column( - Modifier.fillMaxSize().verticalScroll(rememberScrollState()).height(IntrinsicSize.Max), + Modifier.fillMaxSize().verticalScroll(scrollState).then(if (appPlatform.isDesktop) scrollModifier else Modifier).height(IntrinsicSize.Max), ) { AppBarTitle(stringResource(MR.strings.migrate_from_device_title)) SectionByState(migrationState, tempDatabaseFile.value, chatReceiver) SectionBottomSpacer() } + if (appPlatform.isDesktop) { + Box(Modifier.fillMaxSize()) { + platform.desktopScrollBar(scrollState, Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, false) + } + } platform.androidLockPortraitOrientation() } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt index e24570ba8b..9d204ad42c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalClipboardManager import chat.simplex.common.model.* @@ -154,14 +155,20 @@ private fun ModalData.MigrateToDeviceLayout( close: () -> Unit, ) { val tempDatabaseFile = rememberSaveable { mutableStateOf(fileForTemporaryDatabase()) } - + val (scrollBarAlpha, scrollModifier, scrollJob) = platform.desktopScrollBarComponents() + val scrollState = rememberScrollState() Column( - Modifier.fillMaxSize().verticalScroll(rememberScrollState()).height(IntrinsicSize.Max), + Modifier.fillMaxSize().verticalScroll(scrollState).then(if (appPlatform.isDesktop) scrollModifier else Modifier).height(IntrinsicSize.Max), ) { AppBarTitle(stringResource(MR.strings.migrate_to_device_title)) SectionByState(migrationState, tempDatabaseFile.value, chatReceiver, close) SectionBottomSpacer() } + if (appPlatform.isDesktop) { + Box(Modifier.fillMaxSize()) { + platform.desktopScrollBar(scrollState, Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, false) + } + } platform.androidLockPortraitOrientation() } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddContactLearnMore.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddContactLearnMore.kt index c2523c9b2e..da59050a3a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddContactLearnMore.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddContactLearnMore.kt @@ -1,10 +1,11 @@ package chat.simplex.common.views.newchat -import androidx.compose.foundation.* -import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.platform.chatModel +import chat.simplex.common.ui.theme.DEFAULT_PADDING import dev.icerock.moko.resources.compose.stringResource import chat.simplex.common.views.helpers.AppBarTitle import chat.simplex.common.views.helpers.KeyChangeEffect @@ -14,10 +15,10 @@ import chat.simplex.res.MR @Composable fun AddContactLearnMore(close: () -> Unit) { - Column( - Modifier.verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.padding(horizontal = DEFAULT_PADDING), ) { - AppBarTitle(stringResource(MR.strings.one_time_link)) + AppBarTitle(stringResource(MR.strings.one_time_link), withPadding = false) ReadableText(MR.strings.scan_qr_to_connect_to_contact) ReadableText(MR.strings.if_you_cant_meet_in_person) ReadableTextWithLink(MR.strings.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/readme.html#connect-to-friends") diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddGroupView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddGroupView.kt index ee03028909..a7bb026f1a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddGroupView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/AddGroupView.kt @@ -94,10 +94,9 @@ fun AddGroupLayout( sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp) ) { ModalView(close = close) { - Column( + ColumnWithScrollBar( Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()) .padding(horizontal = DEFAULT_PADDING) ) { AppBarTitle(stringResource(MR.strings.create_secret_group_title), hostDevice(rhId)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt index 6202d8263f..31623e4a61 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/ContactConnectionInfoView.kt @@ -65,14 +65,7 @@ fun ContactConnectionInfoView( share = { if (connReqInvitation != null) clipboard.shareText(connReqInvitation) }, learnMore = { ModalManager.end.showModalCloseable { close -> - Column( - Modifier - .fillMaxHeight() - .padding(horizontal = DEFAULT_PADDING), - verticalArrangement = Arrangement.SpaceBetween - ) { - AddContactLearnMore(close) - } + AddContactLearnMore(close) } } ) @@ -111,9 +104,8 @@ private fun ContactConnectionInfoLayout( } } - Column( - Modifier - .verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier, ) { AppBarTitle( stringResource( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt index bf154acca8..f341d59305 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/newchat/NewChatView.kt @@ -141,10 +141,10 @@ fun ModalData.NewChatView(rh: RemoteHostInfo?, selection: NewChatOption, showQRC } HorizontalPager(state = pagerState, Modifier.fillMaxSize(), verticalAlignment = Alignment.Top) { index -> - Column( + // LALAL SCROLLBAR DOESN'T WORK + ColumnWithScrollBar( Modifier - .fillMaxSize() - .verticalScroll(rememberScrollState()), + .fillMaxSize(), verticalArrangement = if (index == NewChatOption.INVITE.ordinal && connReqInvitation.isEmpty()) Arrangement.Center else Arrangement.Top) { Spacer(Modifier.height(DEFAULT_PADDING)) when (index) { @@ -232,14 +232,7 @@ private fun AddContactLearnMoreButton() { { if (appPlatform.isDesktop) ModalManager.end.closeModals() ModalManager.end.showModalCloseable { close -> - Column( - Modifier - .fillMaxHeight() - .padding(horizontal = DEFAULT_PADDING), - verticalArrangement = Arrangement.SpaceBetween - ) { - AddContactLearnMore(close) - } + AddContactLearnMore(close) } } ) { 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 190b962eae..e8ba5d7b60 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 @@ -75,8 +75,8 @@ private fun CreateSimpleXAddressLayout( createAddress: () -> Unit, nextStep: () -> Unit, ) { - Column( - Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(top = DEFAULT_PADDING), + ColumnWithScrollBar( + Modifier.fillMaxSize().padding(top = DEFAULT_PADDING), horizontalAlignment = Alignment.CenterHorizontally, ) { AppBarTitle(stringResource(MR.strings.simplex_address)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt index 14b36d0718..28fa1d3a48 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt @@ -14,6 +14,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.common.model.* +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.ui.theme.* import chat.simplex.common.views.chat.item.MarkdownText import chat.simplex.common.views.helpers.* @@ -22,7 +23,7 @@ import dev.icerock.moko.resources.StringResource @Composable fun HowItWorks(user: User?, onboardingStage: SharedPreference? = null) { - Column(Modifier + ColumnWithScrollBar(Modifier .fillMaxWidth() .padding(horizontal = DEFAULT_PADDING), ) { 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 aa413016d1..9124808959 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 @@ -15,6 +15,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.common.model.ChatModel import chat.simplex.common.model.NotificationsMode +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* import chat.simplex.common.views.usersettings.changeNotificationsMode @@ -23,10 +24,9 @@ import dev.icerock.moko.resources.StringResource @Composable fun SetNotificationsMode(m: ChatModel) { - Column( + ColumnWithScrollBar( modifier = Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()) .padding(vertical = 14.dp) ) { //CloseSheetBar(null) 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 905bf77989..65bd89b11b 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 @@ -98,8 +98,8 @@ private fun SetupDatabasePassphraseLayout( onConfirmEncrypt: () -> Unit, nextStep: () -> Unit, ) { - Column( - Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(top = DEFAULT_PADDING), + ColumnWithScrollBar( + Modifier.fillMaxSize().padding(top = DEFAULT_PADDING), 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 b82852664b..84c48bbc1b 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 @@ -16,6 +16,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.* import chat.simplex.common.model.* +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.platform.chatModel import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* @@ -39,10 +40,9 @@ fun SimpleXInfoLayout( onboardingStage: SharedPreference?, showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), ) { - Column( + ColumnWithScrollBar( Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()) .padding(start = DEFAULT_PADDING , end = DEFAULT_PADDING, top = DEFAULT_PADDING), horizontalAlignment = Alignment.CenterHorizontally ) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/WhatsNewView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/WhatsNewView.kt index fa7058160a..3f63e72a69 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/WhatsNewView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/WhatsNewView.kt @@ -18,6 +18,7 @@ import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.common.model.ChatModel +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* import chat.simplex.res.MR @@ -105,11 +106,10 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) { val v = versionDescriptions[currentVersion.value] ModalView(close = close) { - Column( + ColumnWithScrollBar( Modifier .fillMaxSize() - .padding(horizontal = DEFAULT_PADDING) - .verticalScroll(rememberScrollState()), + .padding(horizontal = DEFAULT_PADDING), verticalArrangement = Arrangement.spacedBy(DEFAULT_PADDING.times(0.75f)) ) { AppBarTitle(String.format(generalGetString(MR.strings.new_in_version), v.version), bottomPadding = DEFAULT_PADDING) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectDesktopView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectDesktopView.kt index 5acb240cb3..76f522c614 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectDesktopView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectDesktopView.kt @@ -75,8 +75,8 @@ private fun ConnectDesktopLayout(deviceName: String, close: () -> Unit) { val sessionAddress = remember { mutableStateOf("") } val remoteCtrls = remember { mutableStateListOf() } val session = remember { chatModel.remoteCtrlSession }.value - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), ) { val discovery = if (session == null) null else session.sessionState is UIRemoteCtrlSessionState.Searching if (discovery == true || (discovery == null && !showConnectScreen.value)) { @@ -391,8 +391,8 @@ private fun DesktopAddressView(sessionAddress: MutableState) { @Composable private fun LinkedDesktopsView(remoteCtrls: SnapshotStateList) { - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.linked_desktops)) SectionView(stringResource(MR.strings.desktop_devices).uppercase()) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectMobileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectMobileView.kt index bf7884e9d8..bd1be525be 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectMobileView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/remote/ConnectMobileView.kt @@ -91,8 +91,8 @@ fun ConnectMobileLayout( connectDesktop: () -> Unit, deleteHost: (RemoteHostInfo) -> Unit, ) { - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(8.dp) ) { AppBarTitle(stringResource(if (remember { chatModel.remoteHosts }.isEmpty()) MR.strings.link_a_mobile else MR.strings.linked_mobiles)) @@ -181,8 +181,8 @@ private fun ConnectMobileViewLayout( refreshQrCode: () -> Unit = {}, UnderQrLayout: @Composable () -> Unit = {}, ) { - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(8.dp) ) { if (title != null) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/AdvancedNetworkSettings.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/AdvancedNetworkSettings.kt index 7683f0ed18..a2ea5959c3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/AdvancedNetworkSettings.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/AdvancedNetworkSettings.kt @@ -23,6 +23,7 @@ import chat.simplex.common.model.* import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* import chat.simplex.common.model.ChatModel +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.res.MR import java.text.DecimalFormat @@ -141,10 +142,9 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) { ) { val secondsLabel = stringResource(MR.strings.network_option_seconds_label) - Column( + ColumnWithScrollBar( Modifier - .fillMaxWidth() - .verticalScroll(rememberScrollState()), + .fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.network_settings_title)) SectionView { 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 62216761ed..67f9a02ca7 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 @@ -57,8 +57,8 @@ object AppearanceScope { @Composable fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) { - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), ) { val currentTheme by CurrentColors.collectAsState() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/CallSettings.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/CallSettings.kt index d4219a51c5..94415b0ee0 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/CallSettings.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/CallSettings.kt @@ -16,6 +16,7 @@ import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import chat.simplex.common.views.helpers.* import chat.simplex.common.model.* +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.res.MR @Composable @@ -35,8 +36,8 @@ fun CallSettingsLayout( callOnLockScreen: SharedPreference, editIceServers: () -> Unit, ) { - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(8.dp) ) { AppBarTitle(stringResource(MR.strings.your_calls)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/DeveloperView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/DeveloperView.kt index 421d4feec3..a03a015207 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/DeveloperView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/DeveloperView.kt @@ -12,10 +12,9 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler import chat.simplex.common.model.* +import chat.simplex.common.platform.* import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource -import chat.simplex.common.platform.appPlatform -import chat.simplex.common.platform.appPreferences import chat.simplex.common.views.TerminalView import chat.simplex.common.views.helpers.* import chat.simplex.res.MR @@ -26,7 +25,7 @@ fun DeveloperView( showCustomModal: (@Composable ModalData.(ChatModel, () -> Unit) -> Unit) -> (() -> Unit), withAuth: (title: String, desc: String, block: () -> Unit) -> Unit ) { - Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) { + ColumnWithScrollBar(Modifier.fillMaxWidth()) { val uriHandler = LocalUriHandler.current AppBarTitle(stringResource(MR.strings.settings_developer_tools)) val developerTools = m.controller.appPrefs.developerTools diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/HelpView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/HelpView.kt index 33e183aaaf..c2bf69bc0e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/HelpView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/HelpView.kt @@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import dev.icerock.moko.resources.compose.stringResource import androidx.compose.desktop.ui.tooling.preview.Preview +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.ui.theme.DEFAULT_PADDING import chat.simplex.common.ui.theme.SimpleXTheme import chat.simplex.common.views.chatlist.ChatHelpView @@ -20,10 +21,9 @@ fun HelpView(userDisplayName: String) { @Composable fun HelpLayout(userDisplayName: String) { - Column( + ColumnWithScrollBar( Modifier .fillMaxWidth() - .verticalScroll(rememberScrollState()) .padding(horizontal = DEFAULT_PADDING), ){ AppBarTitle(String.format(stringResource(MR.strings.personal_welcome), userDisplayName), withPadding = false) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/HiddenProfileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/HiddenProfileView.kt index f3496c850f..4dd406c398 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/HiddenProfileView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/HiddenProfileView.kt @@ -17,6 +17,7 @@ import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import chat.simplex.common.model.ChatModel import chat.simplex.common.model.User +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.ui.theme.* import chat.simplex.common.views.chatlist.UserProfileRow import chat.simplex.common.views.database.PassphraseField @@ -53,10 +54,9 @@ private fun HiddenProfileLayout( user: User, saveProfilePassword: (String) -> Unit ) { - Column( + ColumnWithScrollBar( Modifier - .fillMaxWidth() - .verticalScroll(rememberScrollState()), + .fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.hide_profile)) SectionView(padding = PaddingValues(start = 8.dp, end = DEFAULT_PADDING)) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/IncognitoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/IncognitoView.kt index 6da0d34bd3..6098f66941 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/IncognitoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/IncognitoView.kt @@ -1,13 +1,13 @@ package chat.simplex.common.views.usersettings import SectionBottomSpacer -import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.ui.theme.DEFAULT_PADDING import chat.simplex.common.views.helpers.AppBarTitle import chat.simplex.common.views.helpers.generalGetString @@ -21,11 +21,10 @@ fun IncognitoView() { @Composable fun IncognitoLayout() { - Column { + ColumnWithScrollBar { AppBarTitle(stringResource(MR.strings.settings_section_title_incognito)) Column( Modifier - .verticalScroll(rememberScrollState()) .padding(horizontal = DEFAULT_PADDING), verticalArrangement = Arrangement.spacedBy(20.dp) ) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NetworkAndServers.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NetworkAndServers.kt index 27e5c80cde..e1f050b0b6 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NetworkAndServers.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NetworkAndServers.kt @@ -25,6 +25,7 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.common.model.* +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.platform.chatModel import chat.simplex.common.ui.theme.* import chat.simplex.common.views.chat.item.ClickableText @@ -151,8 +152,8 @@ fun NetworkAndServersView() { updateSessionMode: (TransportSessionMode) -> Unit, ) { val m = chatModel - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(8.dp) ) { AppBarTitle(stringResource(MR.strings.network_and_servers)) @@ -276,10 +277,9 @@ fun SockProxySettings( networkProxyHostPort: SharedPreference = m.controller.appPrefs.networkProxyHostPort, migration: Boolean, ) { - Column( + ColumnWithScrollBar( Modifier .fillMaxWidth() - .verticalScroll(rememberScrollState()) ) { val defaultHostPort = remember { "localhost:9050" } AppBarTitle(generalGetString(MR.strings.network_socks_proxy_settings)) @@ -376,7 +376,7 @@ private fun UseOnionHosts( } val onSelected = { showModal { - Column( + ColumnWithScrollBar( Modifier.fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.network_use_onion_hosts)) @@ -430,7 +430,7 @@ private fun SessionModePicker( icon = painterResource(MR.images.ic_safety_divider), onSelected = { showModal { - Column( + ColumnWithScrollBar( Modifier.fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.network_session_mode_transport_isolation)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NotificationsSettingsView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NotificationsSettingsView.kt index ddd1b4068e..515d73a426 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NotificationsSettingsView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NotificationsSettingsView.kt @@ -56,8 +56,8 @@ fun NotificationsSettingsLayout( val modes = remember { notificationModes() } val previewModes = remember { notificationPreviewModes() } - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.notifications)) SectionView(null) { @@ -90,7 +90,7 @@ fun NotificationsModeView( onNotificationsModeSelected: (NotificationsMode) -> Unit, ) { val modes = remember { notificationModes() } - Column( + ColumnWithScrollBar( Modifier.fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.settings_notifications_mode_title).lowercase().capitalize(Locale.current)) @@ -104,7 +104,7 @@ fun NotificationPreviewView( onNotificationPreviewModeSelected: (NotificationPreviewMode) -> Unit, ) { val previewModes = remember { notificationPreviewModes() } - Column( + ColumnWithScrollBar( Modifier.fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.settings_notification_preview_title)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Preferences.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Preferences.kt index 8b7ac68205..cd0e40f5d0 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Preferences.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Preferences.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.Modifier import dev.icerock.moko.resources.compose.stringResource import chat.simplex.common.views.helpers.* import chat.simplex.common.model.* +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.res.MR @Composable @@ -62,8 +63,8 @@ private fun PreferencesLayout( reset: () -> Unit, savePrefs: () -> Unit, ) { - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.your_preferences)) val timedMessages = remember(preferences) { mutableStateOf(preferences.timedMessages.allow) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt index 5f4b6c01e3..b376285259 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt @@ -30,8 +30,7 @@ import chat.simplex.common.views.isValidDisplayName import chat.simplex.common.views.localauth.SetAppPasscodeView import chat.simplex.common.views.onboarding.ReadableText import chat.simplex.common.model.ChatModel -import chat.simplex.common.platform.AppPlatform -import chat.simplex.common.platform.appPlatform +import chat.simplex.common.platform.* enum class LAMode { SYSTEM, @@ -55,8 +54,8 @@ fun PrivacySettingsView( showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), setPerformLA: (Boolean) -> Unit ) { - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), ) { val simplexLinkMode = chatModel.controller.appPrefs.simplexLinkMode AppBarTitle(stringResource(MR.strings.your_privacy)) @@ -473,8 +472,8 @@ fun SimplexLockView( } } - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.chat_lock)) SectionView { @@ -580,8 +579,8 @@ fun SimplexLockView( @Composable private fun SelfDestructInfoView() { - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING), + ColumnWithScrollBar( + Modifier.fillMaxWidth().padding(horizontal = DEFAULT_PADDING), ) { AppBarTitle(stringResource(MR.strings.self_destruct), withPadding = false) ReadableText(stringResource(MR.strings.if_you_enter_self_destruct_code)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt index cb3b16b227..399895870f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServerView.kt @@ -5,7 +5,6 @@ import SectionDividerSpaced import SectionItemView import SectionItemViewSpaceBetween import SectionView -import chat.simplex.common.platform.Log import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.selection.SelectionContainer @@ -20,13 +19,13 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import chat.simplex.common.platform.TAG import chat.simplex.common.model.* import chat.simplex.common.model.ServerAddress.Companion.parseServerAddress import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* import chat.simplex.common.views.newchat.QRCode import chat.simplex.common.model.ChatModel +import chat.simplex.common.platform.* import chat.simplex.res.MR import kotlinx.coroutines.* import kotlinx.coroutines.flow.distinctUntilChanged @@ -76,10 +75,9 @@ private fun ProtocolServerLayout( onUpdate: (ServerCfg) -> Unit, onDelete: () -> Unit, ) { - Column( + ColumnWithScrollBar( Modifier .fillMaxWidth() - .verticalScroll(rememberScrollState()) ) { AppBarTitle(stringResource(if (server.preset) MR.strings.smp_servers_preset_server else MR.strings.smp_servers_your_server)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServersView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServersView.kt index ad1648f1ea..fe847432fb 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServersView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/ProtocolServersView.kt @@ -22,6 +22,7 @@ import androidx.compose.ui.unit.dp import chat.simplex.common.model.ServerAddress.Companion.parseServerAddress import chat.simplex.common.views.helpers.* import chat.simplex.common.model.* +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.platform.appPlatform import chat.simplex.res.MR @@ -191,10 +192,9 @@ private fun ProtocolServersLayout( saveSMPServers: () -> Unit, showServer: (ServerCfg) -> Unit, ) { - Column( + ColumnWithScrollBar( Modifier .fillMaxWidth() - .verticalScroll(rememberScrollState()) ) { AppBarTitle(stringResource(if (serverProtocol == ServerProtocol.SMP) MR.strings.your_SMP_servers else MR.strings.your_XFTP_servers)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/RTCServers.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/RTCServers.kt index 50bed458cc..761a74d6e4 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/RTCServers.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/RTCServers.kt @@ -19,6 +19,7 @@ import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.common.model.ChatModel +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.ui.theme.* import chat.simplex.common.views.call.parseRTCIceServers import chat.simplex.common.views.helpers.* @@ -98,12 +99,11 @@ fun RTCServersLayout( saveRTCServers: () -> Unit, editOn: () -> Unit, ) { - Column { + ColumnWithScrollBar { AppBarTitle(stringResource(MR.strings.your_ICE_servers)) Column( Modifier .fillMaxWidth() - .verticalScroll(rememberScrollState()) .padding(horizontal = DEFAULT_PADDING), verticalArrangement = Arrangement.spacedBy(8.dp) ) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SetDeliveryReceiptsView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SetDeliveryReceiptsView.kt index c18fd3f6f6..f0960c1511 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SetDeliveryReceiptsView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SetDeliveryReceiptsView.kt @@ -74,8 +74,10 @@ private fun SetDeliveryReceiptsLayout( userCount: Int, ) { val endPadding = if (appPlatform.isDesktop) 56.dp else 0.dp + val (scrollBarAlpha, scrollModifier, scrollJob) = platform.desktopScrollBarComponents() + val scrollState = rememberScrollState() Column( - Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(top = DEFAULT_PADDING, end = endPadding), + Modifier.fillMaxSize().verticalScroll(scrollState).then(if (appPlatform.isDesktop) scrollModifier else Modifier).padding(top = DEFAULT_PADDING, end = endPadding), horizontalAlignment = Alignment.CenterHorizontally, ) { AppBarTitle(stringResource(MR.strings.delivery_receipts_title)) @@ -95,6 +97,11 @@ private fun SetDeliveryReceiptsLayout( SectionBottomSpacer() } + if (appPlatform.isDesktop) { + Box(Modifier.fillMaxSize().padding(end = endPadding)) { + platform.desktopScrollBar(scrollState, Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, false) + } + } } @Composable diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt index 3ef02f536a..298eb39737 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/SettingsView.kt @@ -105,10 +105,9 @@ fun SettingsLayout( val theme = CurrentColors.collectAsState() val uriHandler = LocalUriHandler.current Box(Modifier.fillMaxSize()) { - Column( + ColumnWithScrollBar( Modifier .fillMaxSize() - .verticalScroll(rememberScrollState()) .themedBackground(theme.value.base) .padding(top = if (appPlatform.isAndroid) DEFAULT_PADDING else DEFAULT_PADDING * 3) ) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressLearnMore.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressLearnMore.kt index 276c595435..63baece5cf 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressLearnMore.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressLearnMore.kt @@ -1,9 +1,10 @@ package chat.simplex.common.views.usersettings -import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import chat.simplex.common.platform.ColumnWithScrollBar +import chat.simplex.common.ui.theme.DEFAULT_PADDING import dev.icerock.moko.resources.compose.stringResource import chat.simplex.common.views.helpers.* import chat.simplex.common.views.onboarding.ReadableText @@ -12,8 +13,9 @@ import chat.simplex.res.MR @Composable fun UserAddressLearnMore() { - Column( - Modifier.verticalScroll(rememberScrollState()), + ColumnWithScrollBar(Modifier + .fillMaxHeight() + .padding(horizontal = DEFAULT_PADDING) ) { AppBarTitle(stringResource(MR.strings.simplex_address)) ReadableText(MR.strings.you_can_share_your_address) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt index ffaec8eb04..b595bd4e0e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserAddressView.kt @@ -7,9 +7,7 @@ import SectionTextFooter import SectionView import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable @@ -91,14 +89,7 @@ fun UserAddressView( }, learnMore = { ModalManager.start.showModal { - Column( - Modifier - .fillMaxHeight() - .padding(horizontal = DEFAULT_PADDING), - verticalArrangement = Arrangement.SpaceBetween - ) { - UserAddressLearnMore() - } + UserAddressLearnMore() } }, share = { userAddress: String -> clipboard.shareText(userAddress) }, @@ -182,9 +173,7 @@ private fun UserAddressLayout( deleteAddress: () -> Unit, saveAas: (AutoAcceptState, MutableState) -> Unit, ) { - Column( - Modifier.verticalScroll(rememberScrollState()), - ) { + ColumnWithScrollBar { AppBarTitle(stringResource(MR.strings.simplex_address), hostDevice(user?.remoteHostId), withPadding = false) Column( Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF), diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfileView.kt index 1f5177d08b..e3636ec9c5 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfileView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfileView.kt @@ -98,9 +98,8 @@ fun UserProfileLayout( } } ModalView(close = closeWithAlert) { - Column( + ColumnWithScrollBar( Modifier - .verticalScroll(scrollState) .padding(horizontal = DEFAULT_PADDING), ) { AppBarTitle(stringResource(MR.strings.your_current_profile)) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt index 1beccd516c..a7e57662b5 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/UserProfilesView.kt @@ -158,10 +158,9 @@ private fun UserProfilesLayout( unmuteUser: (User) -> Unit, showHiddenProfile: (User) -> Unit, ) { - Column( + ColumnWithScrollBar( Modifier .fillMaxWidth() - .verticalScroll(rememberScrollState()) ) { if (profileHidden.value) { SectionView { @@ -260,10 +259,9 @@ enum class UserProfileAction { @Composable private fun ProfileActionView(action: UserProfileAction, user: User, doAction: (String) -> Unit) { - Column( + ColumnWithScrollBar( Modifier .fillMaxWidth() - .verticalScroll(rememberScrollState()) ) { val actionPassword = rememberSaveable { mutableStateOf("") } val passwordValid by remember { derivedStateOf { actionPassword.value == actionPassword.value.trim() } } 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 new file mode 100644 index 0000000000..1caf96902d --- /dev/null +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/ScrollableColumn.desktop.kt @@ -0,0 +1,129 @@ +package chat.simplex.common.platform + +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.AnimationVector1D +import androidx.compose.foundation.* +import androidx.compose.foundation.gestures.FlingBehavior +import androidx.compose.foundation.interaction.* +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.input.pointer.* +import androidx.compose.ui.unit.dp +import chat.simplex.common.views.helpers.detectCursorMove +import chat.simplex.common.views.helpers.mixWith +import kotlinx.coroutines.* + +@Composable +actual fun LazyColumnWithScrollBar( + modifier: Modifier, + state: LazyListState, + contentPadding: PaddingValues, + reverseLayout: Boolean, + verticalArrangement: Arrangement.Vertical, + horizontalAlignment: Alignment.Horizontal, + flingBehavior: FlingBehavior, + userScrollEnabled: Boolean, + content: LazyListScope.() -> Unit +) { + if (appPlatform.isAndroid) { + LazyColumn(modifier, state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content) + } else { + val scope = rememberCoroutineScope() + val scrollBarAlpha = remember { Animatable(0f) } + val scrollJob: MutableState = remember { mutableStateOf(Job()) } + val scrollModifier = remember { + Modifier + .pointerInput(Unit) { + detectCursorMove { + scope.launch { + scrollBarAlpha.animateTo(1f) + } + scrollJob.value.cancel() + scrollJob.value = scope.launch { + delay(1000L) + scrollBarAlpha.animateTo(0f) + } + } + } + } + LazyColumn(modifier.then(if (appPlatform.isDesktop) scrollModifier else Modifier), state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled, content) + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.CenterEnd) { + DesktopScrollBar(rememberScrollbarAdapter(state), Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, reverseLayout) + } + } +} + +@Composable +actual fun ColumnWithScrollBar( + modifier: Modifier, + verticalArrangement: Arrangement.Vertical, + horizontalAlignment: Alignment.Horizontal, + state: ScrollState, + content: @Composable ColumnScope.() -> Unit +) { + val scope = rememberCoroutineScope() + val scrollBarAlpha = remember { Animatable(0f) } + val scrollJob: MutableState = remember { mutableStateOf(Job()) } + val scrollModifier = remember { + Modifier + .pointerInput(Unit) { + detectCursorMove { + scope.launch { + scrollBarAlpha.animateTo(1f) + } + scrollJob.value.cancel() + scrollJob.value = scope.launch { + delay(1000L) + scrollBarAlpha.animateTo(0f) + } + } + } + } + Column(modifier.verticalScroll(state).then(scrollModifier), verticalArrangement, horizontalAlignment, content) + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.CenterEnd) { + DesktopScrollBar(rememberScrollbarAdapter(state), Modifier.align(Alignment.CenterEnd).fillMaxHeight(), scrollBarAlpha, scrollJob, false) + } +} + +@Composable +fun DesktopScrollBar(adapter: androidx.compose.foundation.v2.ScrollbarAdapter, modifier: Modifier, scrollBarAlpha: Animatable, scrollJob: MutableState, reversed: Boolean) { + val scope = rememberCoroutineScope() + val interactionSource = remember { MutableInteractionSource() } + val isHovered by interactionSource.collectIsHoveredAsState() + val isDragged by interactionSource.collectIsDraggedAsState() + LaunchedEffect(isHovered, isDragged) { + scrollJob.value.cancel() + if (isHovered || isDragged) { + scrollBarAlpha.animateTo(1f) + } else { + scrollJob.value = scope.launch { + delay(1000L) + scrollBarAlpha.animateTo(0f) + } + } + } + VerticalScrollbar( + modifier = modifier.graphicsLayer { alpha = scrollBarAlpha.value } + .onPointerEvent(PointerEventType.Enter) { + scrollJob.value.cancel() + scope.launch { + scrollBarAlpha.animateTo(1f) + } + }, + reverseLayout = reversed, + style = LocalScrollbarStyle.current.copy( + thickness = if (isHovered || isDragged) 10.dp else 6.dp, + shape = RoundedCornerShape(if (isHovered || isDragged) 5.dp else 3.dp), + unhoverColor = if (MaterialTheme.colors.isLight) MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.7f) else MaterialTheme.colors.onBackground.mixWith(MaterialTheme.colors.background, 0.3f), + hoverColor = if (MaterialTheme.colors.isLight) MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.6f) else MaterialTheme.colors.onBackground.mixWith(MaterialTheme.colors.background, 0.4f) + ), + adapter = adapter, + interactionSource = interactionSource + ) +} diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/Appearance.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/Appearance.desktop.kt index 1a8ad010e3..5ffc68be79 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/Appearance.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/usersettings/Appearance.desktop.kt @@ -4,8 +4,6 @@ import SectionBottomSpacer import SectionDividerSpaced import SectionView import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable @@ -13,6 +11,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import chat.simplex.common.model.ChatModel import chat.simplex.common.model.SharedPreference +import chat.simplex.common.platform.ColumnWithScrollBar import chat.simplex.common.platform.defaultLocale import chat.simplex.common.ui.theme.ThemeColor import chat.simplex.common.views.helpers.* @@ -43,8 +42,8 @@ fun AppearanceScope.AppearanceLayout( showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), editColor: (ThemeColor, Color) -> Unit, ) { - Column( - Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + ColumnWithScrollBar( + Modifier.fillMaxWidth(), ) { AppBarTitle(stringResource(MR.strings.appearance_settings)) SectionView(stringResource(MR.strings.settings_section_title_language), padding = PaddingValues()) { diff --git a/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt b/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt index e32b0ae79a..7171f17991 100644 --- a/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt +++ b/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt @@ -1,7 +1,19 @@ package chat.simplex.desktop +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.AnimationVector1D +import androidx.compose.foundation.* +import androidx.compose.foundation.interaction.* +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.* +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.pointer.* import chat.simplex.common.platform.* +import chat.simplex.common.platform.DesktopPlatform import chat.simplex.common.showApp +import chat.simplex.common.views.helpers.* +import kotlinx.coroutines.* import java.io.File fun main() { @@ -12,6 +24,7 @@ fun main() { return showApp() } +@OptIn(ExperimentalComposeUiApi::class) @Suppress("UnsafeDynamicallyLoadedCode") private fun initHaskell() { val resourcesDir = File(System.getProperty("compose.application.resources.dir")) @@ -27,6 +40,40 @@ private fun initHaskell() { System.setProperty("jna.library.path", vlcDir.absolutePath) //discoverVlcLibs(File(File(vlcDir, "vlc"), "plugins").absolutePath) initHS() + + platform = object: PlatformInterface { + @Composable + override fun desktopScrollBarComponents(): Triple, Modifier, MutableState> { + val scope = rememberCoroutineScope() + val scrollBarAlpha = remember { Animatable(0f) } + val scrollJob: MutableState = remember { mutableStateOf(Job()) } + val modifier = remember { + Modifier.pointerInput(Unit) { + detectCursorMove { + scope.launch { + scrollBarAlpha.animateTo(1f) + } + scrollJob.value.cancel() + scrollJob.value = scope.launch { + delay(1000L) + scrollBarAlpha.animateTo(0f) + } + } + } + } + return Triple(scrollBarAlpha, modifier, scrollJob) + } + + @Composable + override fun desktopScrollBar(state: LazyListState, modifier: Modifier, scrollBarAlpha: Animatable, scrollJob: MutableState, reversed: Boolean) { + DesktopScrollBar(rememberScrollbarAdapter(scrollState = state), modifier, scrollBarAlpha, scrollJob, reversed) + } + + @Composable + override fun desktopScrollBar(state: ScrollState, modifier: Modifier, scrollBarAlpha: Animatable, scrollJob: MutableState, reversed: Boolean) { + DesktopScrollBar(rememberScrollbarAdapter(scrollState = state), modifier, scrollBarAlpha, scrollJob, reversed) + } + } } private fun windowsLoadRequiredLibs(libsTmpDir: File, vlcDir: File) {