diff --git a/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt b/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt index 41343539cf..17ab557f68 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt @@ -20,7 +20,6 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp import androidx.fragment.app.FragmentActivity import androidx.lifecycle.* import chat.simplex.app.model.ChatModel @@ -338,10 +337,7 @@ fun MainPage( } } } - onboarding == OnboardingStage.Step1_SimpleXInfo -> - Box(Modifier.padding(horizontal = 20.dp)) { - SimpleXInfo(chatModel, onboarding = true) - } + onboarding == OnboardingStage.Step1_SimpleXInfo -> SimpleXInfo(chatModel, onboarding = true) onboarding == OnboardingStage.Step2_CreateProfile -> CreateProfile(chatModel) } ModalManager.shared.showInView() diff --git a/apps/android/app/src/main/java/chat/simplex/app/ui/theme/Theme.kt b/apps/android/app/src/main/java/chat/simplex/app/ui/theme/Theme.kt index e5b7bba032..873d3f313f 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/ui/theme/Theme.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/ui/theme/Theme.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp import chat.simplex.app.SimplexApp import kotlinx.coroutines.flow.MutableStateFlow @@ -13,6 +14,10 @@ enum class DefaultTheme { SYSTEM, DARK, LIGHT } +val DEFAULT_PADDING = 16.dp +val DEFAULT_SPACE_AFTER_ICON = 4.dp +val DEFAULT_PADDING_HALF = DEFAULT_PADDING / 2 + val DarkColorPalette = darkColors( primary = SimplexBlue, // If this value changes also need to update #0088ff in string resource files primaryVariant = SimplexGreen, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/TerminalView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/TerminalView.kt index 608cbb2bfc..0c6ee01829 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/TerminalView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/TerminalView.kt @@ -150,14 +150,14 @@ fun TerminalLog(terminalItems: List) { maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier - .padding(horizontal = 8.dp, vertical = 4.dp) + .fillMaxWidth() .clickable { ModalManager.shared.showModal { SelectionContainer(modifier = Modifier.verticalScroll(rememberScrollState())) { Text(item.details) } } - } + }.padding(horizontal = 8.dp, vertical = 4.dp) ) } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt index b7faf8e8b6..4ed162ec02 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt @@ -1,7 +1,6 @@ package chat.simplex.app.views -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable +import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField @@ -26,12 +25,13 @@ import chat.simplex.app.R import chat.simplex.app.SimplexService import chat.simplex.app.model.ChatModel import chat.simplex.app.model.Profile -import chat.simplex.app.ui.theme.HighOrLowlight -import chat.simplex.app.ui.theme.SimpleButton +import chat.simplex.app.ui.theme.* +import chat.simplex.app.views.helpers.AppBarTitle import chat.simplex.app.views.helpers.withApi import chat.simplex.app.views.onboarding.OnboardingStage import chat.simplex.app.views.onboarding.ReadableText import com.google.accompanist.insets.navigationBarsWithImePadding +import kotlinx.coroutines.delay fun isValidDisplayName(name: String) : Boolean { return (name.firstOrNull { it.isWhitespace() }) == null @@ -45,13 +45,9 @@ fun CreateProfilePanel(chatModel: ChatModel) { Surface(Modifier.background(MaterialTheme.colors.onBackground)) { Column( - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()) ) { - Text( - stringResource(R.string.create_profile), - style = MaterialTheme.typography.h4, - modifier = Modifier.padding(vertical = 5.dp) - ) + AppBarTitle(stringResource(R.string.create_profile), false) ReadableText(R.string.your_profile_is_stored_on_your_device) ReadableText(R.string.profile_is_only_shared_with_your_contacts) Spacer(Modifier.height(10.dp)) @@ -102,6 +98,7 @@ fun CreateProfilePanel(chatModel: ChatModel) { } LaunchedEffect(Unit) { + delay(300) focusRequester.requestFocus() } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatInfoView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatInfoView.kt index dc7deb6b3d..b07a436d00 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatInfoView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatInfoView.kt @@ -35,6 +35,7 @@ import chat.simplex.app.SimplexApp import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* +import chat.simplex.app.views.usersettings.SettingsActionItem import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* @@ -143,7 +144,11 @@ fun ChatInfoLayout( if (connStats != null) { SectionView(title = stringResource(R.string.conn_stats_section_title_servers)) { - SectionItemView { + SectionItemView({ + AlertManager.shared.showAlertMsg( + generalGetString(R.string.network_status), + chat.serverInfo.networkStatus.statusExplanation + )}) { NetworkStatusRow(chat.serverInfo.networkStatus) } val rcvServers = connStats.rcvServers @@ -160,13 +165,9 @@ fun ChatInfoLayout( SectionSpacer() } SectionView { - SectionItemView { - ClearChatButton(clearChat) - } + ClearChatButton(clearChat) SectionDivider() - SectionItemView { - DeleteContactButton(deleteContact) - } + DeleteContactButton(deleteContact) } SectionSpacer() @@ -244,14 +245,7 @@ private fun LocalAliasEditor(initialValue: String, updateValue: (String) -> Unit @Composable fun NetworkStatusRow(networkStatus: Chat.NetworkStatus) { Row( - Modifier - .fillMaxSize() - .clickable { - AlertManager.shared.showAlertMsg( - generalGetString(R.string.network_status), - networkStatus.statusExplanation - ) - }, + Modifier.fillMaxSize(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { @@ -306,39 +300,25 @@ fun SimplexServers(text: String, servers: List) { } @Composable -fun ClearChatButton(clearChat: () -> Unit) { - Row( - Modifier - .fillMaxSize() - .clickable { clearChat() }, - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - Icons.Outlined.Restore, - stringResource(R.string.clear_chat_button), - tint = WarningOrange - ) - Spacer(Modifier.size(8.dp)) - Text(stringResource(R.string.clear_chat_button), color = WarningOrange) - } +fun ClearChatButton(onClick: () -> Unit) { + SettingsActionItem( + Icons.Outlined.Restore, + stringResource(R.string.clear_chat_button), + click = onClick, + textColor = WarningOrange, + iconColor = WarningOrange, + ) } @Composable -fun DeleteContactButton(deleteContact: () -> Unit) { - Row( - Modifier - .fillMaxSize() - .clickable { deleteContact() }, - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - Icons.Outlined.Delete, - stringResource(R.string.button_delete_contact), - tint = Color.Red - ) - Spacer(Modifier.size(8.dp)) - Text(stringResource(R.string.button_delete_contact), color = Color.Red) - } +fun DeleteContactButton(onClick: () -> Unit) { + SettingsActionItem( + Icons.Outlined.Delete, + stringResource(R.string.button_delete_contact), + click = onClick, + textColor = Color.Red, + iconColor = Color.Red, + ) } private fun setContactAlias(contactApiId: Long, localAlias: String, chatModel: ChatModel, onChatUpdated: (Chat) -> Unit) = withApi { diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt index 7453bdd6ae..64872cd70d 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt @@ -78,7 +78,6 @@ fun ChatView(chatModel: ChatModel) { } else { val chat = activeChat!! BackHandler { chatModel.chatId.value = null } - // We need to have real unreadCount value for displaying it inside top right button // Having activeChat reloaded on every change in it is inefficient (UI lags) val unreadCount = remember { @@ -113,25 +112,15 @@ fun ChatView(chatModel: ChatModel) { val cInfo = chat.chatInfo if (cInfo is ChatInfo.Direct) { val contactInfo = chatModel.controller.apiContactInfo(cInfo.apiId) - ModalManager.shared.showCustomModal { close -> - ModalView( - close = close, modifier = Modifier, - background = if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight - ) { - ChatInfoView(chatModel, cInfo.contact, contactInfo?.first, contactInfo?.second, chat.chatInfo.localAlias, close) { - activeChat = it - } + ModalManager.shared.showModalCloseable(true) { close -> + ChatInfoView(chatModel, cInfo.contact, contactInfo?.first, contactInfo?.second, chat.chatInfo.localAlias, close) { + activeChat = it } } } else if (cInfo is ChatInfo.Group) { setGroupMembers(cInfo.groupInfo, chatModel) - ModalManager.shared.showCustomModal { close -> - ModalView( - close = close, modifier = Modifier, - background = if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight - ) { - GroupChatInfoView(chatModel, close) - } + ModalManager.shared.showModalCloseable(true) { close -> + GroupChatInfoView(chatModel, close) } } } @@ -139,13 +128,8 @@ fun ChatView(chatModel: ChatModel) { showMemberInfo = { groupInfo: GroupInfo, member: GroupMember -> withApi { val stats = chatModel.controller.apiGroupMemberInfo(groupInfo.groupId, member.groupMemberId) - ModalManager.shared.showCustomModal { close -> - ModalView( - close = close, modifier = Modifier, - background = if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight - ) { - GroupMemberInfoView(groupInfo, member, stats, chatModel, close, close) - } + ModalManager.shared.showModalCloseable(true) { close -> + GroupMemberInfoView(groupInfo, member, stats, chatModel, close, close) } } }, @@ -195,13 +179,8 @@ fun ChatView(chatModel: ChatModel) { addMembers = { groupInfo -> withApi { setGroupMembers(groupInfo, chatModel) - ModalManager.shared.showCustomModal { close -> - ModalView( - close = close, modifier = Modifier, - background = if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight - ) { + ModalManager.shared.showModalCloseable(true) { close -> AddGroupMembersView(groupInfo, chatModel, close) - } } } }, @@ -355,7 +334,6 @@ fun ChatInfoToolbar( } } } - val ntfsEnabled = remember { mutableStateOf(chat.chatInfo.ntfsEnabled) } menuItems.add { ItemAction( @@ -463,7 +441,6 @@ fun BoxWithConstraintsScope.ChatItemsList( val scope = rememberCoroutineScope() val uriHandler = LocalUriHandler.current val cxt = LocalContext.current - // Helps to scroll to bottom after moving from Group to Direct chat // and prevents scrolling to bottom on orientation change var shouldAutoScroll by rememberSaveable { mutableStateOf(true) } @@ -492,7 +469,6 @@ fun BoxWithConstraintsScope.ChatItemsList( } Spacer(Modifier.size(8.dp)) - val reversedChatItems by remember { derivedStateOf { chatItems.reversed() } } LazyColumn(Modifier.align(Alignment.BottomCenter), state = listState, reverseLayout = true) { itemsIndexed(reversedChatItems) { i, cItem -> @@ -591,10 +567,9 @@ fun BoxWithConstraintsScope.FloatingButtons( listState: LazyListState ) { val scope = rememberCoroutineScope() - var firstVisibleIndex by remember { mutableStateOf(listState.firstVisibleItemIndex) } var lastIndexOfVisibleItems by remember { mutableStateOf(listState.layoutInfo.visibleItemsInfo.lastIndex) } - var firstItemIsVisible by remember { mutableStateOf(firstVisibleIndex == 0) } + var firstItemIsVisible by remember { mutableStateOf(firstVisibleIndex == 0) } LaunchedEffect(listState) { snapshotFlow { listState.firstVisibleItemIndex } @@ -614,18 +589,15 @@ fun BoxWithConstraintsScope.FloatingButtons( lastIndexOfVisibleItems = it } } - val bottomUnreadCount by remember { derivedStateOf { if (unreadCount.value == 0) return@derivedStateOf 0 - val from = chatItems.lastIndex - firstVisibleIndex - lastIndexOfVisibleItems if (chatItems.size <= from || from < 0) return@derivedStateOf 0 chatItems.subList(from, chatItems.size).count { it.isRcvNew } } } - val firstVisibleOffset = (-with(LocalDensity.current) { maxHeight.roundToPx() } * 0.8).toInt() LaunchedEffect(bottomUnreadCount, firstItemIsVisible) { @@ -851,7 +823,7 @@ fun PreviewChatLayout() { chatModelIncognito = false, back = {}, info = {}, - showMemberInfo = {_, _ -> }, + showMemberInfo = { _, _ -> }, loadPrevMessages = { _ -> }, deleteMessage = { _, _ -> }, receiveFile = {}, @@ -909,7 +881,7 @@ fun PreviewGroupChatLayout() { chatModelIncognito = false, back = {}, info = {}, - showMemberInfo = {_, _ -> }, + showMemberInfo = { _, _ -> }, loadPrevMessages = { _ -> }, deleteMessage = { _, _ -> }, receiveFile = {}, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt index 6a5b761cf7..205ad79492 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt @@ -29,6 +29,7 @@ import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.chat.ChatInfoToolbarTitle import chat.simplex.app.views.helpers.* +import chat.simplex.app.views.usersettings.SettingsActionItem @Composable fun AddGroupMembersView(groupInfo: GroupInfo, chatModel: ChatModel, close: () -> Unit) { @@ -91,6 +92,7 @@ fun AddGroupMembersLayout( .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.Start, ) { + AppBarTitle(stringResource(R.string.button_add_members)) Row( Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center @@ -120,9 +122,7 @@ fun AddGroupMembersLayout( RoleSelectionRow(groupInfo, selectedRole) } SectionDivider() - SectionItemView { - InviteMembersButton(inviteMembers, disabled = selectedContacts.isEmpty()) - } + InviteMembersButton(inviteMembers, disabled = selectedContacts.isEmpty()) } SectionCustomFooter { InviteSectionFooter(selectedContactsCount = selectedContacts.count(), clearSelection) @@ -144,93 +144,43 @@ fun RoleSelectionRow(groupInfo: GroupInfo, selectedRole: MutableState) { - val options = GroupMemberRole.values() - .filter { it <= groupInfo.membership.memberRole } - var expanded by remember { mutableStateOf(false) } - - ExposedDropdownMenuBox( - expanded = expanded, - onExpandedChange = { - expanded = !expanded - } - ) { - Row( - Modifier.fillMaxWidth(0.7f), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.End - ) { - Text( - selectedRole.value.text, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - color = HighOrLowlight - ) - Spacer(Modifier.size(4.dp)) - Icon( - if (!expanded) Icons.Outlined.ExpandMore else Icons.Outlined.ExpandLess, - generalGetString(R.string.invite_to_group_button), - modifier = Modifier.padding(start = 8.dp), - tint = HighOrLowlight - ) - } - ExposedDropdownMenu( - expanded = expanded, - onDismissRequest = { - expanded = false - } - ) { - options.forEach { selectionOption -> - DropdownMenuItem( - onClick = { - selectedRole.value = selectionOption - expanded = false - } - ) { - Text( - selectionOption.text, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - } - } - } - } -} - -@Composable -fun InviteMembersButton(inviteMembers: () -> Unit, disabled: Boolean) { - val modifier = if (disabled) Modifier else Modifier.clickable { inviteMembers() } - Row( - modifier.fillMaxSize(), - horizontalArrangement = Arrangement.End, - verticalAlignment = Alignment.CenterVertically - ) { - val color = if (disabled) HighOrLowlight else MaterialTheme.colors.primary - Text(stringResource(R.string.invite_to_group_button), color = color) - Spacer(Modifier.size(8.dp)) - Icon( - Icons.Outlined.Check, - stringResource(R.string.invite_to_group_button), - tint = color + val values = GroupMemberRole.values().filter { it <= groupInfo.membership.memberRole }.map { it to it.text } + ExposedDropDownSettingRow( + generalGetString(R.string.new_member_role), + values, + selectedRole, + icon = null, + enabled = remember { mutableStateOf(true) }, + onSelected = { selectedRole.value = it } ) } } +@Composable +fun InviteMembersButton(onClick: () -> Unit, disabled: Boolean) { + SettingsActionItem( + Icons.Outlined.Check, + stringResource(R.string.invite_to_group_button), + click = onClick, + textColor = MaterialTheme.colors.primary, + iconColor = MaterialTheme.colors.primary, + disabled = disabled, + ) +} + @Composable fun InviteSectionFooter(selectedContactsCount: Int, clearSelection: () -> Unit) { Row( Modifier.fillMaxWidth(), - horizontalArrangement = if (selectedContactsCount >= 1) Arrangement.SpaceBetween else Arrangement.End, + horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { if (selectedContactsCount >= 1) { + Text( + String.format(generalGetString(R.string.num_contacts_selected), selectedContactsCount), + color = HighOrLowlight, + fontSize = 12.sp + ) Box( Modifier.clickable { clearSelection() } ) { @@ -240,12 +190,6 @@ fun InviteSectionFooter(selectedContactsCount: Int, clearSelection: () -> Unit) fontSize = 12.sp ) } - - Text( - String.format(generalGetString(R.string.num_contacts_selected), selectedContactsCount), - color = HighOrLowlight, - fontSize = 12.sp - ) } else { Text( stringResource(R.string.no_contacts_selected), @@ -266,12 +210,10 @@ fun ContactList( ) { Column { contacts.forEachIndexed { index, contact -> - SectionItemView { - ContactCheckRow( - contact, groupInfo, addContact, removeContact, - checked = selectedContacts.contains(contact.apiId) - ) - } + ContactCheckRow( + contact, groupInfo, addContact, removeContact, + checked = selectedContacts.contains(contact.apiId) + ) if (index < contacts.lastIndex) { SectionDivider() } @@ -300,30 +242,21 @@ fun ContactCheckRow( icon = Icons.Outlined.Circle iconColor = HighOrLowlight } - Row( - Modifier - .fillMaxSize() - .clickable { - if (prohibitedToInviteIncognito) { - showProhibitedToInviteIncognitoAlertDialog() - } else if (!checked) - addContact(contact.apiId) - else - removeContact(contact.apiId) - }, - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(4.dp) - ) { - ProfileImage(size = 36.dp, contact.image) - Text( - contact.chatViewName, maxLines = 1, overflow = TextOverflow.Ellipsis, - color = if (prohibitedToInviteIncognito) HighOrLowlight else Color.Unspecified - ) - } + SectionItemView(click = { + if (prohibitedToInviteIncognito) { + showProhibitedToInviteIncognitoAlertDialog() + } else if (!checked) + addContact(contact.apiId) + else + removeContact(contact.apiId) + }) { + ProfileImage(size = 36.dp, contact.image) + Spacer(Modifier.width(DEFAULT_SPACE_AFTER_ICON)) + Text( + contact.chatViewName, maxLines = 1, overflow = TextOverflow.Ellipsis, + color = if (prohibitedToInviteIncognito) HighOrLowlight else Color.Unspecified + ) + Spacer(Modifier.fillMaxWidth().weight(1f)) Icon( icon, contentDescription = stringResource(R.string.icon_descr_contact_checked), diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt index 538cd5a3cd..1b35d1b8bd 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt @@ -46,26 +46,16 @@ fun GroupChatInfoView(chatModel: ChatModel, close: () -> Unit) { addMembers = { withApi { setGroupMembers(groupInfo, chatModel) - ModalManager.shared.showCustomModal { close -> - ModalView( - close = close, modifier = Modifier, - background = if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight - ) { - AddGroupMembersView(groupInfo, chatModel, close) - } + ModalManager.shared.showModalCloseable(true) { close -> + AddGroupMembersView(groupInfo, chatModel, close) } } }, showMemberInfo = { member -> withApi { val stats = chatModel.controller.apiGroupMemberInfo(groupInfo.groupId, member.groupMemberId) - ModalManager.shared.showCustomModal { closeCurrent -> - ModalView( - close = closeCurrent, modifier = Modifier, - background = if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight - ) { - GroupMemberInfoView(groupInfo, member, stats, chatModel, closeCurrent) { closeCurrent(); close() } - } + ModalManager.shared.showModalCloseable(true) { closeCurrent -> + GroupMemberInfoView(groupInfo, member, stats, chatModel, closeCurrent) { closeCurrent(); close() } } } }, @@ -144,10 +134,10 @@ fun GroupChatInfoLayout( SectionView(title = String.format(generalGetString(R.string.group_info_section_title_num_members), members.count() + 1)) { if (groupInfo.canAddMembers) { - SectionItemView { + val onAddMembersClick = if (chat.chatInfo.incognito) ::cantInviteIncognitoAlert else addMembers + SectionItemView(onAddMembersClick) { val tint = if (chat.chatInfo.incognito) HighOrLowlight else MaterialTheme.colors.primary - val onClick = if (chat.chatInfo.incognito) ::cantInviteIncognitoAlert else addMembers - AddMembersButton(tint, onClick) + AddMembersButton(tint) } SectionDivider() } @@ -163,25 +153,17 @@ fun GroupChatInfoLayout( SectionView { if (groupInfo.canEdit) { - SectionItemView { - EditGroupProfileButton(editGroupProfile) - } + SectionItemView(editGroupProfile) { EditGroupProfileButton() } SectionDivider() } - SectionItemView { - ClearChatButton(clearChat) - } + ClearChatButton(clearChat) if (groupInfo.canDelete) { SectionDivider() - SectionItemView { - DeleteGroupButton(deleteGroup) - } + SectionItemView(deleteGroup) { DeleteGroupButton() } } if (groupInfo.membership.memberCurrent) { SectionDivider() - SectionItemView { - LeaveGroupButton(leaveGroup) - } + SectionItemView(leaveGroup) { LeaveGroupButton() } } } SectionSpacer() @@ -222,11 +204,9 @@ fun GroupChatInfoHeader(cInfo: ChatInfo) { } @Composable -fun AddMembersButton(tint: Color = MaterialTheme.colors.primary, addMembers: () -> Unit) { +fun AddMembersButton(tint: Color = MaterialTheme.colors.primary) { Row( - Modifier - .fillMaxSize() - .clickable { addMembers() }, + Modifier.fillMaxSize(), verticalAlignment = Alignment.CenterVertically ) { Icon( @@ -290,11 +270,10 @@ fun MemberRow(member: GroupMember, showMemberInfo: ((GroupMember) -> Unit)? = nu } @Composable -fun EditGroupProfileButton(editGroupProfile: () -> Unit) { +fun EditGroupProfileButton() { Row( Modifier - .fillMaxSize() - .clickable { editGroupProfile() }, + .fillMaxSize(), verticalAlignment = Alignment.CenterVertically ) { Icon( @@ -308,11 +287,9 @@ fun EditGroupProfileButton(editGroupProfile: () -> Unit) { } @Composable -fun LeaveGroupButton(leaveGroup: () -> Unit) { +fun LeaveGroupButton() { Row( - Modifier - .fillMaxSize() - .clickable { leaveGroup() }, + Modifier.fillMaxSize(), verticalAlignment = Alignment.CenterVertically ) { Icon( @@ -326,11 +303,9 @@ fun LeaveGroupButton(leaveGroup: () -> Unit) { } @Composable -fun DeleteGroupButton(deleteGroup: () -> Unit) { +fun DeleteGroupButton() { Row( - Modifier - .fillMaxSize() - .clickable { deleteGroup() }, + Modifier.fillMaxSize(), verticalAlignment = Alignment.CenterVertically ) { Icon( diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupMemberInfoView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupMemberInfoView.kt index 53a19528fe..2034bbecc4 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupMemberInfoView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupMemberInfoView.kt @@ -2,7 +2,6 @@ package chat.simplex.app.views.chat.group import InfoRow import SectionDivider -import SectionItemView import SectionSpacer import SectionView import androidx.activity.compose.BackHandler @@ -26,6 +25,7 @@ import chat.simplex.app.ui.theme.* import chat.simplex.app.views.chat.SimplexServers import chat.simplex.app.views.chatlist.openChat import chat.simplex.app.views.helpers.* +import chat.simplex.app.views.usersettings.SettingsActionItem @Composable fun GroupMemberInfoView( @@ -107,9 +107,7 @@ fun GroupMemberInfoLayout( SectionSpacer() SectionView { - SectionItemView { - OpenChatButton(openDirectChat) - } + OpenChatButton(openDirectChat) } SectionSpacer() @@ -147,9 +145,7 @@ fun GroupMemberInfoLayout( if (member.canBeRemoved(groupInfo.membership)) { SectionView { - SectionItemView { - RemoveMemberButton(removeMember) - } + RemoveMemberButton(removeMember) } SectionSpacer() } @@ -190,40 +186,25 @@ fun GroupMemberInfoHeader(member: GroupMember) { } @Composable -fun RemoveMemberButton(removeMember: () -> Unit) { - Row( - Modifier - .fillMaxSize() - .clickable { removeMember() }, - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - Icons.Outlined.Delete, - stringResource(R.string.button_remove_member), - tint = Color.Red - ) - Spacer(Modifier.size(8.dp)) - Text(stringResource(R.string.button_remove_member), color = Color.Red) - } +fun RemoveMemberButton(onClick: () -> Unit) { + SettingsActionItem( + Icons.Outlined.Delete, + stringResource(R.string.button_remove_member), + click = onClick, + textColor = Color.Red, + iconColor = Color.Red, + ) } @Composable fun OpenChatButton(onClick: () -> Unit) { - Row( - Modifier - .fillMaxSize() - .clickable { onClick() }, - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - Icons.Outlined.Message, - stringResource(R.string.button_send_direct_message), - Modifier.padding(top = 5.dp), - tint = MaterialTheme.colors.primary - ) - Spacer(Modifier.size(8.dp)) - Text(stringResource(R.string.button_send_direct_message), color = MaterialTheme.colors.primary) - } + SettingsActionItem( + Icons.Outlined.Message, + stringResource(R.string.button_send_direct_message), + click = onClick, + textColor = MaterialTheme.colors.primary, + iconColor = MaterialTheme.colors.primary, + ) } @Preview diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupProfileView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupProfileView.kt index 52995d30a8..2d96714a3f 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupProfileView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupProfileView.kt @@ -17,14 +17,14 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.* -import chat.simplex.app.ui.theme.HighOrLowlight -import chat.simplex.app.ui.theme.SimpleXTheme +import chat.simplex.app.ui.theme.* import chat.simplex.app.views.ProfileNameField import chat.simplex.app.views.helpers.* import chat.simplex.app.views.isValidDisplayName import chat.simplex.app.views.usersettings.* import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsWithImePadding +import kotlinx.coroutines.delay import kotlinx.coroutines.launch @Composable @@ -78,7 +78,7 @@ fun GroupProfileLayout( Column( Modifier .verticalScroll(scrollState) - .padding(bottom = 16.dp), + .padding(horizontal = DEFAULT_PADDING), horizontalAlignment = Alignment.Start ) { Text( @@ -147,6 +147,7 @@ fun GroupProfileLayout( } LaunchedEffect(Unit) { + delay(300) focusRequester.requestFocus() } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/database/ChatArchiveView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/database/ChatArchiveView.kt index 9bc80a4a9a..759177605c 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/database/ChatArchiveView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/database/ChatArchiveView.kt @@ -59,25 +59,22 @@ fun ChatArchiveLayout( Modifier.fillMaxWidth(), horizontalAlignment = Alignment.Start, ) { - Text( - title, - Modifier.padding(start = 16.dp, bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) - + AppBarTitle(title) SectionView(stringResource(R.string.chat_archive_section)) { SettingsActionItem( Icons.Outlined.IosShare, stringResource(R.string.save_archive), saveArchive, - textColor = MaterialTheme.colors.primary + textColor = MaterialTheme.colors.primary, + iconColor = MaterialTheme.colors.primary, ) SectionDivider() SettingsActionItem( Icons.Outlined.Delete, stringResource(R.string.delete_archive), deleteArchiveAlert, - textColor = Color.Red + textColor = Color.Red, + iconColor = Color.Red, ) } val archiveTs = SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.US).format(Date.from(archiveTime.toJavaInstant())) @@ -137,7 +134,7 @@ private fun deleteArchiveAlert(m: ChatModel, archivePath: String) { fun PreviewChatArchiveLayout() { SimpleXTheme { ChatArchiveLayout( - title = "New database archive", + "New database archive", archiveTime = Clock.System.now(), saveArchive = {}, deleteArchiveAlert = {} diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseEncryptionView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseEncryptionView.kt index e2fceae5bd..fa511e0b81 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseEncryptionView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseEncryptionView.kt @@ -138,12 +138,7 @@ fun DatabaseEncryptionLayout( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.Start, ) { - Text( - stringResource(R.string.database_passphrase), - Modifier.padding(start = 16.dp, bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) - + AppBarTitle(stringResource(R.string.database_passphrase)) SectionView(null) { SavePassphraseSetting(useKeychain.value, initialRandomDBPassphrase.value, storedKey.value, progressIndicator.value) { checked -> if (checked) { @@ -169,7 +164,7 @@ fun DatabaseEncryptionLayout( DatabaseKeyField( currentKey, generalGetString(R.string.current_passphrase), - modifier = Modifier.padding(start = 8.dp), + modifier = Modifier.padding(horizontal = DEFAULT_PADDING), isValid = ::validKey, keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }), ) @@ -178,7 +173,7 @@ fun DatabaseEncryptionLayout( DatabaseKeyField( newKey, generalGetString(R.string.new_passphrase), - modifier = Modifier.padding(start = 8.dp), + modifier = Modifier.padding(horizontal = DEFAULT_PADDING), showStrength = true, isValid = ::validKey, keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }), @@ -209,7 +204,7 @@ fun DatabaseEncryptionLayout( DatabaseKeyField( confirmNewKey, generalGetString(R.string.confirm_new_passphrase), - modifier = Modifier.padding(start = 8.dp), + modifier = Modifier.padding(horizontal = DEFAULT_PADDING), isValid = { confirmNewKey.value == "" || newKey.value == confirmNewKey.value }, keyboardActions = KeyboardActions(onDone = { if (!disabled) onClickUpdate() @@ -217,7 +212,7 @@ fun DatabaseEncryptionLayout( }), ) - SectionItemViewSpaceBetween(onClickUpdate, padding = PaddingValues(start = 8.dp, end = 12.dp), disabled = disabled) { + SectionItemViewSpaceBetween(onClickUpdate, disabled = disabled) { Text(generalGetString(R.string.update_database_passphrase), color = if (disabled) HighOrLowlight else MaterialTheme.colors.primary) } } @@ -292,7 +287,7 @@ fun SavePassphraseSetting( progressIndicator: Boolean, onCheckedChange: (Boolean) -> Unit, ) { - SectionItemView() { + SectionItemView { Row(verticalAlignment = Alignment.CenterVertically) { Icon( if (storedKey) Icons.Filled.VpnKey else Icons.Filled.VpnKeyOff, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseErrorView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseErrorView.kt index 9abd0c6984..1dc25440ac 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseErrorView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseErrorView.kt @@ -60,7 +60,7 @@ fun DatabaseErrorView( } Column( - Modifier.fillMaxWidth().fillMaxHeight().verticalScroll(rememberScrollState()), + Modifier.fillMaxSize().verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.Center, ) { @@ -69,61 +69,57 @@ fun DatabaseErrorView( Modifier.padding(start = 16.dp, top = 16.dp, bottom = 24.dp), style = MaterialTheme.typography.h1 ) - SectionView(null) { - Column( - Modifier.padding(horizontal = 8.dp, vertical = 8.dp) - ) { - val buttonEnabled = validKey(dbKey.value) && !progressIndicator.value - when (val status = chatDbStatus.value) { - is DBMigrationResult.ErrorNotADatabase -> { - if (useKeychain && !storedDBKey.isNullOrEmpty()) { - Text(generalGetString(R.string.passphrase_is_different)) - DatabaseKeyField(dbKey, buttonEnabled) { - saveAndRunChatOnClick() - } + SectionView(null, padding = PaddingValues(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF)) { + val buttonEnabled = validKey(dbKey.value) && !progressIndicator.value + when (val status = chatDbStatus.value) { + is DBMigrationResult.ErrorNotADatabase -> { + if (useKeychain && !storedDBKey.isNullOrEmpty()) { + Text(generalGetString(R.string.passphrase_is_different)) + DatabaseKeyField(dbKey, buttonEnabled) { + saveAndRunChatOnClick() + } + SaveAndOpenButton(buttonEnabled, saveAndRunChatOnClick) + SectionSpacer() + Text(String.format(generalGetString(R.string.file_with_path), status.dbFile)) + } else { + Text(generalGetString(R.string.database_passphrase_is_required)) + DatabaseKeyField(dbKey, buttonEnabled) { + if (useKeychain) saveAndRunChatOnClick() else runChat(dbKey.value, chatDbStatus, progressIndicator, appPreferences) + } + if (useKeychain) { SaveAndOpenButton(buttonEnabled, saveAndRunChatOnClick) - SectionSpacer() - Text(String.format(generalGetString(R.string.file_with_path), status.dbFile)) } else { - Text(generalGetString(R.string.database_passphrase_is_required)) - DatabaseKeyField(dbKey, buttonEnabled) { - if (useKeychain) saveAndRunChatOnClick() else runChat(dbKey.value, chatDbStatus, progressIndicator, appPreferences) - } - if (useKeychain) { - SaveAndOpenButton(buttonEnabled, saveAndRunChatOnClick) - } else { - OpenChatButton(buttonEnabled) { runChat(dbKey.value, chatDbStatus, progressIndicator, appPreferences) } - } + OpenChatButton(buttonEnabled) { runChat(dbKey.value, chatDbStatus, progressIndicator, appPreferences) } } } - is DBMigrationResult.Error -> { - Text(String.format(generalGetString(R.string.file_with_path), status.dbFile)) - Text(String.format(generalGetString(R.string.error_with_info), status.migrationError)) - } - is DBMigrationResult.ErrorKeychain -> { - Text(generalGetString(R.string.cannot_access_keychain)) - } - is DBMigrationResult.Unknown -> { - Text(String.format(generalGetString(R.string.unknown_database_error_with_info), status.json)) - } - is DBMigrationResult.OK -> { - } - null -> { - } } - if (restoreDbFromBackup.value) { - SectionSpacer() - Text(generalGetString(R.string.database_backup_can_be_restored)) - Spacer(Modifier.size(16.dp)) - RestoreDbButton { - AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.restore_database_alert_title), - text = generalGetString(R.string.restore_database_alert_desc), - confirmText = generalGetString(R.string.restore_database_alert_confirm), - onConfirm = { restoreDb(restoreDbFromBackup, appPreferences, context) }, - destructive = true, - ) - } + is DBMigrationResult.Error -> { + Text(String.format(generalGetString(R.string.file_with_path), status.dbFile)) + Text(String.format(generalGetString(R.string.error_with_info), status.migrationError)) + } + is DBMigrationResult.ErrorKeychain -> { + Text(generalGetString(R.string.cannot_access_keychain)) + } + is DBMigrationResult.Unknown -> { + Text(String.format(generalGetString(R.string.unknown_database_error_with_info), status.json)) + } + is DBMigrationResult.OK -> { + } + null -> { + } + } + if (restoreDbFromBackup.value) { + SectionSpacer() + Text(generalGetString(R.string.database_backup_can_be_restored)) + Spacer(Modifier.size(16.dp)) + RestoreDbButton { + AlertManager.shared.showAlertDialog( + title = generalGetString(R.string.restore_database_alert_title), + text = generalGetString(R.string.restore_database_alert_desc), + confirmText = generalGetString(R.string.restore_database_alert_confirm), + onConfirm = { restoreDb(restoreDbFromBackup, appPreferences, context) }, + destructive = true, + ) } } } @@ -168,16 +164,16 @@ private fun runChat( } } is DBMigrationResult.ErrorNotADatabase -> { - AlertManager.shared.showAlertMsg( generalGetString(R.string.wrong_passphrase_title), generalGetString(R.string.enter_correct_passphrase)) + AlertManager.shared.showAlertMsg(generalGetString(R.string.wrong_passphrase_title), generalGetString(R.string.enter_correct_passphrase)) } is DBMigrationResult.Error -> { - AlertManager.shared.showAlertMsg( generalGetString(R.string.database_error), status.migrationError) + AlertManager.shared.showAlertMsg(generalGetString(R.string.database_error), status.migrationError) } is DBMigrationResult.ErrorKeychain -> { - AlertManager.shared.showAlertMsg( generalGetString(R.string.keychain_error)) + AlertManager.shared.showAlertMsg(generalGetString(R.string.keychain_error)) } is DBMigrationResult.Unknown -> { - AlertManager.shared.showAlertMsg( generalGetString(R.string.unknown_error), status.json) + AlertManager.shared.showAlertMsg(generalGetString(R.string.unknown_error), status.json) } null -> {} } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseView.kt index 5e9a661188..c908760cbd 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseView.kt @@ -133,12 +133,7 @@ fun DatabaseLayout( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.Start, ) { - Text( - stringResource(R.string.your_chat_database), - Modifier.padding(start = 16.dp, bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) - + AppBarTitle(stringResource(R.string.your_chat_database)) SectionView(stringResource(R.string.run_chat_section)) { RunChatSetting(runChat, stopped, chatDbDeleted, startChat, stopChatAlert) } @@ -149,7 +144,7 @@ fun DatabaseLayout( SettingsActionItem( if (unencrypted) Icons.Outlined.LockOpen else if (useKeyChain) Icons.Filled.VpnKey else Icons.Outlined.Lock, stringResource(R.string.database_passphrase), - click = showSettingsModal { DatabaseEncryptionView(it) }, + click = showSettingsModal() { DatabaseEncryptionView(it) }, iconColor = if (unencrypted) WarningOrange else HighOrLowlight, disabled = operationsDisabled ) @@ -165,6 +160,7 @@ fun DatabaseLayout( } }, textColor = MaterialTheme.colors.primary, + iconColor = MaterialTheme.colors.primary, disabled = operationsDisabled ) SectionDivider() @@ -173,6 +169,7 @@ fun DatabaseLayout( stringResource(R.string.import_database), { importArchiveLauncher.launch("application/zip") }, textColor = Color.Red, + iconColor = Color.Red, disabled = operationsDisabled ) SectionDivider() @@ -194,6 +191,7 @@ fun DatabaseLayout( stringResource(R.string.delete_database), deleteChatAlert, textColor = Color.Red, + iconColor = Color.Red, disabled = operationsDisabled ) } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/CloseSheetBar.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/CloseSheetBar.kt index c0de98ad65..ad3d598910 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/CloseSheetBar.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/CloseSheetBar.kt @@ -3,37 +3,46 @@ package chat.simplex.app.views.helpers import android.content.res.Configuration import androidx.compose.foundation.layout.* import androidx.compose.material.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.Close import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import chat.simplex.app.R -import chat.simplex.app.ui.theme.SimpleXTheme +import chat.simplex.app.ui.theme.* @Composable fun CloseSheetBar(close: () -> Unit) { - Row ( + Column( Modifier .fillMaxWidth() - .height(60.dp), - horizontalArrangement = Arrangement.End, - verticalAlignment = Alignment.CenterVertically + .heightIn(min = AppBarHeight) + .padding(horizontal = AppBarHorizontalPadding), ) { - IconButton(onClick = close) { - Icon( - Icons.Outlined.Close, - stringResource(R.string.icon_descr_close_button), - tint = MaterialTheme.colors.primary, - modifier = Modifier.padding(10.dp) - ) - } + Row( + Modifier + .width(TitleInsetWithIcon - AppBarHorizontalPadding) + .padding(top = 4.dp), // Like in DefaultAppBar + content = { NavigationButtonBack(close) } + ) } } +@Composable +fun AppBarTitle(title: String, withPadding: Boolean = true) { + val padding = if (withPadding) + PaddingValues(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING ) + else + PaddingValues(bottom = DEFAULT_PADDING) + Text( + title, + Modifier + .fillMaxWidth() + .padding(padding), + overflow = TextOverflow.Ellipsis, + style = MaterialTheme.typography.h1 + ) +} + @Preview(showBackground = true) @Preview( uiMode = Configuration.UI_MODE_NIGHT_YES, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/DefaultTopAppBar.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/DefaultTopAppBar.kt index a4962dc7a8..601e258fce 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/DefaultTopAppBar.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/DefaultTopAppBar.kt @@ -5,8 +5,7 @@ import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.ArrowBackIos -import androidx.compose.material.icons.outlined.Menu +import androidx.compose.material.icons.outlined.* import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -18,7 +17,7 @@ import chat.simplex.app.ui.theme.* @Composable fun DefaultTopAppBar( navigationButton: @Composable RowScope.() -> Unit, - title: @Composable () -> Unit, + title: (@Composable () -> Unit)?, onTitleClick: (() -> Unit)? = null, showSearch: Boolean, onSearchValueChanged: (String) -> Unit, @@ -33,7 +32,7 @@ fun DefaultTopAppBar( modifier = modifier, title = { if (!showSearch) { - title() + title?.invoke() } else { SearchTextField(Modifier.fillMaxWidth(), stringResource(android.R.string.search_go), onSearchValueChanged) } @@ -41,7 +40,7 @@ fun DefaultTopAppBar( backgroundColor = if (isInDarkTheme()) ToolbarDark else ToolbarLight, navigationIcon = navigationButton, buttons = if (!showSearch) buttons else emptyList(), - centered = !showSearch + centered = !showSearch, ) } @@ -91,7 +90,6 @@ private fun TopAppBar( content = navigationIcon ) } - Row( Modifier .fillMaxHeight() @@ -118,6 +116,6 @@ private fun TopAppBar( } val AppBarHeight = 56.dp -private val AppBarHorizontalPadding = 4.dp -private val TitleInsetWithoutIcon = 16.dp - AppBarHorizontalPadding -private val TitleInsetWithIcon = 72.dp +val AppBarHorizontalPadding = 4.dp +private val TitleInsetWithoutIcon = DEFAULT_PADDING - AppBarHorizontalPadding +val TitleInsetWithIcon = 72.dp diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/ModalView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/ModalView.kt index f73cab9b22..36f72c269d 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/ModalView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/ModalView.kt @@ -2,22 +2,24 @@ package chat.simplex.app.views.helpers import android.util.Log import androidx.activity.compose.BackHandler +import androidx.compose.animation.* +import androidx.compose.animation.core.* import androidx.compose.foundation.background import androidx.compose.foundation.layout.* -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf +import androidx.compose.material.* +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp import chat.simplex.app.TAG +import chat.simplex.app.ui.theme.SettingsBackgroundLight +import chat.simplex.app.ui.theme.isInDarkTheme +import kotlinx.coroutines.delay @Composable fun ModalView( close: () -> Unit, background: Color = MaterialTheme.colors.background, - modifier: Modifier = Modifier.padding(horizontal = 16.dp), + modifier: Modifier = Modifier, content: @Composable () -> Unit, ) { BackHandler(onBack = close) @@ -32,37 +34,82 @@ fun ModalView( class ModalManager { private val modalViews = arrayListOf<(@Composable (close: () -> Unit) -> Unit)?>() private val modalCount = mutableStateOf(0) + private val toRemove = mutableSetOf() - fun showModal(content: @Composable () -> Unit) { - showCustomModal { close -> ModalView(close, content = content) } + fun showModal(settings: Boolean = false, content: @Composable () -> Unit) { + showCustomModal { close -> + ModalView(close, if (!settings || isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight, content = content) + } } - fun showModalCloseable(content: @Composable (close: () -> Unit) -> Unit) { - showCustomModal { close -> ModalView(close, content = { content(close) }) } + fun showModalCloseable(settings: Boolean = false, content: @Composable (close: () -> Unit) -> Unit) { + showCustomModal { close -> + ModalView(close, if (!settings || isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight, content = { content(close) }) + } } fun showCustomModal(modal: @Composable (close: () -> Unit) -> Unit) { Log.d(TAG, "ModalManager.showModal") modalViews.add(modal) - modalCount.value = modalViews.count() + modalCount.value = modalViews.size - toRemove.size } fun closeModal() { if (modalViews.isNotEmpty()) { - modalViews.removeAt(modalViews.count() - 1) + //modalViews.removeAt(modalViews.lastIndex) + toRemove.add(modalViews.lastIndex - toRemove.size) } - modalCount.value = modalViews.count() + modalCount.value = modalViews.size - toRemove.size } fun closeModals() { while (modalViews.isNotEmpty()) closeModal() } + @OptIn(ExperimentalAnimationApi::class) @Composable fun showInView() { - if (modalCount.value > 0) modalViews.lastOrNull()?.invoke(::closeModal) + AnimatedContent(targetState = modalCount.value, + transitionSpec = { + if (targetState > initialState) { + fromEndToStartTransition() + } else { + fromStartToEndTransition() + }.using(SizeTransform(clip = false)) + } + ) { + modalViews.getOrNull(it - 1)?.invoke(::closeModal) + // This is needed because if we delete from modalViews immediately on request, animation will be bad + if (toRemove.isNotEmpty() && it == modalCount.value && transition.currentState == EnterExitState.Visible && !transition.isRunning) { + toRemove.removeIf { elem -> modalViews.removeAt(elem); true } + } + } } + @OptIn(ExperimentalAnimationApi::class) + private fun fromStartToEndTransition() = + slideInHorizontally( + initialOffsetX = { fullWidth -> -fullWidth }, + animationSpec = animationSpec() + ) with slideOutHorizontally( + targetOffsetX = { fullWidth -> fullWidth }, + animationSpec = animationSpec() + ) + + @OptIn(ExperimentalAnimationApi::class) + private fun fromEndToStartTransition() = + slideInHorizontally( + initialOffsetX = { fullWidth -> fullWidth }, + animationSpec = animationSpec() + ) with slideOutHorizontally( + targetOffsetX = { fullWidth -> -fullWidth }, + animationSpec = animationSpec() + ) + +private fun animationSpec() = tween(durationMillis = 250, easing = FastOutSlowInEasing) +// private fun animationSpecFromStart() = tween(durationMillis = 150, easing = FastOutLinearInEasing) +// private fun animationSpecFromEnd() = tween(durationMillis = 100, easing = FastOutSlowInEasing) + companion object { val shared = ModalManager() } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Section.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Section.kt index 3d416a70e7..18941e2c76 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Section.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Section.kt @@ -17,16 +17,16 @@ import chat.simplex.app.views.helpers.ValueTitleDesc import chat.simplex.app.views.helpers.ValueTitle @Composable -fun SectionView(title: String? = null, content: (@Composable () -> Unit)) { +fun SectionView(title: String? = null, padding: PaddingValues = PaddingValues(), content: (@Composable ColumnScope.() -> Unit)) { Column { if (title != null) { Text( title, color = HighOrLowlight, style = MaterialTheme.typography.body2, - modifier = Modifier.padding(start = 16.dp, bottom = 5.dp), fontSize = 12.sp + modifier = Modifier.padding(start = DEFAULT_PADDING, bottom = 5.dp), fontSize = 12.sp ) } Surface(color = if (isInDarkTheme()) GroupDark else MaterialTheme.colors.background) { - Column(Modifier.padding(horizontal = 6.dp).fillMaxWidth()) { content() } + Column(Modifier.padding(padding).fillMaxWidth()) { content() } } } } @@ -34,20 +34,18 @@ fun SectionView(title: String? = null, content: (@Composable () -> Unit)) { @Composable fun SectionViewSelectable( title: String?, - currentValue: MutableState, + currentValue: State, values: List>, onSelected: (T) -> Unit, ) { SectionView(title) { - LazyColumn( - Modifier.padding(horizontal = 8.dp) - ) { + LazyColumn { items(values.size) { index -> val item = values[index] - SectionItemViewSpaceBetween({ onSelected(item.value) }, padding = PaddingValues()) { + SectionItemViewSpaceBetween({ onSelected(item.value) }) { Text(item.title) if (currentValue.value == item.value) { - Icon(Icons.Outlined.Check, item.title, tint = HighOrLowlight) + Icon(Icons.Outlined.Check, item.title, tint = MaterialTheme.colors.primary) } } Spacer(Modifier.padding(horizontal = 4.dp)) @@ -60,11 +58,10 @@ fun SectionViewSelectable( @Composable fun SectionItemView(click: (() -> Unit)? = null, minHeight: Dp = 46.dp, disabled: Boolean = false, content: (@Composable RowScope.() -> Unit)) { val modifier = Modifier - .padding(horizontal = 8.dp) .fillMaxWidth() .sizeIn(minHeight = minHeight) Row( - if (click == null || disabled) modifier else modifier.clickable(onClick = click), + if (click == null || disabled) modifier.padding(horizontal = DEFAULT_PADDING) else modifier.clickable(onClick = click).padding(horizontal = DEFAULT_PADDING), verticalAlignment = Alignment.CenterVertically ) { content() @@ -75,16 +72,15 @@ fun SectionItemView(click: (() -> Unit)? = null, minHeight: Dp = 46.dp, disabled fun SectionItemViewSpaceBetween( click: (() -> Unit)? = null, minHeight: Dp = 46.dp, - padding: PaddingValues = PaddingValues(horizontal = 8.dp), + padding: PaddingValues = PaddingValues(horizontal = DEFAULT_PADDING), disabled: Boolean = false, - content: (@Composable () -> Unit) + content: (@Composable RowScope.() -> Unit) ) { val modifier = Modifier - .padding(padding) .fillMaxWidth() .sizeIn(minHeight = minHeight) Row( - if (click == null || disabled) modifier else modifier.clickable(onClick = click), + if (click == null || disabled) modifier.padding(padding) else modifier.clickable(onClick = click).padding(padding), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { @@ -135,7 +131,7 @@ fun SectionItemWithValue( fun SectionTextFooter(text: String) { Text( text, - Modifier.padding(horizontal = 16.dp).padding(top = 8.dp).fillMaxWidth(0.9F), + Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, top = DEFAULT_PADDING_HALF).fillMaxWidth(0.9F), color = HighOrLowlight, lineHeight = 18.sp, fontSize = 14.sp @@ -143,7 +139,7 @@ fun SectionTextFooter(text: String) { } @Composable -fun SectionCustomFooter(padding: PaddingValues = PaddingValues(start = 16.dp, end = 16.dp, top = 5.dp), content: (@Composable () -> Unit)) { +fun SectionCustomFooter(padding: PaddingValues = PaddingValues(start = DEFAULT_PADDING, end = DEFAULT_PADDING, top = 5.dp), content: (@Composable () -> Unit)) { Row( Modifier.padding(padding) ) { @@ -163,37 +159,25 @@ fun SectionSpacer() { @Composable fun InfoRow(title: String, value: String) { - SectionItemView { - Row( - Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Text(title) - Text(value, color = HighOrLowlight) - } + SectionItemViewSpaceBetween { + Text(title) + Text(value, color = HighOrLowlight) } } @Composable fun InfoRowEllipsis(title: String, value: String, onClick: () -> Unit) { - SectionItemView { - Row( - Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - val configuration = LocalConfiguration.current - Text(title) - Text(value, - Modifier - .padding(start = 10.dp) - .widthIn(max = (configuration.screenWidthDp / 2).dp) - .clickable(onClick = onClick), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - color = HighOrLowlight - ) - } + SectionItemViewSpaceBetween(onClick) { + val configuration = LocalConfiguration.current + Text(title) + Text( + value, + Modifier + .padding(start = 10.dp) + .widthIn(max = (configuration.screenWidthDp / 2).dp), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + color = HighOrLowlight + ) } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddContactView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddContactView.kt index 4acb441a79..a64a0a3356 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddContactView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddContactView.kt @@ -38,14 +38,12 @@ fun AddContactLayout(chatModelIncognito: Boolean, connReq: String, share: () -> BoxWithConstraints { val screenHeight = maxHeight Column( - Modifier.verticalScroll(rememberScrollState()).padding(bottom = 16.dp), + Modifier + .verticalScroll(rememberScrollState()) + .padding(bottom = 16.dp), verticalArrangement = Arrangement.SpaceBetween, ) { - Text( - stringResource(R.string.add_contact), - Modifier.padding(bottom = 16.dp), - style = MaterialTheme.typography.h1, - ) + AppBarTitle(stringResource(R.string.add_contact), false) Text( stringResource(R.string.show_QR_code_for_your_contact_to_scan_from_the_app__multiline), ) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddGroupView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddGroupView.kt index f18ccecbcd..73f52cc3d6 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddGroupView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddGroupView.kt @@ -13,7 +13,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -25,11 +24,11 @@ import chat.simplex.app.views.chat.group.AddGroupMembersView import chat.simplex.app.views.chatlist.setGroupMembers import chat.simplex.app.views.helpers.* import chat.simplex.app.views.isValidDisplayName -import chat.simplex.app.views.onboarding.ReadableText import chat.simplex.app.views.usersettings.DeleteImageButton import chat.simplex.app.views.usersettings.EditImageButton import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsWithImePadding +import kotlinx.coroutines.delay import kotlinx.coroutines.launch @Composable @@ -45,13 +44,8 @@ fun AddGroupView(chatModel: ChatModel, close: () -> Unit) { chatModel.chatId.value = groupInfo.id setGroupMembers(groupInfo, chatModel) close.invoke() - ModalManager.shared.showCustomModal { close -> - ModalView( - close = close, modifier = Modifier, - background = if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight - ) { - AddGroupMembersView(groupInfo, chatModel, close) - } + ModalManager.shared.showModalCloseable(true) { close -> + AddGroupMembersView(groupInfo, chatModel, close) } } } @@ -85,71 +79,67 @@ fun AddGroupLayout(chatModelIncognito: Boolean, createGroup: (GroupProfile) -> U sheetState = bottomSheetModalState, sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp) ) { - ModalView(close) { - Surface(Modifier.background(MaterialTheme.colors.onBackground).fillMaxSize()) { - Column( + ModalView(close = close) { + Column( + Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(horizontal = DEFAULT_PADDING) + ) { + AppBarTitle(stringResource(R.string.create_secret_group_title), false) + Text(stringResource(R.string.group_is_decentralized)) + InfoAboutIncognito( + chatModelIncognito, + false, + generalGetString(R.string.group_unsupported_incognito_main_profile_sent), + generalGetString(R.string.group_main_profile_sent) + ) + Box( Modifier - .verticalScroll(rememberScrollState()) - .padding(bottom = 16.dp), + .fillMaxWidth() + .padding(bottom = 24.dp), + contentAlignment = Alignment.Center ) { - Text( - stringResource(R.string.create_secret_group_title), - style = MaterialTheme.typography.h1.copy(fontWeight = FontWeight.Normal), - modifier = Modifier.padding(vertical = 5.dp) - ) - Text(stringResource(R.string.group_is_decentralized)) - InfoAboutIncognito( - chatModelIncognito, - false, - generalGetString(R.string.group_unsupported_incognito_main_profile_sent), - generalGetString(R.string.group_main_profile_sent) - ) - Box( - Modifier - .fillMaxWidth() - .padding(bottom = 24.dp), - contentAlignment = Alignment.Center - ) { - Box(contentAlignment = Alignment.TopEnd) { - Box(contentAlignment = Alignment.Center) { - ProfileImage(size = 192.dp, image = profileImage.value) - EditImageButton { scope.launch { bottomSheetModalState.show() } } - } - if (profileImage.value != null) { - DeleteImageButton { profileImage.value = null } - } + Box(contentAlignment = Alignment.TopEnd) { + Box(contentAlignment = Alignment.Center) { + ProfileImage(size = 192.dp, image = profileImage.value) + EditImageButton { scope.launch { bottomSheetModalState.show() } } + } + if (profileImage.value != null) { + DeleteImageButton { profileImage.value = null } } } - Text( - stringResource(R.string.group_display_name_field), - Modifier.padding(bottom = 3.dp) - ) - ProfileNameField(displayName, focusRequester) - val errorText = if (!isValidDisplayName(displayName.value)) stringResource(R.string.display_name_cannot_contain_whitespace) else "" - Text( - errorText, - fontSize = 15.sp, - color = MaterialTheme.colors.error - ) - Spacer(Modifier.height(3.dp)) - Text( - stringResource(R.string.group_full_name_field), - Modifier.padding(bottom = 5.dp) - ) - ProfileNameField(fullName) + } + Text( + stringResource(R.string.group_display_name_field), + Modifier.padding(bottom = 3.dp) + ) + ProfileNameField(displayName, focusRequester) + val errorText = if (!isValidDisplayName(displayName.value)) stringResource(R.string.display_name_cannot_contain_whitespace) else "" + Text( + errorText, + fontSize = 15.sp, + color = MaterialTheme.colors.error + ) + Spacer(Modifier.height(3.dp)) + Text( + stringResource(R.string.group_full_name_field), + Modifier.padding(bottom = 5.dp) + ) + ProfileNameField(fullName) - Spacer(Modifier.height(8.dp)) - val enabled = displayName.value.isNotEmpty() && isValidDisplayName(displayName.value) - if (enabled) { - CreateGroupButton(MaterialTheme.colors.primary, Modifier - .clickable { createGroup(GroupProfile(displayName.value, fullName.value, profileImage.value)) } - .padding(8.dp)) - } else { - CreateGroupButton(HighOrLowlight, Modifier.padding(8.dp)) - } - LaunchedEffect(Unit) { - focusRequester.requestFocus() - } + Spacer(Modifier.height(8.dp)) + val enabled = displayName.value.isNotEmpty() && isValidDisplayName(displayName.value) + if (enabled) { + CreateGroupButton(MaterialTheme.colors.primary, Modifier + .clickable { createGroup(GroupProfile(displayName.value, fullName.value, profileImage.value)) } + .padding(8.dp)) + } else { + CreateGroupButton(HighOrLowlight, Modifier.padding(8.dp)) + } + LaunchedEffect(Unit) { + delay(300) + focusRequester.requestFocus() } } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ConnectViaLinkView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ConnectViaLinkView.kt index 590340ef3f..0919d234f4 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ConnectViaLinkView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ConnectViaLinkView.kt @@ -11,8 +11,6 @@ import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.ChatModel import chat.simplex.app.ui.theme.HighOrLowlight -import chat.simplex.app.views.helpers.withApi -import chat.simplex.app.views.usersettings.UserAddressView enum class ConnectViaLinkTab { SCAN, PASTE diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/CreateLinkView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/CreateLinkView.kt index 0908aca35b..c0042faca8 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/CreateLinkView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/CreateLinkView.kt @@ -10,6 +10,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.ChatModel +import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.ui.theme.HighOrLowlight import chat.simplex.app.views.helpers.withApi import chat.simplex.app.views.usersettings.UserAddressView @@ -37,7 +38,9 @@ fun CreateLinkView(m: ChatModel, initialSelection: CreateLinkTab) { } } Column( - Modifier.fillMaxHeight(), + Modifier + .fillMaxHeight() + .padding(horizontal = DEFAULT_PADDING), verticalArrangement = Arrangement.SpaceBetween ) { Column(Modifier.weight(1f)) { diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/NewChatSheet.kt b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/NewChatSheet.kt index 813b2c66a0..6b386fc706 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/NewChatSheet.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/NewChatSheet.kt @@ -22,6 +22,7 @@ import chat.simplex.app.ui.theme.HighOrLowlight import chat.simplex.app.ui.theme.SimpleXTheme import chat.simplex.app.views.chatlist.ScaffoldController import chat.simplex.app.views.helpers.ModalManager +import chat.simplex.app.views.helpers.generalGetString @Composable fun NewChatSheet(chatModel: ChatModel, newChatCtrl: ScaffoldController) { diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/PasteToConnect.kt b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/PasteToConnect.kt index 7a599fd37e..9554d8a991 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/PasteToConnect.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/PasteToConnect.kt @@ -6,7 +6,6 @@ import android.net.Uri import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.* @@ -19,8 +18,7 @@ import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat.getSystemService import chat.simplex.app.R import chat.simplex.app.model.ChatModel -import chat.simplex.app.ui.theme.SimpleButton -import chat.simplex.app.ui.theme.SimpleXTheme +import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* @Composable @@ -60,14 +58,10 @@ fun PasteToConnectLayout( connectViaLink: (String) -> Unit, ) { Column( - Modifier.verticalScroll(rememberScrollState()).padding(bottom = 16.dp), + Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING), verticalArrangement = Arrangement.SpaceBetween, ) { - Text( - stringResource(R.string.connect_via_link), - Modifier.padding(bottom = 16.dp), - style = MaterialTheme.typography.h1, - ) + AppBarTitle(stringResource(R.string.connect_via_link), false) Text(stringResource(R.string.paste_connection_link_below_to_connect)) InfoAboutIncognito( diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ScanToConnectView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ScanToConnectView.kt index 5416006a88..a022ca4c94 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ScanToConnectView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ScanToConnectView.kt @@ -10,11 +10,13 @@ import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.ChatModel +import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.ui.theme.SimpleXTheme import chat.simplex.app.views.helpers.* import com.google.accompanist.permissions.rememberPermissionState @@ -75,14 +77,10 @@ suspend fun connectViaUri(chatModel: ChatModel, action: String, uri: Uri): Boole @Composable fun ConnectContactLayout(chatModelIncognito: Boolean, qrCodeScanner: @Composable () -> Unit) { Column( - Modifier.verticalScroll(rememberScrollState()).padding(bottom = 16.dp), + Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING), verticalArrangement = Arrangement.spacedBy(12.dp) ) { - Text( - generalGetString(R.string.scan_QR_code), - Modifier.padding(bottom = 16.dp), - style = MaterialTheme.typography.h1, - ) + AppBarTitle(stringResource(R.string.scan_QR_code), false) InfoAboutIncognito( chatModelIncognito, true, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/HowItWorks.kt b/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/HowItWorks.kt index 07ee6d892b..a00a7ae65c 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/HowItWorks.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/HowItWorks.kt @@ -4,7 +4,6 @@ import android.content.res.Configuration import androidx.annotation.StringRes import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* -import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -17,14 +16,18 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.User +import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.ui.theme.SimpleXTheme -import chat.simplex.app.views.helpers.ModalManager -import chat.simplex.app.views.helpers.annotatedStringResource +import chat.simplex.app.views.helpers.* @Composable fun HowItWorks(user: User?, onboardingStage: MutableState? = null) { - Column(Modifier.fillMaxHeight(), horizontalAlignment = Alignment.Start) { - Text(stringResource(R.string.how_simplex_works), style = MaterialTheme.typography.h1, modifier = Modifier.padding(bottom = 8.dp)) + Column(Modifier + .fillMaxWidth() + .padding(horizontal = DEFAULT_PADDING), + horizontalAlignment = Alignment.Start + ) { + AppBarTitle(stringResource(R.string.how_simplex_works), false) ReadableText(R.string.many_people_asked_how_can_it_deliver) ReadableText(R.string.to_protect_privacy_simplex_has_ids_for_queues) ReadableText(R.string.you_control_servers_to_receive_your_contacts_to_send) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/SimpleXInfo.kt b/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/SimpleXInfo.kt index 72da39b334..89b1114ce1 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/SimpleXInfo.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/SimpleXInfo.kt @@ -2,7 +2,7 @@ package chat.simplex.app.views.onboarding import android.content.res.Configuration import androidx.annotation.StringRes -import androidx.compose.foundation.Image +import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.material.icons.Icons @@ -16,6 +16,7 @@ import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -24,6 +25,7 @@ import chat.simplex.app.model.ChatModel import chat.simplex.app.model.User import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.ModalManager +import chat.simplex.app.views.helpers.generalGetString @Composable fun SimpleXInfo(chatModel: ChatModel, onboarding: Boolean = true) { @@ -40,34 +42,36 @@ fun SimpleXInfoLayout( onboardingStage: MutableState?, showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), ) { - Column(Modifier.fillMaxHeight(), horizontalAlignment = Alignment.Start) { - SimpleXLogo() + Column( + Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(horizontal = DEFAULT_PADDING), + ) { + Box(Modifier.fillMaxWidth().padding(top = 24.dp, bottom = 8.dp), contentAlignment = Alignment.Center) { + SimpleXLogo() + } - Text(stringResource(R.string.next_generation_of_private_messaging), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = 16.dp)) + Text(stringResource(R.string.next_generation_of_private_messaging), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = 24.dp), textAlign = TextAlign.Center) InfoRow(painterResource(R.drawable.privacy), R.string.privacy_redefined, R.string.first_platform_without_user_ids) InfoRow(painterResource(R.drawable.shield), R.string.immune_to_spam_and_abuse, R.string.people_can_connect_only_via_links_you_share) InfoRow(painterResource(R.drawable.decentralized), R.string.decentralized, R.string.opensource_protocol_and_code_anybody_can_run_servers) - Spacer( - Modifier - .fillMaxHeight() - .weight(1f)) + Spacer(Modifier.fillMaxHeight().weight(1f)) if (onboardingStage != null) { Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { OnboardingActionButton(user, onboardingStage) } - Spacer( - Modifier - .fillMaxHeight() - .weight(1f)) + Spacer(Modifier.fillMaxHeight().weight(1f)) } Box( Modifier .fillMaxWidth() - .padding(bottom = 16.dp), contentAlignment = Alignment.Center) { + .padding(bottom = 16.dp), contentAlignment = Alignment.Center + ) { SimpleButton(text = stringResource(R.string.how_it_works), icon = Icons.Outlined.Info, click = showModal { HowItWorks(user, onboardingStage) }) } @@ -80,7 +84,7 @@ fun SimpleXLogo() { painter = painterResource(if (isInDarkTheme()) R.drawable.logo_light else R.drawable.logo), contentDescription = stringResource(R.string.image_descr_simplex_logo), modifier = Modifier - .padding(vertical = 20.dp) + .padding(vertical = DEFAULT_PADDING) .fillMaxWidth(0.80f) ) } @@ -98,7 +102,6 @@ private fun InfoRow(icon: Painter, @StringRes titleId: Int, @StringRes textId: I } } - @Composable fun OnboardingActionButton(user: User?, onboardingStage: MutableState, onclick: (() -> Unit)? = null) { if (user == null) { @@ -139,7 +142,7 @@ fun PreviewSimpleXInfo() { SimpleXInfoLayout( user = null, onboardingStage = null, - showModal = {{}} + showModal = { {} } ) } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/AdvancedNetworkSettings.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/AdvancedNetworkSettings.kt index 589181a131..f3478b6b43 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/AdvancedNetworkSettings.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/AdvancedNetworkSettings.kt @@ -147,13 +147,7 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) { .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.Start, ) { - Text( - stringResource(R.string.network_settings_title), - Modifier.padding(start = 16.dp, bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) - SectionSpacer() - + AppBarTitle(stringResource(R.string.network_settings_title)) SectionView { SectionItemView { ResetToDefaultsButton(reset, disabled = resetDisabled) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/Appearance.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/Appearance.kt index 3ab5ac25ab..80e6a51450 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/Appearance.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/Appearance.kt @@ -23,13 +23,14 @@ import androidx.compose.ui.graphics.* import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.capitalize +import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.toBitmap import chat.simplex.app.* import chat.simplex.app.R -import chat.simplex.app.model.ChatModel import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import com.godaddy.android.colorpicker.* @@ -40,9 +41,7 @@ enum class AppIcon(val resId: Int) { } @Composable -fun AppearanceView( - showCustomModal: (@Composable (ChatModel, () -> Unit) -> Unit) -> (() -> Unit), -) { +fun AppearanceView() { val appIcon = remember { mutableStateOf(findEnabledIcon()) } fun setAppIcon(newIcon: AppIcon) { @@ -65,19 +64,15 @@ fun AppearanceView( AppearanceLayout( appIcon, changeIcon = ::setAppIcon, - showThemeSelector = showCustomModal { _, close -> - ModalView( - close = close, modifier = Modifier, - background = if (isInDarkTheme()) colors.background else SettingsBackgroundLight - ) { ThemeSelectorView() } + showThemeSelector = { + ModalManager.shared.showModal(true) { + ThemeSelectorView() + } }, editPrimaryColor = { primary -> - showCustomModal { _, close -> - ModalView( - close = close, modifier = Modifier, - background = if (isInDarkTheme()) colors.background else SettingsBackgroundLight - ) { ColorEditor(primary, close) } - }() + ModalManager.shared.showModalCloseable { close -> + ColorEditor(primary, close) + } }, ) } @@ -92,12 +87,8 @@ fun AppearanceView( Modifier.fillMaxWidth(), horizontalAlignment = Alignment.Start, ) { - Text( - stringResource(R.string.appearance_settings), - Modifier.padding(start = 16.dp, bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) - SectionView(stringResource(R.string.settings_section_title_icon)) { + AppBarTitle(stringResource(R.string.appearance_settings)) + SectionView(stringResource(R.string.settings_section_title_icon), padding = PaddingValues(horizontal = DEFAULT_PADDING_HALF)) { LazyRow { items(AppIcon.values().size, { index -> AppIcon.values()[index] }) { index -> val item = AppIcon.values()[index] @@ -123,19 +114,15 @@ fun AppearanceView( SectionSpacer() val currentTheme by CurrentColors.collectAsState() SectionView(stringResource(R.string.settings_section_title_themes)) { - Column( - Modifier.padding(horizontal = 8.dp) - ) { - SectionItemViewSpaceBetween(showThemeSelector, padding = PaddingValues()) { - Text(generalGetString(R.string.theme)) - } - Spacer(Modifier.padding(horizontal = 4.dp)) + SectionItemViewSpaceBetween(showThemeSelector) { + Text(generalGetString(R.string.theme)) + } + Spacer(Modifier.padding(horizontal = 4.dp)) - SectionItemViewSpaceBetween({ editPrimaryColor(currentTheme.first.primary) }, padding = PaddingValues()) { - val title = generalGetString(R.string.color_primary) - Text(title) - Icon(Icons.Filled.Circle, title, tint = colors.primary) - } + SectionItemViewSpaceBetween({ editPrimaryColor(currentTheme.first.primary) }) { + val title = generalGetString(R.string.color_primary) + Text(title) + Icon(Icons.Filled.Circle, title, tint = colors.primary) } } if (currentTheme.first.primary != LightColorPalette.primary) { @@ -161,6 +148,7 @@ fun ColorEditor( Modifier .fillMaxWidth() ) { + AppBarTitle(stringResource(R.string.color_primary)) var currentColor by remember { mutableStateOf(initialColor) } ColorPicker(initialColor) { currentColor = it diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/CallSettings.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/CallSettings.kt index aaf3190dc6..085824c787 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/CallSettings.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/CallSettings.kt @@ -15,8 +15,7 @@ import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.HighOrLowlight -import chat.simplex.app.views.helpers.ExposedDropDownSettingRow -import chat.simplex.app.views.helpers.generalGetString +import chat.simplex.app.views.helpers.* @Composable fun CallSettingsView(m: ChatModel, @@ -40,12 +39,8 @@ fun CallSettingsLayout( horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.spacedBy(8.dp) ) { + AppBarTitle(stringResource(R.string.your_calls)) val lockCallState = remember { mutableStateOf(callOnLockScreen.get()) } - Text( - stringResource(R.string.your_calls), - Modifier.padding(start = 16.dp, bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) SectionView(stringResource(R.string.settings_section_title_settings)) { SectionItemView() { SharedPreferenceToggle(stringResource(R.string.connect_calls_via_relay), webrtcPolicyRelay) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/HelpView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/HelpView.kt index 5400aa0aa9..062735a144 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/HelpView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/HelpView.kt @@ -1,44 +1,35 @@ package chat.simplex.app.views.usersettings import android.content.res.Configuration -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import chat.simplex.app.R -import chat.simplex.app.model.ChatModel +import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.ui.theme.SimpleXTheme import chat.simplex.app.views.chatlist.ChatHelpView +import chat.simplex.app.views.helpers.AppBarTitle @Composable -fun HelpView(chatModel: ChatModel) { - val user = chatModel.currentUser.value - if (user != null) { - HelpLayout(displayName = user.profile.displayName) - } +fun HelpView(userDisplayName: String) { + HelpLayout(userDisplayName) } @Composable -fun HelpLayout(displayName: String) { +fun HelpLayout(userDisplayName: String) { Column( Modifier + .fillMaxWidth() .verticalScroll(rememberScrollState()) - .padding(bottom = 16.dp), + .padding(horizontal = DEFAULT_PADDING), horizontalAlignment = Alignment.Start ){ - Text( - String.format(stringResource(R.string.personal_welcome), displayName), - Modifier.padding(bottom = 24.dp), - style = MaterialTheme.typography.h1, - ) + AppBarTitle(String.format(stringResource(R.string.personal_welcome), userDisplayName), false) ChatHelpView() } } @@ -52,6 +43,6 @@ fun HelpLayout(displayName: String) { @Composable fun PreviewHelpView() { SimpleXTheme { - HelpLayout(displayName = "Alice") + HelpLayout("Alice") } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/IncognitoView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/IncognitoView.kt index 002dedf43a..5f49b15091 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/IncognitoView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/IncognitoView.kt @@ -4,11 +4,12 @@ import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.* -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import chat.simplex.app.R +import chat.simplex.app.ui.theme.DEFAULT_PADDING +import chat.simplex.app.views.helpers.AppBarTitle import chat.simplex.app.views.helpers.generalGetString @Composable @@ -18,30 +19,18 @@ fun IncognitoView() { @Composable fun IncognitoLayout() { - Column( - Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.Start, - ) { - Text( - stringResource(R.string.settings_section_title_incognito), - Modifier.padding(start = 8.dp, bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) - + Column { + AppBarTitle(stringResource(R.string.settings_section_title_incognito)) Column( Modifier .verticalScroll(rememberScrollState()) - .padding(horizontal = 8.dp) + .padding(horizontal = DEFAULT_PADDING), + verticalArrangement = Arrangement.spacedBy(20.dp) ) { - Column( - Modifier.padding(bottom = 16.dp), - verticalArrangement = Arrangement.spacedBy(20.dp) - ) { - Text(generalGetString(R.string.incognito_info_protects)) - Text(generalGetString(R.string.incognito_info_allows)) - Text(generalGetString(R.string.incognito_info_share)) - Text(generalGetString(R.string.incognito_info_find)) - } + Text(generalGetString(R.string.incognito_info_protects)) + Text(generalGetString(R.string.incognito_info_allows)) + Text(generalGetString(R.string.incognito_info_share)) + Text(generalGetString(R.string.incognito_info_find)) } } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/MarkdownHelpView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/MarkdownHelpView.kt index 6493b90bcc..c654e14c11 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/MarkdownHelpView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/MarkdownHelpView.kt @@ -2,8 +2,9 @@ package chat.simplex.app.views.usersettings import android.content.res.Configuration import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.selection.SelectionContainer -import androidx.compose.material.MaterialTheme +import androidx.compose.foundation.verticalScroll import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -14,19 +15,22 @@ import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.model.Format import chat.simplex.app.model.FormatColor +import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.ui.theme.SimpleXTheme +import chat.simplex.app.views.helpers.AppBarTitle +import chat.simplex.app.views.helpers.generalGetString @Composable fun MarkdownHelpView() { - Column { - Text( - stringResource(R.string.how_to_use_markdown), - style = MaterialTheme.typography.h1, - ) - Text( - stringResource(R.string.you_can_use_markdown_to_format_messages__prompt), - Modifier.padding(vertical = 16.dp) - ) + Column( + Modifier + .fillMaxWidth() + .verticalScroll(rememberScrollState()) + .padding(horizontal = DEFAULT_PADDING) + ) { + AppBarTitle(stringResource(R.string.how_to_use_markdown), false) + Text(stringResource(R.string.you_can_use_markdown_to_format_messages__prompt)) + Spacer(Modifier.height(DEFAULT_PADDING)) val bold = stringResource(R.string.bold) val italic = stringResource(R.string.italic) val strikethrough = stringResource(R.string.strikethrough) @@ -85,7 +89,6 @@ fun appendColor(b: AnnotatedString.Builder, s: String, c: FormatColor, after: St b.append(after) } - @Preview(showBackground = true) @Preview( uiMode = Configuration.UI_MODE_NIGHT_YES, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/NetworkAndServers.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/NetworkAndServers.kt index 35c55cbded..d5c45ca432 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/NetworkAndServers.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/NetworkAndServers.kt @@ -24,7 +24,7 @@ import chat.simplex.app.views.helpers.* fun NetworkAndServersView( chatModel: ChatModel, showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), - showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit) + showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), ) { // It's not a state, just a one-time value. Shouldn't be used in any state-related situations val netCfg = remember { chatModel.controller.getNetCfg() } @@ -110,11 +110,7 @@ fun NetworkAndServersView( horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.spacedBy(8.dp) ) { - Text( - stringResource(R.string.network_and_servers), - Modifier.padding(start = 16.dp, bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) + AppBarTitle(stringResource(R.string.network_and_servers)) SectionView(generalGetString(R.string.settings_section_title_messages)) { SettingsActionItem(Icons.Outlined.Dns, stringResource(R.string.smp_servers), showModal { SMPServersView(it) }) SectionDivider() @@ -172,7 +168,7 @@ fun UseSocksProxySwitch( private fun UseOnionHosts( onionHosts: MutableState, enabled: State, - showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), + showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), useOnion: (OnionHosts) -> Unit, ) { val values = remember { @@ -184,16 +180,13 @@ private fun UseOnionHosts( } } } - val onSelected = showSettingsModal { + val onSelected = showModal { + Column( Modifier.fillMaxWidth(), horizontalAlignment = Alignment.Start, ) { - Text( - stringResource(R.string.network_use_onion_hosts), - Modifier.padding(start = 16.dp, end = 16.dp, bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) + AppBarTitle(stringResource(R.string.network_use_onion_hosts)) SectionViewSelectable(null, onionHosts, values, useOnion) } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/NotificationsSettingsView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/NotificationsSettingsView.kt index 18d989a810..6a94a1164b 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/NotificationsSettingsView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/NotificationsSettingsView.kt @@ -1,14 +1,11 @@ package chat.simplex.app.views.usersettings import SectionItemViewSpaceBetween -import SectionTextFooter import SectionView +import SectionViewSelectable import android.os.Build import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.Check import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -47,7 +44,6 @@ enum class NotificationPreviewMode { @Composable fun NotificationsSettingsView( chatModel: ChatModel, - showCustomModal: (@Composable (ChatModel, () -> Unit) -> Unit) -> (() -> Unit), ) { val onNotificationsModeSelected = { mode: NotificationsMode -> chatModel.controller.appPrefs.notificationsMode.set(mode.name) @@ -77,17 +73,12 @@ fun NotificationsSettingsView( notificationsMode = chatModel.notificationsMode, notificationPreviewMode = chatModel.notificationPreviewMode, showPage = { page -> - showCustomModal { _, close -> - ModalView( - close = close, modifier = Modifier, - background = if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight - ) { + ModalManager.shared.showModalCloseable(true) { when (page) { CurrentPage.NOTIFICATIONS_MODE -> NotificationsModeView(chatModel.notificationsMode, onNotificationsModeSelected) CurrentPage.NOTIFICATION_PREVIEW_MODE -> NotificationPreviewView(chatModel.notificationPreviewMode, onNotificationPreviewModeSelected) } - } - }() + } }, ) } @@ -109,36 +100,28 @@ fun NotificationsSettingsLayout( Modifier.fillMaxWidth(), horizontalAlignment = Alignment.Start, ) { - Text( - stringResource(R.string.notifications), - Modifier.padding(start = 16.dp, end = 16.dp, bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) + AppBarTitle(stringResource(R.string.notifications)) SectionView(null) { - Column( - Modifier.padding(horizontal = 8.dp) - ) { - SectionItemViewSpaceBetween({ showPage(CurrentPage.NOTIFICATIONS_MODE) }, padding = PaddingValues()) { - Text(stringResource(R.string.settings_notifications_mode_title)) - Spacer(Modifier.padding(horizontal = 10.dp)) - Text( - modes.first { it.first == notificationsMode.value }.second, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - color = HighOrLowlight - ) - } - Spacer(Modifier.padding(horizontal = 4.dp)) - SectionItemViewSpaceBetween({ showPage(CurrentPage.NOTIFICATION_PREVIEW_MODE) }, padding = PaddingValues()) { - Text(stringResource(R.string.settings_notification_preview_mode_title)) - Spacer(Modifier.padding(horizontal = 10.dp)) - Text( - previewModes.first { it.first == notificationPreviewMode.value }.second, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - color = HighOrLowlight - ) - } + SectionItemViewSpaceBetween({ showPage(CurrentPage.NOTIFICATIONS_MODE) }) { + Text(stringResource(R.string.settings_notifications_mode_title)) + Spacer(Modifier.padding(horizontal = 10.dp)) + Text( + modes.first { it.value == notificationsMode.value }.title, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + color = HighOrLowlight + ) + } + Spacer(Modifier.padding(horizontal = 4.dp)) + SectionItemViewSpaceBetween({ showPage(CurrentPage.NOTIFICATION_PREVIEW_MODE) }) { + Text(stringResource(R.string.settings_notification_preview_mode_title)) + Spacer(Modifier.padding(horizontal = 10.dp)) + Text( + previewModes.first { it.value == notificationPreviewMode.value }.title, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + color = HighOrLowlight + ) } } } @@ -150,36 +133,12 @@ fun NotificationsModeView( onNotificationsModeSelected: (NotificationsMode) -> Unit, ) { val modes = remember { notificationModes() } - Column( Modifier.fillMaxWidth(), horizontalAlignment = Alignment.Start, ) { - Text( - stringResource(R.string.settings_notifications_mode_title).lowercase().capitalize(Locale.current), - Modifier.padding(start = 16.dp, end = 16.dp, bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) - SectionView(null) { - LazyColumn( - Modifier.padding(horizontal = 8.dp) - ) { - items(modes.size) { index -> - val item = modes[index] - val onClick = { - onNotificationsModeSelected(item.first) - } - SectionItemViewSpaceBetween(onClick, padding = PaddingValues()) { - Text(item.second) - if (notificationsMode.value == item.first) { - Icon(Icons.Outlined.Check, item.second, tint = HighOrLowlight) - } - } - Spacer(Modifier.padding(horizontal = 4.dp)) - } - } - } - SectionTextFooter(modes.first { it.first == notificationsMode.value }.third) + AppBarTitle(stringResource(R.string.settings_notifications_mode_title).lowercase().capitalize(Locale.current)) + SectionViewSelectable(null, notificationsMode, modes, onNotificationsModeSelected) } } @@ -189,59 +148,34 @@ fun NotificationPreviewView( onNotificationPreviewModeSelected: (NotificationPreviewMode) -> Unit, ) { val previewModes = remember { notificationPreviewModes() } - Column( Modifier.fillMaxWidth(), horizontalAlignment = Alignment.Start, ) { - Text( - stringResource(R.string.settings_notification_preview_title), - Modifier.padding(start = 16.dp, end = 16.dp, bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) - - SectionView(null) { - LazyColumn( - Modifier.padding(horizontal = 8.dp) - ) { - items(previewModes.size) { index -> - val item = previewModes[index] - val onClick = { - onNotificationPreviewModeSelected(item.first) - } - SectionItemViewSpaceBetween(onClick, padding = PaddingValues()) { - Text(item.second) - if (notificationPreviewMode.value == item.first) { - Icon(Icons.Outlined.Check, item.second, tint = HighOrLowlight) - } - } - Spacer(Modifier.padding(horizontal = 4.dp)) - } - } - } - SectionTextFooter(previewModes.first { it.first == notificationPreviewMode.value }.third) + AppBarTitle(stringResource(R.string.settings_notification_preview_title)) + SectionViewSelectable(null, notificationPreviewMode, previewModes, onNotificationPreviewModeSelected) } } // mode, name, description -fun notificationModes(): List> { - val res = ArrayList>() +fun notificationModes(): List> { + val res = ArrayList>() res.add( - Triple( + ValueTitleDesc( NotificationsMode.OFF, generalGetString(R.string.notifications_mode_off), generalGetString(R.string.notifications_mode_off_desc), ) ) res.add( - Triple( + ValueTitleDesc( NotificationsMode.PERIODIC, generalGetString(R.string.notifications_mode_periodic), generalGetString(R.string.notifications_mode_periodic_desc), ) ) res.add( - Triple( + ValueTitleDesc( NotificationsMode.SERVICE, generalGetString(R.string.notifications_mode_service), generalGetString(R.string.notifications_mode_service_desc), @@ -251,24 +185,24 @@ fun notificationModes(): List> { } // preview mode, name, description -fun notificationPreviewModes(): List> { - val res = ArrayList>() +fun notificationPreviewModes(): List> { + val res = ArrayList>() res.add( - Triple( + ValueTitleDesc( NotificationPreviewMode.MESSAGE, generalGetString(R.string.notification_preview_mode_message), generalGetString(R.string.notification_preview_mode_message_desc), ) ) res.add( - Triple( + ValueTitleDesc( NotificationPreviewMode.CONTACT, generalGetString(R.string.notification_preview_mode_contact), generalGetString(R.string.notification_preview_mode_contact_desc), ) ) res.add( - Triple( + ValueTitleDesc( NotificationPreviewMode.HIDDEN, generalGetString(R.string.notification_preview_mode_hidden), generalGetString(R.string.notification_display_mode_hidden_desc), diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/PrivacySettings.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/PrivacySettings.kt index bc4cb3f3a1..eb46e36e6e 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/PrivacySettings.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/PrivacySettings.kt @@ -15,6 +15,8 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.model.ChatModel +import chat.simplex.app.views.helpers.AppBarTitle +import chat.simplex.app.views.helpers.generalGetString @Composable fun PrivacySettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) { @@ -22,11 +24,7 @@ fun PrivacySettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) { Modifier.fillMaxWidth(), horizontalAlignment = Alignment.Start ) { - Text( - stringResource(R.string.your_privacy), - style = MaterialTheme.typography.h1, - modifier = Modifier.padding(start = 16.dp, bottom = 24.dp) - ) + AppBarTitle(stringResource(R.string.your_privacy)) SectionView(stringResource(R.string.settings_section_title_device)) { ChatLockItem(chatModel.performLA, setPerformLA) } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/RTCServers.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/RTCServers.kt index ff268f8a9a..d893e90699 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/RTCServers.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/RTCServers.kt @@ -20,7 +20,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.ChatModel -import chat.simplex.app.ui.theme.HighOrLowlight +import chat.simplex.app.ui.theme.* import chat.simplex.app.views.call.parseRTCIceServers import chat.simplex.app.views.helpers.* @@ -98,15 +98,11 @@ fun RTCServersLayout( editOn: () -> Unit, ) { Column( - Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.Start, - verticalArrangement = Arrangement.spacedBy(8.dp) + Modifier + .fillMaxWidth() + .padding(horizontal = DEFAULT_PADDING), ) { - Text( - stringResource(R.string.your_ICE_servers), - Modifier.padding(bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) + AppBarTitle(stringResource(R.string.your_ICE_servers), false) SectionItemViewSpaceBetween(padding = PaddingValues()) { Text(stringResource(R.string.configure_ICE_servers), Modifier.padding(end = 24.dp)) Switch( diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SMPServers.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SMPServers.kt index 24331b7eb4..d3c7d2262d 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SMPServers.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SMPServers.kt @@ -20,8 +20,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.ChatModel -import chat.simplex.app.ui.theme.HighOrLowlight -import chat.simplex.app.ui.theme.SimpleXTheme +import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* @Composable @@ -99,15 +98,11 @@ fun SMPServersLayout( editOn: () -> Unit, ) { Column( - Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.Start, - verticalArrangement = Arrangement.spacedBy(8.dp) + Modifier + .fillMaxWidth() + .padding(horizontal = DEFAULT_PADDING), ) { - Text( - stringResource(R.string.your_SMP_servers), - Modifier.padding(bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) + AppBarTitle(stringResource(R.string.your_SMP_servers), false) SectionItemViewSpaceBetween(padding = PaddingValues()) { Text(stringResource(R.string.configure_SMP_servers), Modifier.padding(end = 24.dp)) Switch( diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt index 9384e69306..2654acb8fa 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt @@ -50,14 +50,10 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) { chatModel.incognito, chatModel.controller.appPrefs.incognito, developerTools = chatModel.controller.appPrefs.developerTools, + user.displayName, setPerformLA = setPerformLA, showModal = { modalView -> { ModalManager.shared.showModal { modalView(chatModel) } } }, - showSettingsModal = { modalView -> { ModalManager.shared.showCustomModal { close -> - ModalView(close = close, modifier = Modifier, - background = if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight) { - modalView(chatModel) - } - } } }, + showSettingsModal = { modalView -> { ModalManager.shared.showModal(true) { modalView(chatModel) } } }, showCustomModal = { modalView -> { ModalManager.shared.showCustomModal { close -> modalView(chatModel, close) } } }, showTerminal = { ModalManager.shared.showCustomModal { close -> TerminalView(chatModel, close) } }, // showVideoChatPrototype = { ModalManager.shared.showCustomModal { close -> CallViewDebug(close) } }, @@ -86,6 +82,7 @@ fun SettingsLayout( incognito: MutableState, incognitoPref: Preference, developerTools: Preference, + userDisplayName: String, setPerformLA: (Boolean) -> Unit, showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), @@ -99,21 +96,23 @@ fun SettingsLayout( Modifier .fillMaxSize() .background(if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight) - .padding(top = 16.dp) + .padding(top = DEFAULT_PADDING) ) { Text( stringResource(R.string.your_settings), style = MaterialTheme.typography.h1, - modifier = Modifier.padding(start = 16.dp) + modifier = Modifier.padding(horizontal = DEFAULT_PADDING), + overflow = TextOverflow.Ellipsis, ) - SectionSpacer() + + Spacer(Modifier.height(30.dp)) SectionView(stringResource(R.string.settings_section_title_you)) { SectionItemView(showCustomModal { chatModel, close -> UserProfileView(chatModel, close) }, 80.dp, disabled = stopped) { ProfilePreview(profile, stopped = stopped) } SectionDivider() - SettingsIncognitoActionItem(incognitoPref, incognito, stopped) { onClickIncognitoInfo(showModal) } + SettingsIncognitoActionItem(incognitoPref, incognito, stopped) { showModal { IncognitoView() }() } SectionDivider() SettingsActionItem(Icons.Outlined.QrCode, stringResource(R.string.your_simplex_contact_address), showModal { CreateLinkView(it, CreateLinkTab.LONG_TERM) }, disabled = stopped) SectionDivider() @@ -122,20 +121,20 @@ fun SettingsLayout( SectionSpacer() SectionView(stringResource(R.string.settings_section_title_settings)) { - SettingsActionItem(Icons.Outlined.Bolt, stringResource(R.string.notifications), showSettingsModal { NotificationsSettingsView(it, showCustomModal) }, disabled = stopped) + SettingsActionItem(Icons.Outlined.Bolt, stringResource(R.string.notifications), showSettingsModal { NotificationsSettingsView(it) }, disabled = stopped) SectionDivider() SettingsActionItem(Icons.Outlined.Videocam, stringResource(R.string.settings_audio_video_calls), showSettingsModal { CallSettingsView(it, showModal) }, disabled = stopped) SectionDivider() SettingsActionItem(Icons.Outlined.Lock, stringResource(R.string.privacy_and_security), showSettingsModal { PrivacySettingsView(it, setPerformLA) }, disabled = stopped) SectionDivider() - SettingsActionItem(Icons.Outlined.LightMode, stringResource(R.string.appearance_settings), showSettingsModal { AppearanceView(showCustomModal) }, disabled = stopped) + SettingsActionItem(Icons.Outlined.LightMode, stringResource(R.string.appearance_settings), showSettingsModal { AppearanceView() }, disabled = stopped) SectionDivider() SettingsActionItem(Icons.Outlined.WifiTethering, stringResource(R.string.network_and_servers), showSettingsModal { NetworkAndServersView(it, showModal, showSettingsModal) }, disabled = stopped) } SectionSpacer() SectionView(stringResource(R.string.settings_section_title_help)) { - SettingsActionItem(Icons.Outlined.HelpOutline, stringResource(R.string.how_to_use_simplex_chat), showModal { HelpView(it) }, disabled = stopped) + SettingsActionItem(Icons.Outlined.HelpOutline, stringResource(R.string.how_to_use_simplex_chat), showModal { HelpView(userDisplayName) }, disabled = stopped) SectionDivider() SettingsActionItem(Icons.Outlined.Info, stringResource(R.string.about_simplex_chat), showModal { SimpleXInfo(it, onboarding = false) }) SectionDivider() @@ -180,10 +179,6 @@ fun SettingsIncognitoActionItem( ) } -private val onClickIncognitoInfo: ((@Composable (ChatModel) -> Unit) -> (() -> Unit)) -> Unit = { showModal -> - showModal { IncognitoView() }() -} - @Composable fun MaintainIncognitoState(chatModel: ChatModel) { // Cache previous value and once it changes in background, update it via API @@ -311,7 +306,7 @@ fun MaintainIncognitoState(chatModel: ChatModel) { @Composable fun SettingsActionItem(icon: ImageVector, text: String, click: (() -> Unit)? = null, textColor: Color = Color.Unspecified, iconColor: Color = HighOrLowlight, disabled: Boolean = false) { SectionItemView(click, disabled = disabled) { - Icon(icon, text, tint = iconColor) + Icon(icon, text, tint = if (disabled) HighOrLowlight else iconColor) Spacer(Modifier.padding(horizontal = 4.dp)) Text(text, color = if (disabled) HighOrLowlight else textColor) } @@ -338,8 +333,8 @@ fun SettingsPreferenceItemWithInfo( pref: Preference, prefState: MutableState? = null ) { - SectionItemView() { - Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clickable { onClickInfo() }) { + SectionItemView(onClickInfo) { + Row(verticalAlignment = Alignment.CenterVertically) { Icon(icon, text, tint = if (stopped) HighOrLowlight else iconTint) Spacer(Modifier.padding(horizontal = 4.dp)) SharedPreferenceToggleWithIcon(text, Icons.Outlined.Info, stopped, onClickInfo, pref, prefState) @@ -361,12 +356,13 @@ fun PreviewSettingsLayout() { stopped = false, encrypted = false, incognito = remember { mutableStateOf(false) }, - incognitoPref = Preference({ false}, {}), + incognitoPref = Preference({ false }, {}), developerTools = Preference({ false }, {}), + userDisplayName = "Alice", setPerformLA = {}, showModal = { {} }, showSettingsModal = { {} }, - showCustomModal = { {} }, + showCustomModal = { {}}, showTerminal = {}, // showVideoChatPrototype = {} ) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/ThemeSelector.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/ThemeSelector.kt index 9f410a1bc9..65b4ffed48 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/ThemeSelector.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/ThemeSelector.kt @@ -1,69 +1,44 @@ package chat.simplex.app.views.usersettings -import SectionItemViewSpaceBetween -import SectionView +import SectionViewSelectable import androidx.compose.foundation.* import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.capitalize import androidx.compose.ui.text.intl.Locale -import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.ui.theme.* +import chat.simplex.app.views.helpers.* @Composable fun ThemeSelectorView() { val darkTheme = isSystemInDarkTheme() - val allThemes by remember { mutableStateOf(ThemeManager.allThemes(darkTheme)) } + val allThemes by remember { mutableStateOf(ThemeManager.allThemes(darkTheme).map { ValueTitleDesc(it.second, it.third, "") }) } ThemeSelectorLayout( allThemes, onSelectTheme = { - ThemeManager.applyTheme(it, darkTheme) + ThemeManager.applyTheme(it.name, darkTheme) }, ) } -@Composable fun ThemeSelectorLayout( - allThemes: List>, - onSelectTheme: (String) -> Unit, +@Composable +private fun ThemeSelectorLayout( + allThemes: List>, + onSelectTheme: (DefaultTheme) -> Unit, ) { Column( Modifier.fillMaxWidth(), horizontalAlignment = Alignment.Start, ) { - Text( - stringResource(R.string.settings_section_title_themes).lowercase().capitalize(Locale.current), - Modifier.padding(start = 16.dp, bottom = 24.dp), - style = MaterialTheme.typography.h1 - ) + AppBarTitle(stringResource(R.string.settings_section_title_themes).lowercase().capitalize(Locale.current)) val currentTheme by CurrentColors.collectAsState() - SectionView(null) { - LazyColumn( - Modifier.padding(horizontal = 8.dp) - ) { - items(allThemes.size) { index -> - val item = allThemes[index] - val onClick = { - onSelectTheme(item.second.name) - } - SectionItemViewSpaceBetween(onClick, padding = PaddingValues()) { - Text(item.third) - if (currentTheme.second == item.second) { - Icon(Icons.Outlined.Check, item.third, tint = HighOrLowlight) - } - } - Spacer(Modifier.padding(horizontal = 4.dp)) - } - } - } + val state = remember { derivedStateOf { currentTheme.second } } + SectionViewSelectable(null, state, allThemes, onSelectTheme) } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserAddressView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserAddressView.kt index e2a1bcb86f..0dcaf65133 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserAddressView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserAddressView.kt @@ -2,7 +2,6 @@ package chat.simplex.app.views.usersettings import android.content.res.Configuration import androidx.compose.foundation.layout.* -import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.* @@ -60,11 +59,7 @@ fun UserAddressLayout( horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.Top ) { - Text( - stringResource(R.string.your_contact_address), - Modifier.padding(bottom = 16.dp), - style = MaterialTheme.typography.h1, - ) + AppBarTitle(stringResource(R.string.your_contact_address), false) Text( stringResource(R.string.you_can_share_your_address_anybody_will_be_able_to_connect), Modifier.padding(bottom = 12.dp), diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfileView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfileView.kt index 54a268e394..96353c3ece 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfileView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfileView.kt @@ -23,8 +23,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.* -import chat.simplex.app.ui.theme.HighOrLowlight -import chat.simplex.app.ui.theme.SimpleXTheme +import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import chat.simplex.app.views.isValidDisplayName import com.google.accompanist.insets.ProvideWindowInsets @@ -38,9 +37,9 @@ fun UserProfileView(chatModel: ChatModel, close: () -> Unit) { val editProfile = remember { mutableStateOf(false) } var profile by remember { mutableStateOf(user.profile.toProfile()) } UserProfileLayout( - close = close, editProfile = editProfile, profile = profile, + close, saveProfile = { displayName, fullName, image -> withApi { val p = Profile(displayName, fullName, image) @@ -60,9 +59,9 @@ fun UserProfileView(chatModel: ChatModel, close: () -> Unit) { @Composable fun UserProfileLayout( - close: () -> Unit, editProfile: MutableState, profile: Profile, + close: () -> Unit, saveProfile: (String, String, String?) -> Unit, ) { val bottomSheetModalState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden) @@ -74,7 +73,6 @@ fun UserProfileLayout( val scrollState = rememberScrollState() val keyboardState by getKeyboardState() var savedKeyboardState by remember { mutableStateOf(keyboardState) } - ProvideWindowInsets(windowInsetsAnimationsEnabled = true) { ModalBottomSheetLayout( scrimColor = Color.Black.copy(alpha = 0.12F), @@ -94,15 +92,10 @@ fun UserProfileLayout( Column( Modifier .verticalScroll(scrollState) - .padding(bottom = 16.dp), + .padding(horizontal = DEFAULT_PADDING), horizontalAlignment = Alignment.Start ) { - Text( - stringResource(R.string.your_chat_profile), - Modifier.padding(bottom = 24.dp), - style = MaterialTheme.typography.h1, - color = MaterialTheme.colors.onBackground - ) + AppBarTitle(stringResource(R.string.your_chat_profile), false) Text( stringResource(R.string.your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it), Modifier.padding(bottom = 24.dp), @@ -279,8 +272,8 @@ fun DeleteImageButton(click: () -> Unit) { fun PreviewUserProfileLayoutEditOff() { SimpleXTheme { UserProfileLayout( - close = {}, profile = Profile.sampleData, + close = {}, editProfile = remember { mutableStateOf(false) }, saveProfile = { _, _, _ -> } ) @@ -297,8 +290,8 @@ fun PreviewUserProfileLayoutEditOff() { fun PreviewUserProfileLayoutEditOn() { SimpleXTheme { UserProfileLayout( - close = {}, profile = Profile.sampleData, + close = {}, editProfile = remember { mutableStateOf(true) }, saveProfile = { _, _, _ -> } )