dropdownmenu, userpicker, onehandui, call layout, columns

This commit is contained in:
Avently
2024-10-22 16:55:26 +07:00
parent 4b985907a2
commit 3fee8a1133
13 changed files with 70 additions and 30 deletions
@@ -34,6 +34,7 @@ private val USER_PICKER_ROW_PADDING = 16.dp
@Composable
actual fun UserPickerUsersSection(
users: List<UserInfo>,
iconColor: Color,
stopped: Boolean,
onUserClicked: (user: User) -> Unit,
) {
@@ -151,7 +151,9 @@ fun MainScreen() {
}
SetupClipboardListener()
if (appPlatform.isAndroid) {
AndroidScreen(userPickerState)
AndroidWrapInCallLayout {
AndroidScreen(userPickerState)
}
} else {
DesktopScreen(userPickerState)
}
@@ -183,7 +185,9 @@ fun MainScreen() {
}
}
if (appPlatform.isAndroid) {
ModalManager.fullscreen.showInView()
AndroidWrapInCallLayout {
ModalManager.fullscreen.showInView()
}
SwitchingUsersView()
}
@@ -250,11 +254,23 @@ fun MainScreen() {
val ANDROID_CALL_TOP_PADDING = 40.dp
@Composable
fun AndroidWrapInCallLayout(content: @Composable () -> Unit) {
val call = remember { chatModel.activeCall}.value
val showCallArea = call != null && call.callState != CallState.WaitCapabilities && call.callState != CallState.InvitationAccepted
Box {
Box(Modifier.padding(top = if (showCallArea) ANDROID_CALL_TOP_PADDING else 0.dp)) {
content()
}
if (call != null && showCallArea) {
ActiveCallInteractiveArea(call)
}
}
}
@Composable
fun AndroidScreen(userPickerState: MutableStateFlow<AnimatedViewState>) {
BoxWithConstraints {
val call = remember { chatModel.activeCall} .value
val showCallArea = call != null && call.callState != CallState.WaitCapabilities && call.callState != CallState.InvitationAccepted
val currentChatId = remember { mutableStateOf(chatModel.chatId.value) }
val offset = remember { Animatable(if (chatModel.chatId.value == null) 0f else maxWidth.value) }
Box(
@@ -265,7 +281,6 @@ fun AndroidScreen(userPickerState: MutableStateFlow<AnimatedViewState>) {
// But offset is remembered already, so this is a better way than dropping a value of offset
translationX = -minOf(offset.value.dp, maxWidth).toPx()
}
.padding(top = if (showCallArea) ANDROID_CALL_TOP_PADDING else 0.dp)
) {
StartPartOfScreen(userPickerState)
}
@@ -294,15 +309,11 @@ fun AndroidScreen(userPickerState: MutableStateFlow<AnimatedViewState>) {
}
Box(Modifier
.graphicsLayer { translationX = maxWidth.toPx() - minOf(offset.value.dp, maxWidth).toPx() }
.padding(top = if (showCallArea) ANDROID_CALL_TOP_PADDING else 0.dp)
) Box2@{
currentChatId.value?.let {
ChatView(currentChatId, onComposed)
}
}
if (call != null && showCallArea) {
ActiveCallInteractiveArea(call)
}
}
}
@@ -52,7 +52,7 @@ fun CreateProfile(chatModel: ChatModel, close: () -> Unit) {
modifier = Modifier.fillMaxSize()
) {
Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
AppBarTitle(stringResource(MR.strings.create_profile), bottomPadding = DEFAULT_PADDING)
AppBarTitle(stringResource(MR.strings.create_profile), withPadding = false, bottomPadding = DEFAULT_PADDING)
Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Text(
stringResource(MR.strings.display_name),
@@ -864,11 +864,14 @@ fun ColumnScope.ChatInfoToolbar(
onSearchValueChanged = onSearchValueChanged,
buttons = barButtons
)
Box(Modifier
.fillMaxWidth()
.wrapContentSize(Alignment.TopEnd)
) {
DefaultDropdownMenu(showMenu) {
Box(Modifier.fillMaxWidth().wrapContentSize(Alignment.TopEnd)) {
val density = LocalDensity.current
val width = remember { mutableStateOf(250.dp) }
DefaultDropdownMenu(
showMenu,
modifier = Modifier.onSizeChanged { with(density) { width.value = it.width.toDp().coerceAtLeast(250.dp) } },
offset = DpOffset(-width.value, 0.dp)
) {
menuItems.forEach { it() }
}
}
@@ -1373,8 +1376,14 @@ fun BoxScope.FloatingButtons(
onLongClick = { showDropDown.value = true }
)
Box(Modifier.align(Alignment.TopEnd)) {
DefaultDropdownMenu(showDropDown, offset = DpOffset(-DEFAULT_PADDING, 24.dp + fabSize + topPaddingToContent())) {
Box(Modifier.fillMaxWidth().wrapContentSize(Alignment.TopEnd)) {
val density = LocalDensity.current
val width = remember { mutableStateOf(250.dp) }
DefaultDropdownMenu(
showDropDown,
modifier = Modifier.onSizeChanged { with(density) { width.value = it.width.toDp().coerceAtLeast(250.dp) } },
offset = DpOffset(-DEFAULT_PADDING - width.value, 24.dp + fabSize + topPaddingToContent())
) {
ItemAction(
generalGetString(MR.strings.mark_read),
painterResource(MR.images.ic_check),
@@ -1,9 +1,11 @@
package chat.simplex.common.views.chat
import SectionBottomSpacer
import androidx.compose.foundation.layout.*
import androidx.compose.material.Text
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 chat.simplex.common.views.helpers.*
import chat.simplex.common.views.newchat.QRCodeScanner
@@ -12,7 +14,7 @@ import dev.icerock.moko.resources.compose.stringResource
@Composable
fun ScanCodeView(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit, close: () -> Unit) {
Column(
ColumnWithScrollBar(
Modifier.fillMaxSize()
) {
AppBarTitle(stringResource(MR.strings.scan_code))
@@ -28,5 +30,6 @@ fun ScanCodeView(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit, close: ()
}
}
Text(stringResource(MR.strings.scan_code_from_contacts_app), Modifier.padding(horizontal = DEFAULT_PADDING))
SectionBottomSpacer()
}
}
@@ -23,6 +23,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.*
import chat.simplex.common.model.*
import chat.simplex.common.model.ChatController.appPrefs
import chat.simplex.common.model.ChatController.stopRemoteHostAndReloadHosts
import chat.simplex.common.model.ChatModel.controller
import chat.simplex.common.ui.theme.*
@@ -137,12 +138,17 @@ fun UserPicker(
}
}
val oneHandUI = remember { appPrefs.oneHandUI.state }
val shouldDrawProfilePicturesDarker = appPlatform.isDesktop && MaterialTheme.colors.secondaryVariant == LightColorPalette.secondaryVariant && MaterialTheme.colors.background == LightColorPalette.background
val iconColor = if (shouldDrawProfilePicturesDarker) MaterialTheme.colors.secondaryVariant.darker(0.05f) else MaterialTheme.colors.secondaryVariant
val background = MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, alpha = 1 - userPickerAlpha())
PlatformUserPicker(
modifier = Modifier
.height(IntrinsicSize.Min)
.fillMaxWidth()
.then(if (newChat.isVisible()) Modifier.shadow(8.dp, clip = true) else Modifier)
.background(if (appPlatform.isAndroid) MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, alpha = 1 - userPickerAlpha()) else MaterialTheme.colors.surface)
.then(if (newChat.isVisible()) Modifier.shadow(8.dp, clip = true, ambientColor = background) else Modifier)
.padding(top = if (appPlatform.isDesktop && oneHandUI.value) 14.dp else 0.dp)
.background(background)
.padding(bottom = USER_PICKER_SECTION_SPACING - DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL),
pickerState = userPickerState
) {
@@ -198,12 +204,13 @@ fun UserPicker(
UserPickerUsersSection(
users = users,
onUserClicked = onUserClicked,
iconColor = iconColor,
stopped = stopped
)
}
} else if (currentUser != null) {
SectionItemView({ onUserClicked(currentUser) }, 80.dp, padding = PaddingValues(start = 16.dp, end = DEFAULT_PADDING), disabled = stopped) {
ProfilePreview(currentUser.profile, stopped = stopped)
ProfilePreview(currentUser.profile, iconColor = iconColor, stopped = stopped)
}
}
}
@@ -234,6 +241,7 @@ fun UserPicker(
Column(modifier = Modifier.padding(vertical = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL)) {
UserPickerUsersSection(
users = inactiveUsers,
iconColor = iconColor,
onUserClicked = onUserClicked,
stopped = stopped
)
@@ -519,6 +527,7 @@ private fun DevicePickerRow(
@Composable
expect fun UserPickerUsersSection(
users: List<UserInfo>,
iconColor: Color,
stopped: Boolean,
onUserClicked: (user: User) -> Unit,
)
@@ -14,6 +14,7 @@ import androidx.compose.ui.unit.dp
@Composable
fun DefaultDropdownMenu(
showMenu: MutableState<Boolean>,
modifier: Modifier = Modifier,
offset: DpOffset = DpOffset(0.dp, 0.dp),
dropdownMenuItems: (@Composable () -> Unit)?
) {
@@ -23,7 +24,7 @@ fun DefaultDropdownMenu(
DropdownMenu(
expanded = showMenu.value,
onDismissRequest = { showMenu.value = false },
modifier = Modifier
modifier = modifier
.widthIn(min = 250.dp)
.background(MaterialTheme.colors.surface)
.padding(vertical = 4.dp),
@@ -89,7 +89,7 @@ private fun ContactConnectionInfoLayout(
SettingsActionItemWithContent(
icon = painterResource(MR.images.ic_theater_comedy_filled),
text = null,
click = { ModalManager.start.showModal { IncognitoView() } },
click = { ModalManager.end.showModal { IncognitoView() } },
iconColor = Indigo,
extraPadding = false
) {
@@ -33,6 +33,7 @@ import chat.simplex.common.model.ChatModel.controller
import chat.simplex.common.model.ChatModel.withChats
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.chat.topPaddingToContent
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.usersettings.*
import chat.simplex.res.MR
@@ -398,7 +399,7 @@ fun ActiveProfilePicker(
.fillMaxSize()
.alpha(if (progressByTimeout) 0.6f else 1f)
) {
LazyColumnWithScrollBar(userScrollEnabled = !switchingProfile.value) {
LazyColumnWithScrollBar(Modifier.padding(top = topPaddingToContent()), userScrollEnabled = !switchingProfile.value) {
item {
AppBarTitle(stringResource(MR.strings.select_chat_profile), hostDevice(rhId), bottomPadding = DEFAULT_PADDING)
}
@@ -7,6 +7,7 @@ import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.common.model.ServerAddress.Companion.parseServerAddress
import chat.simplex.common.model.ServerCfg
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.ui.theme.DEFAULT_PADDING
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.newchat.QRCodeScanner
@@ -17,7 +18,7 @@ expect fun ScanProtocolServer(rhId: Long?, onNext: (ServerCfg) -> Unit)
@Composable
fun ScanProtocolServerLayout(rhId: Long?, onNext: (ServerCfg) -> Unit) {
Column(
ColumnWithScrollBar(
Modifier
.fillMaxSize()
) {
@@ -1,6 +1,5 @@
package chat.simplex.common.views.usersettings
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@@ -8,6 +7,7 @@ import androidx.compose.ui.Modifier
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.common.BuildConfigCommon
import chat.simplex.common.model.CoreVersionInfo
import chat.simplex.common.platform.ColumnWithScrollBar
import chat.simplex.common.platform.appPlatform
import chat.simplex.common.ui.theme.DEFAULT_PADDING
import chat.simplex.common.views.helpers.AppBarTitle
@@ -15,7 +15,7 @@ import chat.simplex.res.MR
@Composable
fun VersionInfoView(info: CoreVersionInfo) {
Column(
ColumnWithScrollBar(
Modifier.padding(horizontal = DEFAULT_PADDING),
) {
AppBarTitle(stringResource(MR.strings.app_version_title), withPadding = false)
@@ -10,6 +10,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import chat.simplex.common.model.ChatController.appPrefs
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.call.Call
@@ -27,14 +28,15 @@ actual fun ActiveCallInteractiveArea(call: Call) {
CompositionLocalProvider(
LocalIndication provides NoIndication
) {
val oneHandUI = remember { appPrefs.oneHandUI.state }
Box(
Modifier
.fillMaxSize(),
contentAlignment = Alignment.BottomEnd
contentAlignment = if (oneHandUI.value) Alignment.TopEnd else Alignment.BottomEnd
) {
Box(
Modifier
.padding(end = 15.dp, bottom = 92.dp)
.padding(end = 15.dp, top = if (oneHandUI.value) 15.dp else 0.dp, bottom = if (oneHandUI.value) 0.dp else 92.dp)
.size(67.dp)
.combinedClickable(onClick = {
val chat = chatModel.getChat(call.contact.id)
@@ -10,6 +10,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
@@ -26,6 +27,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
@Composable
actual fun UserPickerUsersSection(
users: List<UserInfo>,
iconColor: Color,
stopped: Boolean,
onUserClicked: (user: User) -> Unit,
) {
@@ -58,7 +60,7 @@ actual fun UserPickerUsersSection(
) {
val user = u.user
Box {
ProfileImage(size = 55.dp, image = user.profile.image, color = MaterialTheme.colors.secondaryVariant)
ProfileImage(size = 55.dp, image = user.profile.image, color = iconColor)
if (u.unreadCount > 0 && !user.activeUser) {
unreadBadge(u.unreadCount, user.showNtfs, true)