From 38640697af2354929d524a955b9ce2ad3b35d2a8 Mon Sep 17 00:00:00 2001 From: Avently <7953703+avently@users.noreply.github.com> Date: Tue, 4 Oct 2022 16:55:19 +0300 Subject: [PATCH] UI changes --- .../java/chat/simplex/app/model/ChatModel.kt | 1 + .../simplex/app/views/chat/ChatInfoView.kt | 10 +- .../app/views/chatlist/ChatListNavLinkView.kt | 10 +- .../app/views/newchat/AddContactView.kt | 10 +- .../newchat/ContactConnectionInfoView.kt | 157 ++++++++++-------- .../app/views/newchat/CreateLinkView.kt | 8 - .../app/src/main/res/values-de/strings.xml | 1 - .../app/src/main/res/values-ru/strings.xml | 1 - .../app/src/main/res/values/strings.xml | 1 - 9 files changed, 105 insertions(+), 94 deletions(-) diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt b/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt index 3b02db61e1..b6c4470576 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt @@ -290,6 +290,7 @@ class ChatModel(val controller: ChatController) { if (connReqInv.value == null) return val info = getChat(id)?.chatInfo as? ChatInfo.ContactConnection ?: return if (info.contactConnection.connReqInv == connReqInv.value) { + connReqInv.value = null ModalManager.shared.closeModals() } } 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 1e3b7f0d2e..ccf936860f 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 @@ -208,21 +208,21 @@ fun ChatInfoHeader(cInfo: ChatInfo, contact: Contact) { } @Composable -fun LocalAliasEditor(initialValue: String, updateValue: (String) -> Unit) { +fun LocalAliasEditor(initialValue: String, center: Boolean = true, updateValue: (String) -> Unit) { var value by rememberSaveable { mutableStateOf(initialValue) } - Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { + Row(Modifier.fillMaxWidth(), horizontalArrangement = if (center) Arrangement.Center else Arrangement.Start) { DefaultBasicTextField( - Modifier.padding(horizontal = 10.dp).widthIn(min = 100.dp), + Modifier.padding(horizontal = DEFAULT_PADDING).widthIn(min = 100.dp), value, { Text( generalGetString(R.string.text_field_set_contact_placeholder), - textAlign = TextAlign.Center, + textAlign = if (center) TextAlign.Center else TextAlign.Start, color = HighOrLowlight ) }, color = HighOrLowlight, - textStyle = TextStyle.Default.copy(textAlign = if (value.isEmpty()) TextAlign.Start else TextAlign.Center), + textStyle = TextStyle.Default.copy(textAlign = if (value.isEmpty() || !center) TextAlign.Start else TextAlign.Center), keyboardActions = KeyboardActions(onDone = { updateValue(value) }) ) { value = it diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt index 1173528854..d85c930bd0 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt @@ -22,6 +22,7 @@ import chat.simplex.app.views.chat.group.deleteGroupDialog import chat.simplex.app.views.chat.group.leaveGroupDialog import chat.simplex.app.views.chat.item.ItemAction import chat.simplex.app.views.helpers.* +import chat.simplex.app.views.newchat.ContactConnectionInfoView import kotlinx.coroutines.delay import kotlinx.datetime.Clock @@ -63,10 +64,11 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) { is ChatInfo.ContactConnection -> ChatListNavLinkLayout( chatLinkPreview = { ContactConnectionView(chat.chatInfo.contactConnection) }, - click = { chat.chatInfo.contactConnection.connReqInv.let { - if (it == null) contactConnectionAlertDialog(chat.chatInfo.contactConnection, chatModel) - else ModalManager.shared.showModalCloseable { close -> ContactConnectionInfoView(chatModel, it, chat.chatInfo.contactConnection, close) } - } }, + click = { + ModalManager.shared.showModalCloseable(true) { close -> + ContactConnectionInfoView(chatModel, chat.chatInfo.contactConnection.connReqInv, chat.chatInfo.contactConnection, close) + } + }, dropdownMenuItems = { ContactConnectionMenuItems(chat.chatInfo, chatModel, showMenu) }, showMenu, stopped 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 a64a0a3356..3629a7d74d 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 @@ -9,7 +9,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.TheaterComedy import androidx.compose.material.icons.outlined.Info import androidx.compose.material.icons.outlined.Share -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -26,6 +26,14 @@ import chat.simplex.app.views.helpers.* @Composable fun AddContactView(chatModel: ChatModel, connReqInvitation: String) { val cxt = LocalContext.current + LaunchedEffect(connReqInvitation) { + if (connReqInvitation.isNotEmpty()) { + chatModel.connReqInv.value = connReqInvitation + } + } + DisposableEffect(Unit) { + onDispose { chatModel.connReqInv.value = null } + } AddContactLayout( chatModelIncognito = chatModel.incognito.value, connReq = connReqInvitation, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ContactConnectionInfoView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ContactConnectionInfoView.kt index 20f831a6fd..a8cb7218ae 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ContactConnectionInfoView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ContactConnectionInfoView.kt @@ -1,6 +1,9 @@ -package chat.simplex.app.views.chatlist +package chat.simplex.app.views.newchat +import SectionDivider +import SectionView import android.content.res.Configuration +import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -10,111 +13,118 @@ import androidx.compose.material.icons.outlined.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext 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.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.chat.LocalAliasEditor +import chat.simplex.app.views.chatlist.deleteContactConnectionAlert import chat.simplex.app.views.helpers.* -import chat.simplex.app.views.newchat.InfoAboutIncognito -import chat.simplex.app.views.newchat.QRCode +import chat.simplex.app.views.usersettings.SettingsActionItem @Composable -fun ContactConnectionInfoView(chatModel: ChatModel, connReqInvitation: String, contactConnection: PendingContactConnection, close: () -> Unit) { - val cxt = LocalContext.current - LaunchedEffect(Unit) { - if (contactConnection.connReqInv != null) { - chatModel.connReqInv.value = contactConnection.connReqInv - } +fun ContactConnectionInfoView(chatModel: ChatModel, connReqInvitation: String?, contactConnection: PendingContactConnection, close: () -> Unit) { + /** When [AddContactView] is open, we don't need to drop [chatModel.connReqInv]. It will be managed by [AddContactView] itself + * Otherwise it will be called here AFTER [AddContactView] is launched and will clear the value too soon */ + val allowDispose = remember { mutableStateOf(true) } + LaunchedEffect(connReqInvitation) { + allowDispose.value = true + chatModel.connReqInv.value = connReqInvitation } DisposableEffect(Unit) { - onDispose { chatModel.connReqInv.value = null } + onDispose { + if (allowDispose.value) { + chatModel.connReqInv.value = null + } + } } ContactConnectionInfoLayout( - chatModelIncognito = chatModel.incognito.value, connReq = connReqInvitation, contactConnection.localAlias, - share = { shareText(cxt, connReqInvitation) }, + contactConnection.initiated, + contactConnection.viaContactUri, deleteConnection = { deleteContactConnectionAlert(contactConnection, chatModel, close) }, - onLocalAliasChanged = { setContactAlias(contactConnection, it, chatModel) } + onLocalAliasChanged = { setContactAlias(contactConnection, it, chatModel) }, + showQr = { + allowDispose.value = false + ModalManager.shared.showModal { + Column( + Modifier + .fillMaxHeight() + .padding(horizontal = DEFAULT_PADDING), + verticalArrangement = Arrangement.SpaceBetween + ) { + AddContactView(chatModel, connReqInvitation ?: return@showModal) + } + } + } ) } @Composable private fun ContactConnectionInfoLayout( - chatModelIncognito: Boolean, - connReq: String, + connReq: String?, localAlias: String, - share: () -> Unit, + connectionInitiated: Boolean, + connectionViaContactUri: Boolean, deleteConnection: () -> Unit, - onLocalAliasChanged: (String) -> Unit + onLocalAliasChanged: (String) -> Unit, + showQr: () -> Unit, ) { BoxWithConstraints { - val screenHeight = maxHeight - var showQr by remember { mutableStateOf(false) } Column( Modifier - .verticalScroll(rememberScrollState()) - .padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING , bottom = DEFAULT_PADDING), - verticalArrangement = Arrangement.SpaceBetween, + .verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.shared_one_time_link), false) - - LocalAliasEditor(localAlias, updateValue = onLocalAliasChanged) - - Text( - stringResource(R.string.show_QR_code_for_your_contact_to_scan_from_the_app__multiline), + AppBarTitle( + stringResource( + if (connectionInitiated) R.string.you_invited_your_contact + else R.string.you_accepted_connection + ) ) - Row { - InfoAboutIncognito( - chatModelIncognito, - true, - generalGetString(R.string.incognito_random_profile_description), - generalGetString(R.string.your_profile_will_be_sent) - ) - } - if (connReq.isNotEmpty() && showQr) { - QRCode( - connReq, Modifier - .aspectRatio(1f) - .padding(vertical = 3.dp) - ) + Text( + stringResource( + if (connectionViaContactUri) R.string.you_will_be_connected_when_your_connection_request_is_accepted + else R.string.you_will_be_connected_when_your_contacts_device_is_online + ), + Modifier.padding(horizontal = DEFAULT_PADDING) + ) + LocalAliasEditor(localAlias, center = false, updateValue = onLocalAliasChanged) - Text( - annotatedStringResource(R.string.if_you_cannot_meet_in_person_show_QR_in_video_call_or_via_another_channel), - lineHeight = 22.sp, - modifier = Modifier - .padding(bottom = if (screenHeight > 600.dp) 8.dp else 0.dp) - ) - } - if (!showQr) { - Row( - Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center - ) { - SimpleButton(stringResource(R.string.show_QR_code), icon = Icons.Outlined.QrCode, click = { showQr = true }) + SectionView { + if (!connReq.isNullOrEmpty() && connectionInitiated) { + ShowQrButton(showQr) + SectionDivider() } - } - Row( - Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center - ) { - SimpleButton(stringResource(R.string.share_invitation_link), icon = Icons.Outlined.Share, click = share) - } - Row( - Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center - ) { - SimpleButton(stringResource(R.string.delete_verb), icon = Icons.Outlined.Delete, color = Color.Red, click = deleteConnection) + DeleteButton(deleteConnection) } } } } +@Composable +fun ShowQrButton(onClick: () -> Unit) { + SettingsActionItem( + Icons.Outlined.QrCode, + stringResource(R.string.show_QR_code), + click = onClick, + textColor = MaterialTheme.colors.primary, + iconColor = MaterialTheme.colors.primary, + ) +} + +@Composable +fun DeleteButton(onClick: () -> Unit) { + SettingsActionItem( + Icons.Outlined.Delete, + stringResource(R.string.delete_verb), + click = onClick, + textColor = Color.Red, + iconColor = Color.Red, + ) +} + private fun setContactAlias(contactConnection: PendingContactConnection, localAlias: String, chatModel: ChatModel) = withApi { chatModel.controller.apiSetConnectionAlias(contactConnection.pccConnId, localAlias)?.let { chatModel.updateContactConnection(it) @@ -128,15 +138,16 @@ private fun setContactAlias(contactConnection: PendingContactConnection, localAl name = "Dark Mode" ) @Composable -private fun PreviewAddContactView() { +private fun PreviewContactConnectionInfoView() { SimpleXTheme { ContactConnectionInfoLayout( - chatModelIncognito = false, localAlias = "", connReq = "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D", - share = {}, + connectionInitiated = true, + connectionViaContactUri = true, deleteConnection = {}, onLocalAliasChanged = {}, + showQr = {}, ) } } 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 1fe555a85a..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 @@ -29,14 +29,6 @@ fun CreateLinkView(m: ChatModel, initialSelection: CreateLinkTab) { createInvitation(m, creatingConnReq, connReqInvitation) } } - LaunchedEffect(connReqInvitation.value) { - if (connReqInvitation.value.isNotEmpty()) { - m.connReqInv.value = connReqInvitation.value - } - } - DisposableEffect(Unit) { - onDispose { m.connReqInv.value = null } - } val tabTitles = CreateLinkTab.values().map { when { it == CreateLinkTab.ONE_TIME && connReqInvitation.value.isEmpty() -> stringResource(R.string.create_one_time_link) diff --git a/apps/android/app/src/main/res/values-de/strings.xml b/apps/android/app/src/main/res/values-de/strings.xml index 4f96cea009..451f549ffd 100644 --- a/apps/android/app/src/main/res/values-de/strings.xml +++ b/apps/android/app/src/main/res/values-de/strings.xml @@ -309,7 +309,6 @@ Show QR code - Shared one-time link Ungültiger QR-Code diff --git a/apps/android/app/src/main/res/values-ru/strings.xml b/apps/android/app/src/main/res/values-ru/strings.xml index e460789e4b..f77c805986 100644 --- a/apps/android/app/src/main/res/values-ru/strings.xml +++ b/apps/android/app/src/main/res/values-ru/strings.xml @@ -309,7 +309,6 @@ Показать QR код - Поделиться одноразовой ссылкой Неверный QR код diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index d8f214435c..52c66ec778 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -309,7 +309,6 @@ Show QR code - Shared one-time link Invalid QR code