android: rework incognito mode - choose when making connection (#2867)
* android: rework incognito mode - choose when making connection * remove commented code * remove commented code * change text * text editor border * smaller qr code * chat preview height * fix spacing * desktop dialogue * remove import --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
@@ -118,6 +118,7 @@ object NtfManager {
|
||||
val actionPendingIntent: PendingIntent = PendingIntent.getBroadcast(SimplexApp.context, 0, actionIntent, flags)
|
||||
val actionButton = when (action) {
|
||||
NotificationAction.ACCEPT_CONTACT_REQUEST -> generalGetString(MR.strings.accept)
|
||||
NotificationAction.ACCEPT_CONTACT_REQUEST_INCOGNITO -> generalGetString(MR.strings.accept_contact_incognito_button)
|
||||
}
|
||||
builder.addAction(0, actionButton, actionPendingIntent)
|
||||
}
|
||||
@@ -260,7 +261,8 @@ object NtfManager {
|
||||
val chatId = intent?.getStringExtra(ChatIdKey) ?: return
|
||||
val m = SimplexApp.context.chatModel
|
||||
when (intent.action) {
|
||||
NotificationAction.ACCEPT_CONTACT_REQUEST.name -> ntfManager.acceptContactRequestAction(userId, chatId)
|
||||
NotificationAction.ACCEPT_CONTACT_REQUEST.name -> ntfManager.acceptContactRequestAction(userId, incognito = false, chatId)
|
||||
NotificationAction.ACCEPT_CONTACT_REQUEST_INCOGNITO.name -> ntfManager.acceptContactRequestAction(userId, incognito = true, chatId)
|
||||
RejectCallAction -> {
|
||||
val invitation = m.callInvitations[chatId]
|
||||
if (invitation != null) {
|
||||
|
||||
@@ -13,7 +13,8 @@ actual fun ScanToConnectView(chatModel: ChatModel, close: () -> Unit) {
|
||||
cameraPermissionState.launchPermissionRequest()
|
||||
}
|
||||
ConnectContactLayout(
|
||||
chatModelIncognito = chatModel.incognito.value,
|
||||
close
|
||||
chatModel = chatModel,
|
||||
incognitoPref = chatModel.controller.appPrefs.incognito,
|
||||
close = close
|
||||
)
|
||||
}
|
||||
|
||||
@@ -80,7 +80,6 @@ object ChatModel {
|
||||
}
|
||||
val performLA by lazy { mutableStateOf(ChatController.appPrefs.performLA.get()) }
|
||||
val showAdvertiseLAUnavailableAlert = mutableStateOf(false)
|
||||
val incognito by lazy { mutableStateOf(ChatController.appPrefs.incognito.get()) }
|
||||
|
||||
// current WebRTC call
|
||||
val callManager = CallManager(this)
|
||||
|
||||
@@ -331,7 +331,6 @@ object ChatController {
|
||||
if (justStarted) {
|
||||
chatModel.currentUser.value = user
|
||||
chatModel.userCreated.value = true
|
||||
apiSetIncognito(chatModel.incognito.value)
|
||||
getUserChatData()
|
||||
appPrefs.chatLastStart.set(Clock.System.now())
|
||||
chatModel.chatRunning.value = true
|
||||
@@ -546,12 +545,6 @@ object ChatController {
|
||||
throw Error("apiSetXFTPConfig bad response: ${r.responseType} ${r.details}")
|
||||
}
|
||||
|
||||
suspend fun apiSetIncognito(incognito: Boolean) {
|
||||
val r = sendCmd(CC.SetIncognito(incognito))
|
||||
if (r is CR.CmdOk) return
|
||||
throw Exception("failed to set incognito: ${r.responseType} ${r.details}")
|
||||
}
|
||||
|
||||
suspend fun apiExportArchive(config: ArchiveConfig) {
|
||||
val r = sendCmd(CC.ApiExportArchive(config))
|
||||
if (r is CR.CmdOk) return
|
||||
@@ -819,14 +812,14 @@ object ChatController {
|
||||
|
||||
|
||||
|
||||
suspend fun apiAddContact(): String? {
|
||||
suspend fun apiAddContact(incognito: Boolean): Pair<String, PendingContactConnection>? {
|
||||
val userId = chatModel.currentUser.value?.userId ?: run {
|
||||
Log.e(TAG, "apiAddContact: no current user")
|
||||
return null
|
||||
}
|
||||
val r = sendCmd(CC.APIAddContact(userId))
|
||||
val r = sendCmd(CC.APIAddContact(userId, incognito))
|
||||
return when (r) {
|
||||
is CR.Invitation -> r.connReqInvitation
|
||||
is CR.Invitation -> r.connReqInvitation to r.connection
|
||||
else -> {
|
||||
if (!(networkErrorAlert(r))) {
|
||||
apiErrorAlert("apiAddContact", generalGetString(MR.strings.connection_error), r)
|
||||
@@ -836,12 +829,19 @@ object ChatController {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun apiConnect(connReq: String): Boolean {
|
||||
suspend fun apiSetConnectionIncognito(connId: Long, incognito: Boolean): PendingContactConnection? {
|
||||
val r = sendCmd(CC.ApiSetConnectionIncognito(connId, incognito))
|
||||
if (r is CR.ConnectionIncognitoUpdated) return r.toConnection
|
||||
Log.e(TAG, "apiSetConnectionIncognito bad response: ${r.responseType} ${r.details}")
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiConnect(incognito: Boolean, connReq: String): Boolean {
|
||||
val userId = chatModel.currentUser.value?.userId ?: run {
|
||||
Log.e(TAG, "apiConnect: no current user")
|
||||
return false
|
||||
}
|
||||
val r = sendCmd(CC.APIConnect(userId, connReq))
|
||||
val r = sendCmd(CC.APIConnect(userId, incognito, connReq))
|
||||
when {
|
||||
r is CR.SentConfirmation || r is CR.SentInvitation -> return true
|
||||
r is CR.ContactAlreadyExists -> {
|
||||
@@ -998,8 +998,8 @@ object ChatController {
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiAcceptContactRequest(contactReqId: Long): Contact? {
|
||||
val r = sendCmd(CC.ApiAcceptContact(contactReqId))
|
||||
suspend fun apiAcceptContactRequest(incognito: Boolean, contactReqId: Long): Contact? {
|
||||
val r = sendCmd(CC.ApiAcceptContact(incognito, contactReqId))
|
||||
return when {
|
||||
r is CR.AcceptingContactRequest -> r.contact
|
||||
r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorAgent
|
||||
@@ -1805,7 +1805,6 @@ sealed class CC {
|
||||
class SetTempFolder(val tempFolder: String): CC()
|
||||
class SetFilesFolder(val filesFolder: String): CC()
|
||||
class ApiSetXFTPConfig(val config: XFTPFileConfig?): CC()
|
||||
class SetIncognito(val incognito: Boolean): CC()
|
||||
class ApiExportArchive(val config: ArchiveConfig): CC()
|
||||
class ApiImportArchive(val config: ArchiveConfig): CC()
|
||||
class ApiDeleteStorage: CC()
|
||||
@@ -1850,8 +1849,9 @@ sealed class CC {
|
||||
class APIGetGroupMemberCode(val groupId: Long, val groupMemberId: Long): CC()
|
||||
class APIVerifyContact(val contactId: Long, val connectionCode: String?): CC()
|
||||
class APIVerifyGroupMember(val groupId: Long, val groupMemberId: Long, val connectionCode: String?): CC()
|
||||
class APIAddContact(val userId: Long): CC()
|
||||
class APIConnect(val userId: Long, val connReq: String): CC()
|
||||
class APIAddContact(val userId: Long, val incognito: Boolean): CC()
|
||||
class ApiSetConnectionIncognito(val connId: Long, val incognito: Boolean): CC()
|
||||
class APIConnect(val userId: Long, val incognito: Boolean, val connReq: String): CC()
|
||||
class ApiDeleteChat(val type: ChatType, val id: Long): CC()
|
||||
class ApiClearChat(val type: ChatType, val id: Long): CC()
|
||||
class ApiListContacts(val userId: Long): CC()
|
||||
@@ -1872,7 +1872,7 @@ sealed class CC {
|
||||
class ApiSendCallExtraInfo(val contact: Contact, val extraInfo: WebRTCExtraInfo): CC()
|
||||
class ApiEndCall(val contact: Contact): CC()
|
||||
class ApiCallStatus(val contact: Contact, val callStatus: WebRTCCallStatus): CC()
|
||||
class ApiAcceptContact(val contactReqId: Long): CC()
|
||||
class ApiAcceptContact(val incognito: Boolean, val contactReqId: Long): CC()
|
||||
class ApiRejectContact(val contactReqId: Long): CC()
|
||||
class ApiChatRead(val type: ChatType, val id: Long, val range: ItemRange): CC()
|
||||
class ApiChatUnread(val type: ChatType, val id: Long, val unreadChat: Boolean): CC()
|
||||
@@ -1908,7 +1908,6 @@ sealed class CC {
|
||||
is SetTempFolder -> "/_temp_folder $tempFolder"
|
||||
is SetFilesFolder -> "/_files_folder $filesFolder"
|
||||
is ApiSetXFTPConfig -> if (config != null) "/_xftp on ${json.encodeToString(config)}" else "/_xftp off"
|
||||
is SetIncognito -> "/incognito ${onOff(incognito)}"
|
||||
is ApiExportArchive -> "/_db export ${json.encodeToString(config)}"
|
||||
is ApiImportArchive -> "/_db import ${json.encodeToString(config)}"
|
||||
is ApiDeleteStorage -> "/_db delete"
|
||||
@@ -1956,8 +1955,9 @@ sealed class CC {
|
||||
is APIGetGroupMemberCode -> "/_get code #$groupId $groupMemberId"
|
||||
is APIVerifyContact -> "/_verify code @$contactId" + if (connectionCode != null) " $connectionCode" else ""
|
||||
is APIVerifyGroupMember -> "/_verify code #$groupId $groupMemberId" + if (connectionCode != null) " $connectionCode" else ""
|
||||
is APIAddContact -> "/_connect $userId"
|
||||
is APIConnect -> "/_connect $userId $connReq"
|
||||
is APIAddContact -> "/_connect $userId incognito=${onOff(incognito)}"
|
||||
is ApiSetConnectionIncognito -> "/_set incognito :$connId ${onOff(incognito)}"
|
||||
is APIConnect -> "/_connect $userId incognito=${onOff(incognito)} $connReq"
|
||||
is ApiDeleteChat -> "/_delete ${chatRef(type, id)}"
|
||||
is ApiClearChat -> "/_clear chat ${chatRef(type, id)}"
|
||||
is ApiListContacts -> "/_contacts $userId"
|
||||
@@ -1971,7 +1971,7 @@ sealed class CC {
|
||||
is ApiShowMyAddress -> "/_show_address $userId"
|
||||
is ApiSetProfileAddress -> "/_profile_address $userId ${onOff(on)}"
|
||||
is ApiAddressAutoAccept -> "/_auto_accept $userId ${AutoAccept.cmdString(autoAccept)}"
|
||||
is ApiAcceptContact -> "/_accept $contactReqId"
|
||||
is ApiAcceptContact -> "/_accept incognito=${onOff(incognito)} $contactReqId"
|
||||
is ApiRejectContact -> "/_reject $contactReqId"
|
||||
is ApiSendCallInvitation -> "/_call invite @${contact.apiId} ${json.encodeToString(callType)}"
|
||||
is ApiRejectCall -> "/_call reject @${contact.apiId}"
|
||||
@@ -2006,7 +2006,6 @@ sealed class CC {
|
||||
is SetTempFolder -> "setTempFolder"
|
||||
is SetFilesFolder -> "setFilesFolder"
|
||||
is ApiSetXFTPConfig -> "apiSetXFTPConfig"
|
||||
is SetIncognito -> "setIncognito"
|
||||
is ApiExportArchive -> "apiExportArchive"
|
||||
is ApiImportArchive -> "apiImportArchive"
|
||||
is ApiDeleteStorage -> "apiDeleteStorage"
|
||||
@@ -2052,6 +2051,7 @@ sealed class CC {
|
||||
is APIVerifyContact -> "apiVerifyContact"
|
||||
is APIVerifyGroupMember -> "apiVerifyGroupMember"
|
||||
is APIAddContact -> "apiAddContact"
|
||||
is ApiSetConnectionIncognito -> "apiSetConnectionIncognito"
|
||||
is APIConnect -> "apiConnect"
|
||||
is ApiDeleteChat -> "apiDeleteChat"
|
||||
is ApiClearChat -> "apiClearChat"
|
||||
@@ -3249,7 +3249,8 @@ sealed class CR {
|
||||
@Serializable @SerialName("contactCode") class ContactCode(val user: User, val contact: Contact, val connectionCode: String): CR()
|
||||
@Serializable @SerialName("groupMemberCode") class GroupMemberCode(val user: User, val groupInfo: GroupInfo, val member: GroupMember, val connectionCode: String): CR()
|
||||
@Serializable @SerialName("connectionVerified") class ConnectionVerified(val user: User, val verified: Boolean, val expectedCode: String): CR()
|
||||
@Serializable @SerialName("invitation") class Invitation(val user: User, val connReqInvitation: String): CR()
|
||||
@Serializable @SerialName("invitation") class Invitation(val user: User, val connReqInvitation: String, val connection: PendingContactConnection): CR()
|
||||
@Serializable @SerialName("connectionIncognitoUpdated") class ConnectionIncognitoUpdated(val user: User, val toConnection: PendingContactConnection): CR()
|
||||
@Serializable @SerialName("sentConfirmation") class SentConfirmation(val user: User): CR()
|
||||
@Serializable @SerialName("sentInvitation") class SentInvitation(val user: User): CR()
|
||||
@Serializable @SerialName("contactAlreadyExists") class ContactAlreadyExists(val user: User, val contact: Contact): CR()
|
||||
@@ -3378,6 +3379,7 @@ sealed class CR {
|
||||
is GroupMemberCode -> "groupMemberCode"
|
||||
is ConnectionVerified -> "connectionVerified"
|
||||
is Invitation -> "invitation"
|
||||
is ConnectionIncognitoUpdated -> "connectionIncognitoUpdated"
|
||||
is SentConfirmation -> "sentConfirmation"
|
||||
is SentInvitation -> "sentInvitation"
|
||||
is ContactAlreadyExists -> "contactAlreadyExists"
|
||||
@@ -3503,6 +3505,7 @@ sealed class CR {
|
||||
is GroupMemberCode -> withUser(user, "groupInfo: ${json.encodeToString(groupInfo)}\nmember: ${json.encodeToString(member)}\nconnectionCode: $connectionCode")
|
||||
is ConnectionVerified -> withUser(user, "verified: $verified\nconnectionCode: $expectedCode")
|
||||
is Invitation -> withUser(user, connReqInvitation)
|
||||
is ConnectionIncognitoUpdated -> withUser(user, json.encodeToString(toConnection))
|
||||
is SentConfirmation -> withUser(user, noDetails())
|
||||
is SentInvitation -> withUser(user, noDetails())
|
||||
is ContactAlreadyExists -> withUser(user, json.encodeToString(contact))
|
||||
@@ -3822,6 +3825,7 @@ sealed class ChatErrorType {
|
||||
is ServerProtocol -> "serverProtocol"
|
||||
is AgentCommandError -> "agentCommandError"
|
||||
is InvalidFileDescription -> "invalidFileDescription"
|
||||
is ConnectionIncognitoChangeProhibited -> "connectionIncognitoChangeProhibited"
|
||||
is InternalError -> "internalError"
|
||||
is CEException -> "exception $message"
|
||||
}
|
||||
@@ -3895,6 +3899,7 @@ sealed class ChatErrorType {
|
||||
@Serializable @SerialName("serverProtocol") object ServerProtocol: ChatErrorType()
|
||||
@Serializable @SerialName("agentCommandError") class AgentCommandError(val message: String): ChatErrorType()
|
||||
@Serializable @SerialName("invalidFileDescription") class InvalidFileDescription(val message: String): ChatErrorType()
|
||||
@Serializable @SerialName("connectionIncognitoChangeProhibited") object ConnectionIncognitoChangeProhibited: ChatErrorType()
|
||||
@Serializable @SerialName("internalError") class InternalError(val message: String): ChatErrorType()
|
||||
@Serializable @SerialName("exception") class CEException(val message: String): ChatErrorType()
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ import chat.simplex.res.MR
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
enum class NotificationAction {
|
||||
ACCEPT_CONTACT_REQUEST
|
||||
ACCEPT_CONTACT_REQUEST,
|
||||
ACCEPT_CONTACT_REQUEST_INCOGNITO
|
||||
}
|
||||
|
||||
lateinit var ntfManager: NtfManager
|
||||
@@ -29,7 +30,10 @@ abstract class NtfManager {
|
||||
displayName = cInfo.displayName,
|
||||
msgText = generalGetString(MR.strings.notification_new_contact_request),
|
||||
image = cInfo.image,
|
||||
listOf(NotificationAction.ACCEPT_CONTACT_REQUEST to { acceptContactRequestAction(user.userId, cInfo.id) })
|
||||
listOf(
|
||||
NotificationAction.ACCEPT_CONTACT_REQUEST to { acceptContactRequestAction(user.userId, incognito = false, cInfo.id) },
|
||||
NotificationAction.ACCEPT_CONTACT_REQUEST_INCOGNITO to { acceptContactRequestAction(user.userId, incognito = true, cInfo.id) }
|
||||
)
|
||||
)
|
||||
|
||||
fun notifyMessageReceived(user: User, cInfo: ChatInfo, cItem: ChatItem) {
|
||||
@@ -37,7 +41,7 @@ abstract class NtfManager {
|
||||
displayNotification(user = user, chatId = cInfo.id, displayName = cInfo.displayName, msgText = hideSecrets(cItem))
|
||||
}
|
||||
|
||||
fun acceptContactRequestAction(userId: Long?, chatId: ChatId) {
|
||||
fun acceptContactRequestAction(userId: Long?, incognito: Boolean, chatId: ChatId) {
|
||||
val isCurrentUser = ChatModel.currentUser.value?.userId == userId
|
||||
val cInfo: ChatInfo.ContactRequest? = if (isCurrentUser) {
|
||||
(ChatModel.getChat(chatId)?.chatInfo as? ChatInfo.ContactRequest) ?: return
|
||||
@@ -45,7 +49,7 @@ abstract class NtfManager {
|
||||
null
|
||||
}
|
||||
val apiId = chatId.replace("<@", "").toLongOrNull() ?: return
|
||||
acceptContactRequest(apiId, cInfo, isCurrentUser, ChatModel)
|
||||
acceptContactRequest(incognito, apiId, cInfo, isCurrentUser, ChatModel)
|
||||
cancelNotificationsForChat(chatId)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import InfoRowEllipsis
|
||||
import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionItemView
|
||||
import SectionItemViewSpaceBetween
|
||||
import SectionSpacer
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
@@ -271,7 +272,10 @@ fun ChatInfoLayout(
|
||||
SectionSpacer()
|
||||
if (customUserProfile != null) {
|
||||
SectionView(generalGetString(MR.strings.incognito).uppercase()) {
|
||||
InfoRow(generalGetString(MR.strings.incognito_random_profile), customUserProfile.chatViewName)
|
||||
SectionItemViewSpaceBetween {
|
||||
Text(generalGetString(MR.strings.incognito_random_profile))
|
||||
Text(customUserProfile.chatViewName, color = Indigo)
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
|
||||
@@ -127,7 +127,6 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: () -> Unit) {
|
||||
searchText,
|
||||
useLinkPreviews = useLinkPreviews,
|
||||
linkMode = chatModel.simplexLinkMode.value,
|
||||
chatModelIncognito = chatModel.incognito.value,
|
||||
back = {
|
||||
hideKeyboard(view)
|
||||
AudioPlayer.stop()
|
||||
@@ -379,7 +378,6 @@ fun ChatLayout(
|
||||
searchValue: State<String>,
|
||||
useLinkPreviews: Boolean,
|
||||
linkMode: SimplexLinkMode,
|
||||
chatModelIncognito: Boolean,
|
||||
back: () -> Unit,
|
||||
info: () -> Unit,
|
||||
showMemberInfo: (GroupInfo, GroupMember) -> Unit,
|
||||
@@ -465,7 +463,7 @@ fun ChatLayout(
|
||||
) {
|
||||
ChatItemsList(
|
||||
chat, unreadCount, composeState, chatItems, searchValue,
|
||||
useLinkPreviews, linkMode, chatModelIncognito, showMemberInfo, loadPrevMessages, deleteMessage,
|
||||
useLinkPreviews, linkMode, showMemberInfo, loadPrevMessages, deleteMessage,
|
||||
receiveFile, cancelFile, joinGroup, acceptCall, acceptFeature,
|
||||
updateContactStats, updateMemberStats, syncContactConnection, syncMemberConnection, findModelChat, findModelMember,
|
||||
setReaction, showItemDetails, markRead, setFloatingButton, onComposed,
|
||||
@@ -634,7 +632,6 @@ fun BoxWithConstraintsScope.ChatItemsList(
|
||||
searchValue: State<String>,
|
||||
useLinkPreviews: Boolean,
|
||||
linkMode: SimplexLinkMode,
|
||||
chatModelIncognito: Boolean,
|
||||
showMemberInfo: (GroupInfo, GroupMember) -> Unit,
|
||||
loadPrevMessages: (ChatInfo) -> Unit,
|
||||
deleteMessage: (Long, CIDeleteMode) -> Unit,
|
||||
@@ -1184,7 +1181,6 @@ fun PreviewChatLayout() {
|
||||
searchValue,
|
||||
useLinkPreviews = true,
|
||||
linkMode = SimplexLinkMode.DESCRIPTION,
|
||||
chatModelIncognito = false,
|
||||
back = {},
|
||||
info = {},
|
||||
showMemberInfo = { _, _ -> },
|
||||
@@ -1252,7 +1248,6 @@ fun PreviewGroupChatLayout() {
|
||||
searchValue,
|
||||
useLinkPreviews = true,
|
||||
linkMode = SimplexLinkMode.DESCRIPTION,
|
||||
chatModelIncognito = false,
|
||||
back = {},
|
||||
info = {},
|
||||
showMemberInfo = { _, _ -> },
|
||||
|
||||
@@ -20,17 +20,16 @@ import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.chat.ChatInfoToolbarTitle
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.views.newchat.InfoAboutIncognito
|
||||
import chat.simplex.common.views.usersettings.SettingsActionItem
|
||||
import chat.simplex.common.model.GroupInfo
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.views.chat.group.GroupPreferencesView
|
||||
import chat.simplex.res.MR
|
||||
|
||||
@Composable
|
||||
@@ -41,7 +40,6 @@ fun AddGroupMembersView(groupInfo: GroupInfo, creatingGroup: Boolean = false, ch
|
||||
val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) }
|
||||
BackHandler(onBack = close)
|
||||
AddGroupMembersLayout(
|
||||
chatModel.incognito.value,
|
||||
groupInfo = groupInfo,
|
||||
creatingGroup = creatingGroup,
|
||||
contactsToAdd = getContactsToAdd(chatModel, searchText.value.text),
|
||||
@@ -92,7 +90,6 @@ fun getContactsToAdd(chatModel: ChatModel, search: String): List<Contact> {
|
||||
|
||||
@Composable
|
||||
fun AddGroupMembersLayout(
|
||||
chatModelIncognito: Boolean,
|
||||
groupInfo: GroupInfo,
|
||||
creatingGroup: Boolean,
|
||||
contactsToAdd: List<Contact>,
|
||||
@@ -107,19 +104,31 @@ fun AddGroupMembersLayout(
|
||||
removeContact: (Long) -> Unit,
|
||||
close: () -> Unit,
|
||||
) {
|
||||
@Composable fun profileText() {
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
Icon(
|
||||
painterResource(MR.images.ic_info),
|
||||
null,
|
||||
tint = MaterialTheme.colors.secondary,
|
||||
modifier = Modifier.padding(end = 10.dp).size(20.dp)
|
||||
)
|
||||
Text(generalGetString(MR.strings.group_main_profile_sent), textAlign = TextAlign.Center, style = MaterialTheme.typography.body2)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
AppBarTitle(stringResource(MR.strings.button_add_members))
|
||||
InfoAboutIncognito(
|
||||
chatModelIncognito,
|
||||
false,
|
||||
generalGetString(MR.strings.group_unsupported_incognito_main_profile_sent),
|
||||
generalGetString(MR.strings.group_main_profile_sent),
|
||||
true
|
||||
)
|
||||
profileText()
|
||||
Spacer(Modifier.size(DEFAULT_PADDING))
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
@@ -350,7 +359,6 @@ fun showProhibitedToInviteIncognitoAlertDialog() {
|
||||
fun PreviewAddGroupMembersLayout() {
|
||||
SimpleXTheme {
|
||||
AddGroupMembersLayout(
|
||||
chatModelIncognito = false,
|
||||
groupInfo = GroupInfo.sampleData,
|
||||
creatingGroup = false,
|
||||
contactsToAdd = listOf(Contact.sampleData, Contact.sampleData, Contact.sampleData),
|
||||
|
||||
@@ -3,6 +3,7 @@ package chat.simplex.common.views.chat.group
|
||||
import InfoRow
|
||||
import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionItemView
|
||||
import SectionSpacer
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
@@ -445,19 +446,42 @@ private fun updateMemberRoleDialog(
|
||||
}
|
||||
|
||||
fun connectViaMemberAddressAlert(connReqUri: String) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
AlertManager.shared.showAlertDialogButtonsColumn(
|
||||
title = generalGetString(MR.strings.connect_via_member_address_alert_title),
|
||||
text = generalGetString(MR.strings.connect_via_member_address_alert_desc),
|
||||
confirmText = generalGetString(MR.strings.connect_via_link_verb),
|
||||
onConfirm = {
|
||||
val uri = URI(connReqUri)
|
||||
withUriAction(uri) { linkType ->
|
||||
withApi {
|
||||
Log.d(TAG, "connectViaUri: connecting")
|
||||
connectViaUri(chatModel, linkType, uri)
|
||||
text = AnnotatedString(generalGetString(MR.strings.connect_via_member_address_alert_desc)),
|
||||
buttons = {
|
||||
Column {
|
||||
SectionItemView({
|
||||
AlertManager.shared.hideAlert()
|
||||
val uri = URI(connReqUri)
|
||||
withUriAction(uri) { linkType ->
|
||||
withApi {
|
||||
Log.d(TAG, "connectViaUri: connecting")
|
||||
connectViaUri(chatModel, linkType, uri, incognito = false)
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Text(generalGetString(MR.strings.connect_use_current_profile), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
|
||||
}
|
||||
SectionItemView({
|
||||
AlertManager.shared.hideAlert()
|
||||
val uri = URI(connReqUri)
|
||||
withUriAction(uri) { linkType ->
|
||||
withApi {
|
||||
Log.d(TAG, "connectViaUri: connecting incognito")
|
||||
connectViaUri(chatModel, linkType, uri, incognito = true)
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Text(generalGetString(MR.strings.connect_use_new_incognito_profile), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
|
||||
}
|
||||
SectionItemView({
|
||||
AlertManager.shared.hideAlert()
|
||||
}) {
|
||||
Text(stringResource(MR.strings.cancel_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package chat.simplex.common.views.chatlist
|
||||
|
||||
import SectionItemView
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
@@ -13,9 +14,12 @@ import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.chat.*
|
||||
import chat.simplex.common.views.chat.group.deleteGroupDialog
|
||||
@@ -23,9 +27,7 @@ import chat.simplex.common.views.chat.group.leaveGroupDialog
|
||||
import chat.simplex.common.views.chat.item.InvalidJSONView
|
||||
import chat.simplex.common.views.chat.item.ItemAction
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.views.newchat.ContactConnectionInfoView
|
||||
import chat.simplex.common.platform.appPlatform
|
||||
import chat.simplex.common.platform.ntfManager
|
||||
import chat.simplex.common.views.newchat.*
|
||||
import chat.simplex.res.MR
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.datetime.Clock
|
||||
@@ -46,7 +48,7 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) {
|
||||
is ChatInfo.Direct -> {
|
||||
val contactNetworkStatus = chatModel.contactNetworkStatus(chat.chatInfo.contact)
|
||||
ChatListNavLinkLayout(
|
||||
chatLinkPreview = { ChatPreviewView(chat, chatModel.draft.value, chatModel.draftChatId.value, chatModel.incognito.value, chatModel.currentUser.value?.profile?.displayName, contactNetworkStatus, stopped, linkMode) },
|
||||
chatLinkPreview = { ChatPreviewView(chat, chatModel.draft.value, chatModel.draftChatId.value, chatModel.currentUser.value?.profile?.displayName, contactNetworkStatus, stopped, linkMode) },
|
||||
click = { directChatAction(chat.chatInfo, chatModel) },
|
||||
dropdownMenuItems = { ContactMenuItems(chat, chatModel, showMenu, showMarkRead) },
|
||||
showMenu,
|
||||
@@ -55,7 +57,7 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) {
|
||||
}
|
||||
is ChatInfo.Group ->
|
||||
ChatListNavLinkLayout(
|
||||
chatLinkPreview = { ChatPreviewView(chat, chatModel.draft.value, chatModel.draftChatId.value, chatModel.incognito.value, chatModel.currentUser.value?.profile?.displayName, null, stopped, linkMode) },
|
||||
chatLinkPreview = { ChatPreviewView(chat, chatModel.draft.value, chatModel.draftChatId.value, chatModel.currentUser.value?.profile?.displayName, null, stopped, linkMode) },
|
||||
click = { groupChatAction(chat.chatInfo.groupInfo, chatModel) },
|
||||
dropdownMenuItems = { GroupMenuItems(chat, chat.chatInfo.groupInfo, chatModel, showMenu, showMarkRead) },
|
||||
showMenu,
|
||||
@@ -63,7 +65,7 @@ fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) {
|
||||
)
|
||||
is ChatInfo.ContactRequest ->
|
||||
ChatListNavLinkLayout(
|
||||
chatLinkPreview = { ContactRequestView(chatModel.incognito.value, chat.chatInfo) },
|
||||
chatLinkPreview = { ContactRequestView(chat.chatInfo) },
|
||||
click = { contactRequestAlertDialog(chat.chatInfo, chatModel) },
|
||||
dropdownMenuItems = { ContactRequestMenuItems(chat.chatInfo, chatModel, showMenu) },
|
||||
showMenu,
|
||||
@@ -320,11 +322,20 @@ fun LeaveGroupAction(groupInfo: GroupInfo, chatModel: ChatModel, showMenu: Mutab
|
||||
@Composable
|
||||
fun ContactRequestMenuItems(chatInfo: ChatInfo.ContactRequest, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
|
||||
ItemAction(
|
||||
if (chatModel.incognito.value) stringResource(MR.strings.accept_contact_incognito_button) else stringResource(MR.strings.accept_contact_button),
|
||||
if (chatModel.incognito.value) painterResource(MR.images.ic_theater_comedy_filled) else painterResource(MR.images.ic_check),
|
||||
color = if (chatModel.incognito.value) Indigo else MaterialTheme.colors.onBackground,
|
||||
stringResource(MR.strings.accept_contact_button),
|
||||
painterResource(MR.images.ic_check),
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
onClick = {
|
||||
acceptContactRequest(chatInfo.apiId, chatInfo, true, chatModel)
|
||||
acceptContactRequest(incognito = false, chatInfo.apiId, chatInfo, true, chatModel)
|
||||
showMenu.value = false
|
||||
}
|
||||
)
|
||||
ItemAction(
|
||||
stringResource(MR.strings.accept_contact_incognito_button),
|
||||
painterResource(MR.images.ic_theater_comedy),
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
onClick = {
|
||||
acceptContactRequest(incognito = true, chatInfo.apiId, chatInfo, true, chatModel)
|
||||
showMenu.value = false
|
||||
}
|
||||
)
|
||||
@@ -430,19 +441,37 @@ fun markChatUnread(chat: Chat, chatModel: ChatModel) {
|
||||
}
|
||||
|
||||
fun contactRequestAlertDialog(contactRequest: ChatInfo.ContactRequest, chatModel: ChatModel) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
AlertManager.shared.showAlertDialogButtonsColumn(
|
||||
title = generalGetString(MR.strings.accept_connection_request__question),
|
||||
text = generalGetString(MR.strings.if_you_choose_to_reject_the_sender_will_not_be_notified),
|
||||
confirmText = if (chatModel.incognito.value) generalGetString(MR.strings.accept_contact_incognito_button) else generalGetString(MR.strings.accept_contact_button),
|
||||
onConfirm = { acceptContactRequest(contactRequest.apiId, contactRequest, true, chatModel) },
|
||||
dismissText = generalGetString(MR.strings.reject_contact_button),
|
||||
onDismiss = { rejectContactRequest(contactRequest, chatModel) }
|
||||
text = AnnotatedString(generalGetString(MR.strings.if_you_choose_to_reject_the_sender_will_not_be_notified)),
|
||||
buttons = {
|
||||
Column {
|
||||
SectionItemView({
|
||||
AlertManager.shared.hideAlert()
|
||||
acceptContactRequest(incognito = false, contactRequest.apiId, contactRequest, true, chatModel)
|
||||
}) {
|
||||
Text(generalGetString(MR.strings.accept_contact_button), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
|
||||
}
|
||||
SectionItemView({
|
||||
AlertManager.shared.hideAlert()
|
||||
acceptContactRequest(incognito = true, contactRequest.apiId, contactRequest, true, chatModel)
|
||||
}) {
|
||||
Text(generalGetString(MR.strings.accept_contact_incognito_button), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
|
||||
}
|
||||
SectionItemView({
|
||||
AlertManager.shared.hideAlert()
|
||||
rejectContactRequest(contactRequest, chatModel)
|
||||
}) {
|
||||
Text(generalGetString(MR.strings.reject_contact_button), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = Color.Red)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun acceptContactRequest(apiId: Long, contactRequest: ChatInfo.ContactRequest?, isCurrentUser: Boolean, chatModel: ChatModel) {
|
||||
fun acceptContactRequest(incognito: Boolean, apiId: Long, contactRequest: ChatInfo.ContactRequest?, isCurrentUser: Boolean, chatModel: ChatModel) {
|
||||
withApi {
|
||||
val contact = chatModel.controller.apiAcceptContactRequest(apiId)
|
||||
val contact = chatModel.controller.apiAcceptContactRequest(incognito, apiId)
|
||||
if (contact != null && isCurrentUser && contactRequest != null) {
|
||||
val chat = Chat(ChatInfo.Direct(contact), listOf())
|
||||
chatModel.replaceChat(contactRequest.id, chat)
|
||||
@@ -457,38 +486,6 @@ fun rejectContactRequest(contactRequest: ChatInfo.ContactRequest, chatModel: Cha
|
||||
}
|
||||
}
|
||||
|
||||
fun contactConnectionAlertDialog(connection: PendingContactConnection, chatModel: ChatModel) {
|
||||
AlertManager.shared.showAlertDialogButtons(
|
||||
title = generalGetString(
|
||||
if (connection.initiated) MR.strings.you_invited_your_contact
|
||||
else MR.strings.you_accepted_connection
|
||||
),
|
||||
text = generalGetString(
|
||||
if (connection.viaContactUri) MR.strings.you_will_be_connected_when_your_connection_request_is_accepted
|
||||
else MR.strings.you_will_be_connected_when_your_contacts_device_is_online
|
||||
),
|
||||
buttons = {
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 8.dp, vertical = 2.dp),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
TextButton(onClick = {
|
||||
AlertManager.shared.hideAlert()
|
||||
deleteContactConnectionAlert(connection, chatModel) {}
|
||||
}) {
|
||||
Text(stringResource(MR.strings.delete_verb))
|
||||
}
|
||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||
TextButton(onClick = { AlertManager.shared.hideAlert() }) {
|
||||
Text(stringResource(MR.strings.ok))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun deleteContactConnectionAlert(connection: PendingContactConnection, chatModel: ChatModel, onSuccess: () -> Unit) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.delete_pending_connection__question),
|
||||
@@ -662,7 +659,6 @@ fun PreviewChatListNavLinkDirect() {
|
||||
),
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
stopped = false,
|
||||
@@ -702,7 +698,6 @@ fun PreviewChatListNavLinkGroup() {
|
||||
),
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
stopped = false,
|
||||
@@ -727,7 +722,7 @@ fun PreviewChatListNavLinkContactRequest() {
|
||||
SimpleXTheme {
|
||||
ChatListNavLinkLayout(
|
||||
chatLinkPreview = {
|
||||
ContactRequestView(false, ChatInfo.ContactRequest.sampleData)
|
||||
ContactRequestView(ChatInfo.ContactRequest.sampleData)
|
||||
},
|
||||
click = {},
|
||||
dropdownMenuItems = null,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package chat.simplex.common.views.chatlist
|
||||
|
||||
import SectionItemView
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.*
|
||||
@@ -13,9 +14,11 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.*
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.*
|
||||
import chat.simplex.common.SettingsViewState
|
||||
import chat.simplex.common.model.*
|
||||
@@ -221,14 +224,6 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user
|
||||
},
|
||||
title = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
if (chatModel.incognito.value) {
|
||||
Icon(
|
||||
painterResource(MR.images.ic_theater_comedy_filled),
|
||||
stringResource(MR.strings.incognito),
|
||||
tint = Indigo,
|
||||
modifier = Modifier.padding(10.dp).size(26.dp)
|
||||
)
|
||||
}
|
||||
Text(
|
||||
stringResource(MR.strings.your_chats),
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
@@ -317,17 +312,37 @@ fun connectIfOpenedViaUri(uri: URI, chatModel: ChatModel) {
|
||||
ConnectionLinkType.INVITATION -> generalGetString(MR.strings.connect_via_invitation_link)
|
||||
ConnectionLinkType.GROUP -> generalGetString(MR.strings.connect_via_group_link)
|
||||
}
|
||||
AlertManager.shared.showAlertDialog(
|
||||
AlertManager.shared.showAlertDialogButtonsColumn(
|
||||
title = title,
|
||||
text = if (linkType == ConnectionLinkType.GROUP)
|
||||
generalGetString(MR.strings.you_will_join_group)
|
||||
AnnotatedString(generalGetString(MR.strings.you_will_join_group))
|
||||
else
|
||||
generalGetString(MR.strings.profile_will_be_sent_to_contact_sending_link),
|
||||
confirmText = generalGetString(MR.strings.connect_via_link_verb),
|
||||
onConfirm = {
|
||||
withApi {
|
||||
Log.d(TAG, "connectIfOpenedViaUri: connecting")
|
||||
connectViaUri(chatModel, linkType, uri)
|
||||
AnnotatedString(generalGetString(MR.strings.profile_will_be_sent_to_contact_sending_link)),
|
||||
buttons = {
|
||||
Column {
|
||||
SectionItemView({
|
||||
AlertManager.shared.hideAlert()
|
||||
withApi {
|
||||
Log.d(TAG, "connectIfOpenedViaUri: connecting")
|
||||
connectViaUri(chatModel, linkType, uri, incognito = false)
|
||||
}
|
||||
}) {
|
||||
Text(generalGetString(MR.strings.connect_use_current_profile), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
|
||||
}
|
||||
SectionItemView({
|
||||
AlertManager.shared.hideAlert()
|
||||
withApi {
|
||||
Log.d(TAG, "connectIfOpenedViaUri: connecting incognito")
|
||||
connectViaUri(chatModel, linkType, uri, incognito = true)
|
||||
}
|
||||
}) {
|
||||
Text(generalGetString(MR.strings.connect_use_new_incognito_profile), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
|
||||
}
|
||||
SectionItemView({
|
||||
AlertManager.shared.hideAlert()
|
||||
}) {
|
||||
Text(stringResource(MR.strings.cancel_verb), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -33,7 +33,6 @@ fun ChatPreviewView(
|
||||
chat: Chat,
|
||||
chatModelDraft: ComposeState?,
|
||||
chatModelDraftChatId: ChatId?,
|
||||
chatModelIncognito: Boolean,
|
||||
currentUserProfileDisplayName: String?,
|
||||
contactNetworkStatus: NetworkStatus?,
|
||||
stopped: Boolean,
|
||||
@@ -138,7 +137,7 @@ fun ChatPreviewView(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun chatPreviewText(chatModelIncognito: Boolean) {
|
||||
fun chatPreviewText() {
|
||||
val ci = chat.chatItems.lastOrNull()
|
||||
if (ci != null) {
|
||||
val (text: CharSequence, inlineTextContent) = when {
|
||||
@@ -175,7 +174,7 @@ fun ChatPreviewView(
|
||||
}
|
||||
is ChatInfo.Group ->
|
||||
when (cInfo.groupInfo.membership.memberStatus) {
|
||||
GroupMemberStatus.MemInvited -> Text(groupInvitationPreviewText(chatModelIncognito, currentUserProfileDisplayName, cInfo.groupInfo))
|
||||
GroupMemberStatus.MemInvited -> Text(groupInvitationPreviewText(currentUserProfileDisplayName, cInfo.groupInfo))
|
||||
GroupMemberStatus.MemAccepted -> Text(stringResource(MR.strings.group_connection_pending), color = MaterialTheme.colors.secondary)
|
||||
else -> {}
|
||||
}
|
||||
@@ -184,6 +183,37 @@ fun ChatPreviewView(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun chatStatusImage() {
|
||||
if (cInfo is ChatInfo.Direct) {
|
||||
val descr = contactNetworkStatus?.statusString
|
||||
when (contactNetworkStatus) {
|
||||
is NetworkStatus.Connected ->
|
||||
IncognitoIcon(chat.chatInfo.incognito)
|
||||
|
||||
is NetworkStatus.Error ->
|
||||
Icon(
|
||||
painterResource(MR.images.ic_error),
|
||||
contentDescription = descr,
|
||||
tint = MaterialTheme.colors.secondary,
|
||||
modifier = Modifier
|
||||
.size(19.dp)
|
||||
)
|
||||
|
||||
else ->
|
||||
CircularProgressIndicator(
|
||||
Modifier
|
||||
.padding(horizontal = 2.dp)
|
||||
.size(15.dp),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
strokeWidth = 1.5.dp
|
||||
)
|
||||
}
|
||||
} else {
|
||||
IncognitoIcon(chat.chatInfo.incognito)
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
Box(contentAlignment = Alignment.BottomEnd) {
|
||||
ChatInfoImage(cInfo, size = 72.dp)
|
||||
@@ -199,14 +229,14 @@ fun ChatPreviewView(
|
||||
chatPreviewTitle()
|
||||
val height = with(LocalDensity.current) { 46.sp.toDp() }
|
||||
Row(Modifier.heightIn(min = height)) {
|
||||
chatPreviewText(chatModelIncognito)
|
||||
chatPreviewText()
|
||||
}
|
||||
}
|
||||
val ts = chat.chatItems.lastOrNull()?.timestampText ?: getTimestampText(chat.chatInfo.updatedAt)
|
||||
|
||||
Box(
|
||||
contentAlignment = Alignment.TopEnd
|
||||
) {
|
||||
val ts = chat.chatItems.lastOrNull()?.timestampText ?: getTimestampText(chat.chatInfo.updatedAt)
|
||||
Text(
|
||||
ts,
|
||||
color = MaterialTheme.colors.secondary,
|
||||
@@ -262,24 +292,33 @@ fun ChatPreviewView(
|
||||
)
|
||||
}
|
||||
}
|
||||
if (cInfo is ChatInfo.Direct) {
|
||||
Box(
|
||||
Modifier.padding(top = 52.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
ChatStatusImage(contactNetworkStatus)
|
||||
}
|
||||
Box(
|
||||
Modifier.padding(top = 50.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
chatStatusImage()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun groupInvitationPreviewText(chatModelIncognito: Boolean, currentUserProfileDisplayName: String?, groupInfo: GroupInfo): String {
|
||||
fun IncognitoIcon(incognito: Boolean) {
|
||||
if (incognito) {
|
||||
Icon(
|
||||
painterResource(MR.images.ic_theater_comedy),
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colors.secondary,
|
||||
modifier = Modifier
|
||||
.size(21.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun groupInvitationPreviewText(currentUserProfileDisplayName: String?, groupInfo: GroupInfo): String {
|
||||
return if (groupInfo.membership.memberIncognito)
|
||||
String.format(stringResource(MR.strings.group_preview_join_as), groupInfo.membership.memberProfile.displayName)
|
||||
else if (chatModelIncognito)
|
||||
String.format(stringResource(MR.strings.group_preview_join_as), currentUserProfileDisplayName ?: "")
|
||||
else
|
||||
stringResource(MR.strings.group_preview_you_are_invited)
|
||||
}
|
||||
@@ -289,28 +328,6 @@ fun unreadCountStr(n: Int): String {
|
||||
return if (n < 1000) "$n" else "${n / 1000}" + stringResource(MR.strings.thousand_abbreviation)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChatStatusImage(s: NetworkStatus?) {
|
||||
val descr = s?.statusString
|
||||
if (s is NetworkStatus.Error) {
|
||||
Icon(
|
||||
painterResource(MR.images.ic_error),
|
||||
contentDescription = descr,
|
||||
tint = MaterialTheme.colors.secondary,
|
||||
modifier = Modifier
|
||||
.size(19.dp)
|
||||
)
|
||||
} else if (s !is NetworkStatus.Connected) {
|
||||
CircularProgressIndicator(
|
||||
Modifier
|
||||
.padding(horizontal = 2.dp)
|
||||
.size(15.dp),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
strokeWidth = 1.5.dp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview/*(
|
||||
uiMode = Configuration.UI_MODE_NIGHT_YES,
|
||||
showBackground = true,
|
||||
@@ -319,6 +336,6 @@ fun ChatStatusImage(s: NetworkStatus?) {
|
||||
@Composable
|
||||
fun PreviewChatPreviewView() {
|
||||
SimpleXTheme {
|
||||
ChatPreviewView(Chat.sampleData, null, null, false, "", contactNetworkStatus = NetworkStatus.Connected(), stopped = false, linkMode = SimplexLinkMode.DESCRIPTION)
|
||||
ChatPreviewView(Chat.sampleData, null, null, "", contactNetworkStatus = NetworkStatus.Connected(), stopped = false, linkMode = SimplexLinkMode.DESCRIPTION)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,16 +39,22 @@ fun ContactConnectionView(contactConnection: PendingContactConnection) {
|
||||
val height = with(LocalDensity.current) { 46.sp.toDp() }
|
||||
Text(contactConnection.description, Modifier.heightIn(min = height), maxLines = 2, color = if (isInDarkTheme()) MessagePreviewDark else MessagePreviewLight)
|
||||
}
|
||||
val ts = getTimestampText(contactConnection.updatedAt)
|
||||
Column(
|
||||
Modifier.fillMaxHeight(),
|
||||
Box(
|
||||
contentAlignment = Alignment.TopEnd
|
||||
) {
|
||||
val ts = getTimestampText(contactConnection.updatedAt)
|
||||
Text(
|
||||
ts,
|
||||
color = MaterialTheme.colors.secondary,
|
||||
style = MaterialTheme.typography.body2,
|
||||
modifier = Modifier.padding(bottom = 5.dp)
|
||||
)
|
||||
Box(
|
||||
Modifier.padding(top = 50.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
IncognitoIcon(contactConnection.incognito)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import chat.simplex.common.model.getTimestampText
|
||||
import chat.simplex.res.MR
|
||||
|
||||
@Composable
|
||||
fun ContactRequestView(chatModelIncognito: Boolean, contactRequest: ChatInfo.ContactRequest) {
|
||||
fun ContactRequestView(contactRequest: ChatInfo.ContactRequest) {
|
||||
Row {
|
||||
ChatInfoImage(contactRequest, size = 72.dp)
|
||||
Column(
|
||||
@@ -32,7 +32,7 @@ fun ContactRequestView(chatModelIncognito: Boolean, contactRequest: ChatInfo.Con
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = MaterialTheme.typography.h3,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = if (chatModelIncognito) Indigo else MaterialTheme.colors.primary
|
||||
color = MaterialTheme.colors.primary
|
||||
)
|
||||
val height = with(LocalDensity.current) { 46.sp.toDp() }
|
||||
Text(stringResource(MR.strings.contact_wants_to_connect_with_you), Modifier.heightIn(min = height), maxLines = 2, color = if (isInDarkTheme()) MessagePreviewDark else MessagePreviewLight)
|
||||
|
||||
@@ -121,14 +121,6 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
)
|
||||
if (chatModel.incognito.value) {
|
||||
Icon(
|
||||
painterResource(MR.images.ic_theater_comedy_filled),
|
||||
stringResource(MR.strings.incognito),
|
||||
tint = Indigo,
|
||||
modifier = Modifier.padding(10.dp).size(26.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
onTitleClick = null,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package chat.simplex.common.views.helpers
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.*
|
||||
@@ -48,19 +51,20 @@ fun TextEditor(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(contentPadding)
|
||||
.heightIn(min = 52.dp),
|
||||
// .border(border = BorderStroke(1.dp, strokeColor), shape = RoundedCornerShape(26.dp)),
|
||||
.heightIn(min = 52.dp)
|
||||
.border(border = BorderStroke(1.dp, strokeColor), shape = RoundedCornerShape(14.dp)),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
val modifier = modifier
|
||||
val textFieldModifier = modifier
|
||||
.fillMaxWidth()
|
||||
.navigationBarsWithImePadding()
|
||||
.onFocusChanged { focused = it.isFocused }
|
||||
.padding(10.dp)
|
||||
|
||||
BasicTextField(
|
||||
value = value.value,
|
||||
onValueChange = { value.value = it },
|
||||
modifier = if (focusRequester == null) modifier else modifier.focusRequester(focusRequester),
|
||||
modifier = if (focusRequester == null) textFieldModifier else textFieldModifier.focusRequester(focusRequester),
|
||||
textStyle = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onBackground, lineHeight = 22.sp),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
capitalization = KeyboardCapitalization.None,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package chat.simplex.common.views.newchat
|
||||
|
||||
import SectionBottomSpacer
|
||||
import SectionSpacer
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import androidx.compose.foundation.layout.*
|
||||
@@ -14,20 +14,26 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.platform.shareText
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.views.usersettings.SettingsActionItem
|
||||
import chat.simplex.common.views.usersettings.*
|
||||
import chat.simplex.res.MR
|
||||
|
||||
@Composable
|
||||
fun AddContactView(connReqInvitation: String, connIncognito: Boolean) {
|
||||
fun AddContactView(
|
||||
chatModel: ChatModel,
|
||||
connReqInvitation: String,
|
||||
contactConnection: MutableState<PendingContactConnection?>
|
||||
) {
|
||||
val clipboard = LocalClipboardManager.current
|
||||
AddContactLayout(
|
||||
chatModel = chatModel,
|
||||
incognitoPref = chatModel.controller.appPrefs.incognito,
|
||||
connReq = connReqInvitation,
|
||||
connIncognito = connIncognito,
|
||||
contactConnection = contactConnection,
|
||||
share = { clipboard.shareText(connReqInvitation) },
|
||||
learnMore = {
|
||||
ModalManager.center.showModal {
|
||||
@@ -45,57 +51,63 @@ fun AddContactView(connReqInvitation: String, connIncognito: Boolean) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AddContactLayout(connReq: String, connIncognito: Boolean, share: () -> Unit, learnMore: () -> Unit) {
|
||||
fun AddContactLayout(
|
||||
chatModel: ChatModel,
|
||||
incognitoPref: SharedPreference<Boolean>,
|
||||
connReq: String,
|
||||
contactConnection: MutableState<PendingContactConnection?>,
|
||||
share: () -> Unit,
|
||||
learnMore: () -> Unit
|
||||
) {
|
||||
val incognito = remember { mutableStateOf(incognitoPref.get()) }
|
||||
|
||||
LaunchedEffect(incognito.value) {
|
||||
withApi {
|
||||
val contactConnVal = contactConnection.value
|
||||
if (contactConnVal != null) {
|
||||
chatModel.controller.apiSetConnectionIncognito(contactConnVal.pccConnId, incognito.value)?.let {
|
||||
contactConnection.value = it
|
||||
chatModel.updateContactConnection(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
AppBarTitle(stringResource(MR.strings.add_contact))
|
||||
OneTimeLinkProfileText(connIncognito)
|
||||
|
||||
SectionSpacer()
|
||||
SectionView(stringResource(MR.strings.one_time_link_short).uppercase()) {
|
||||
OneTimeLinkSection(connReq, share, learnMore)
|
||||
if (connReq.isNotEmpty()) {
|
||||
QRCode(
|
||||
connReq, Modifier
|
||||
.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF)
|
||||
.aspectRatio(1f)
|
||||
)
|
||||
} else {
|
||||
CircularProgressIndicator(
|
||||
Modifier
|
||||
.size(36.dp)
|
||||
.padding(4.dp)
|
||||
.align(Alignment.CenterHorizontally),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
strokeWidth = 3.dp
|
||||
)
|
||||
}
|
||||
|
||||
IncognitoToggle(incognitoPref, incognito) { ModalManager.start.showModal { IncognitoView() } }
|
||||
ShareLinkButton(share)
|
||||
OneTimeLinkLearnMoreButton(learnMore)
|
||||
}
|
||||
SectionTextFooter(sharedProfileInfo(chatModel, incognito.value))
|
||||
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun OneTimeLinkProfileText(connIncognito: Boolean) {
|
||||
Row(Modifier.padding(horizontal = DEFAULT_PADDING)) {
|
||||
InfoAboutIncognito(
|
||||
connIncognito,
|
||||
true,
|
||||
generalGetString(MR.strings.incognito_random_profile_description),
|
||||
generalGetString(MR.strings.your_profile_will_be_sent)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ColumnScope.OneTimeLinkSection(connReq: String, share: () -> Unit, learnMore: () -> Unit) {
|
||||
if (connReq.isNotEmpty()) {
|
||||
QRCode(
|
||||
connReq, Modifier
|
||||
.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF)
|
||||
.aspectRatio(1f)
|
||||
)
|
||||
} else {
|
||||
CircularProgressIndicator(
|
||||
Modifier
|
||||
.size(36.dp)
|
||||
.padding(4.dp)
|
||||
.align(Alignment.CenterHorizontally),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
strokeWidth = 3.dp
|
||||
)
|
||||
}
|
||||
ShareLinkButton(share)
|
||||
OneTimeLinkLearnMoreButton(learnMore)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShareLinkButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
@@ -117,39 +129,38 @@ fun OneTimeLinkLearnMoreButton(onClick: () -> Unit) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InfoAboutIncognito(chatModelIncognito: Boolean, supportedIncognito: Boolean = true, onText: String, offText: String, centered: Boolean = false) {
|
||||
if (chatModelIncognito) {
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = if (centered) Arrangement.Center else Arrangement.Start
|
||||
) {
|
||||
Icon(
|
||||
if (supportedIncognito) painterResource(MR.images.ic_theater_comedy_filled) else painterResource(MR.images.ic_info),
|
||||
stringResource(MR.strings.incognito),
|
||||
tint = if (supportedIncognito) Indigo else WarningOrange,
|
||||
modifier = Modifier.padding(end = 10.dp).size(20.dp)
|
||||
)
|
||||
Text(onText, textAlign = if (centered) TextAlign.Center else TextAlign.Left, style = MaterialTheme.typography.body2)
|
||||
}
|
||||
fun IncognitoToggle(
|
||||
incognitoPref: SharedPreference<Boolean>,
|
||||
incognito: MutableState<Boolean>,
|
||||
onClickInfo: () -> Unit
|
||||
) {
|
||||
SettingsActionItemWithContent(
|
||||
icon = if (incognito.value) painterResource(MR.images.ic_theater_comedy_filled) else painterResource(MR.images.ic_theater_comedy),
|
||||
text = null,
|
||||
click = onClickInfo,
|
||||
iconColor = if (incognito.value) Indigo else MaterialTheme.colors.secondary,
|
||||
extraPadding = false
|
||||
) {
|
||||
SharedPreferenceToggleWithIcon(
|
||||
stringResource(MR.strings.incognito),
|
||||
painterResource(MR.images.ic_info),
|
||||
stopped = false,
|
||||
onClickInfo = onClickInfo,
|
||||
preference = incognitoPref,
|
||||
preferenceState = incognito
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun sharedProfileInfo(
|
||||
chatModel: ChatModel,
|
||||
incognito: Boolean
|
||||
): String {
|
||||
val name = chatModel.currentUser.value?.displayName ?: ""
|
||||
return if (incognito) {
|
||||
generalGetString(MR.strings.connect__a_new_random_profile_will_be_shared)
|
||||
} else {
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = if (centered) Arrangement.Center else Arrangement.Start
|
||||
) {
|
||||
Icon(
|
||||
painterResource(MR.images.ic_info),
|
||||
stringResource(MR.strings.incognito),
|
||||
tint = MaterialTheme.colors.secondary,
|
||||
modifier = Modifier.padding(end = 10.dp).size(20.dp)
|
||||
)
|
||||
Text(offText, textAlign = if (centered) TextAlign.Center else TextAlign.Left, style = MaterialTheme.typography.body2)
|
||||
}
|
||||
String.format(generalGetString(MR.strings.connect__your_profile_will_be_shared), name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,8 +173,10 @@ fun InfoAboutIncognito(chatModelIncognito: Boolean, supportedIncognito: Boolean
|
||||
fun PreviewAddContactView() {
|
||||
SimpleXTheme {
|
||||
AddContactLayout(
|
||||
chatModel = ChatModel,
|
||||
incognitoPref = SharedPreference({ false }, {}),
|
||||
connReq = "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D",
|
||||
connIncognito = false,
|
||||
contactConnection = mutableStateOf(PendingContactConnection.getSampleData()),
|
||||
share = {},
|
||||
learnMore = {},
|
||||
)
|
||||
|
||||
@@ -2,16 +2,18 @@ package chat.simplex.common.views.newchat
|
||||
|
||||
import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import chat.simplex.common.model.*
|
||||
@@ -19,10 +21,10 @@ import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.chat.LocalAliasEditor
|
||||
import chat.simplex.common.views.chatlist.deleteContactConnectionAlert
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.views.usersettings.SettingsActionItem
|
||||
import chat.simplex.common.model.ChatModel
|
||||
import chat.simplex.common.model.PendingContactConnection
|
||||
import chat.simplex.common.platform.shareText
|
||||
import chat.simplex.common.views.usersettings.*
|
||||
import chat.simplex.res.MR
|
||||
|
||||
@Composable
|
||||
@@ -49,10 +51,10 @@ fun ContactConnectionInfoView(
|
||||
}
|
||||
val clipboard = LocalClipboardManager.current
|
||||
ContactConnectionInfoLayout(
|
||||
chatModel = chatModel,
|
||||
connReq = connReqInvitation,
|
||||
contactConnection,
|
||||
connIncognito = contactConnection.incognito,
|
||||
focusAlias,
|
||||
contactConnection = contactConnection,
|
||||
focusAlias = focusAlias,
|
||||
deleteConnection = { deleteContactConnectionAlert(contactConnection, chatModel, close) },
|
||||
onLocalAliasChanged = { setContactAlias(contactConnection, it, chatModel) },
|
||||
share = { if (connReqInvitation != null) clipboard.shareText(connReqInvitation) },
|
||||
@@ -73,22 +75,43 @@ fun ContactConnectionInfoView(
|
||||
|
||||
@Composable
|
||||
private fun ContactConnectionInfoLayout(
|
||||
chatModel: ChatModel,
|
||||
connReq: String?,
|
||||
contactConnection: PendingContactConnection,
|
||||
connIncognito: Boolean,
|
||||
focusAlias: Boolean,
|
||||
deleteConnection: () -> Unit,
|
||||
onLocalAliasChanged: (String) -> Unit,
|
||||
share: () -> Unit,
|
||||
learnMore: () -> Unit,
|
||||
) {
|
||||
@Composable fun incognitoEnabled() {
|
||||
if (contactConnection.incognito) {
|
||||
SettingsActionItemWithContent(
|
||||
icon = painterResource(MR.images.ic_theater_comedy_filled),
|
||||
text = null,
|
||||
click = { ModalManager.start.showModal { IncognitoView() } },
|
||||
iconColor = Indigo,
|
||||
extraPadding = false
|
||||
) {
|
||||
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(stringResource(MR.strings.incognito), Modifier.padding(end = 4.dp))
|
||||
Icon(
|
||||
painterResource(MR.images.ic_info),
|
||||
null,
|
||||
tint = MaterialTheme.colors.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
AppBarTitle(
|
||||
stringResource(
|
||||
if (contactConnection.initiated) MR.strings.you_invited_your_contact
|
||||
if (contactConnection.initiated) MR.strings.you_invited_a_contact
|
||||
else MR.strings.you_accepted_connection
|
||||
)
|
||||
)
|
||||
@@ -101,7 +124,6 @@ private fun ContactConnectionInfoLayout(
|
||||
),
|
||||
Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING)
|
||||
)
|
||||
OneTimeLinkProfileText(connIncognito)
|
||||
|
||||
if (contactConnection.groupLinkId == null) {
|
||||
LocalAliasEditor(contactConnection.localAlias, center = false, leadingIcon = true, focus = focusAlias, updateValue = onLocalAliasChanged)
|
||||
@@ -109,11 +131,20 @@ private fun ContactConnectionInfoLayout(
|
||||
|
||||
SectionView {
|
||||
if (!connReq.isNullOrEmpty() && contactConnection.initiated) {
|
||||
OneTimeLinkSection(connReq, share, learnMore)
|
||||
QRCode(
|
||||
connReq, Modifier
|
||||
.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF)
|
||||
.aspectRatio(1f)
|
||||
)
|
||||
incognitoEnabled()
|
||||
ShareLinkButton(share)
|
||||
OneTimeLinkLearnMoreButton(learnMore)
|
||||
} else {
|
||||
incognitoEnabled()
|
||||
OneTimeLinkLearnMoreButton(learnMore)
|
||||
}
|
||||
}
|
||||
SectionTextFooter(sharedProfileInfo(chatModel, contactConnection.incognito))
|
||||
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
|
||||
@@ -149,9 +180,9 @@ private fun setContactAlias(contactConnection: PendingContactConnection, localAl
|
||||
private fun PreviewContactConnectionInfoView() {
|
||||
SimpleXTheme {
|
||||
ContactConnectionInfoLayout(
|
||||
chatModel = ChatModel,
|
||||
connReq = "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D",
|
||||
PendingContactConnection.getSampleData(),
|
||||
connIncognito = false,
|
||||
contactConnection = PendingContactConnection.getSampleData(),
|
||||
focusAlias = false,
|
||||
deleteConnection = {},
|
||||
onLocalAliasChanged = {},
|
||||
|
||||
@@ -10,6 +10,7 @@ import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.model.ChatModel
|
||||
import chat.simplex.common.model.PendingContactConnection
|
||||
import chat.simplex.common.views.helpers.ModalManager
|
||||
import chat.simplex.common.views.helpers.withApi
|
||||
import chat.simplex.common.views.usersettings.UserAddressView
|
||||
@@ -23,10 +24,16 @@ enum class CreateLinkTab {
|
||||
fun CreateLinkView(m: ChatModel, initialSelection: CreateLinkTab) {
|
||||
val selection = remember { mutableStateOf(initialSelection) }
|
||||
val connReqInvitation = rememberSaveable { m.connReqInv }
|
||||
val contactConnection: MutableState<PendingContactConnection?> = rememberSaveable { mutableStateOf(null) }
|
||||
val creatingConnReq = rememberSaveable { mutableStateOf(false) }
|
||||
LaunchedEffect(selection.value) {
|
||||
if (selection.value == CreateLinkTab.ONE_TIME && connReqInvitation.value.isNullOrEmpty() && !creatingConnReq.value) {
|
||||
createInvitation(m, creatingConnReq, connReqInvitation)
|
||||
if (
|
||||
selection.value == CreateLinkTab.ONE_TIME
|
||||
&& connReqInvitation.value.isNullOrEmpty()
|
||||
&& contactConnection.value == null
|
||||
&& !creatingConnReq.value
|
||||
) {
|
||||
createInvitation(m, creatingConnReq, connReqInvitation, contactConnection)
|
||||
}
|
||||
}
|
||||
/** When [AddContactView] is open, we don't need to drop [chatModel.connReqInv].
|
||||
@@ -42,9 +49,12 @@ fun CreateLinkView(m: ChatModel, initialSelection: CreateLinkTab) {
|
||||
}
|
||||
val tabTitles = CreateLinkTab.values().map {
|
||||
when {
|
||||
it == CreateLinkTab.ONE_TIME && connReqInvitation.value.isNullOrEmpty() -> stringResource(MR.strings.create_one_time_link)
|
||||
it == CreateLinkTab.ONE_TIME -> stringResource(MR.strings.one_time_link)
|
||||
it == CreateLinkTab.LONG_TERM -> stringResource(MR.strings.your_simplex_contact_address)
|
||||
it == CreateLinkTab.ONE_TIME && connReqInvitation.value.isNullOrEmpty() && contactConnection.value == null ->
|
||||
stringResource(MR.strings.create_one_time_link)
|
||||
it == CreateLinkTab.ONE_TIME ->
|
||||
stringResource(MR.strings.one_time_link)
|
||||
it == CreateLinkTab.LONG_TERM ->
|
||||
stringResource(MR.strings.your_simplex_contact_address)
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
@@ -56,7 +66,7 @@ fun CreateLinkView(m: ChatModel, initialSelection: CreateLinkTab) {
|
||||
Column(Modifier.weight(1f)) {
|
||||
when (selection.value) {
|
||||
CreateLinkTab.ONE_TIME -> {
|
||||
AddContactView(connReqInvitation.value ?: "", m.incognito.value)
|
||||
AddContactView(m, connReqInvitation.value ?: "", contactConnection)
|
||||
}
|
||||
CreateLinkTab.LONG_TERM -> {
|
||||
UserAddressView(m, viaCreateLinkView = true, close = {})
|
||||
@@ -89,12 +99,18 @@ fun CreateLinkView(m: ChatModel, initialSelection: CreateLinkTab) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createInvitation(m: ChatModel, creatingConnReq: MutableState<Boolean>, connReqInvitation: MutableState<String?>) {
|
||||
private fun createInvitation(
|
||||
m: ChatModel,
|
||||
creatingConnReq: MutableState<Boolean>,
|
||||
connReqInvitation: MutableState<String?>,
|
||||
contactConnection: MutableState<PendingContactConnection?>
|
||||
) {
|
||||
creatingConnReq.value = true
|
||||
withApi {
|
||||
val connReq = m.controller.apiAddContact()
|
||||
if (connReq != null) {
|
||||
connReqInvitation.value = connReq
|
||||
val r = m.controller.apiAddContact(incognito = m.controller.appPrefs.incognito.get())
|
||||
if (r != null) {
|
||||
connReqInvitation.value = r.first
|
||||
contactConnection.value = r.second
|
||||
} else {
|
||||
creatingConnReq.value = false
|
||||
}
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
package chat.simplex.common.views.newchat
|
||||
|
||||
import SectionBottomSpacer
|
||||
import SectionTextFooter
|
||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import chat.simplex.common.platform.Log
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.common.platform.TAG
|
||||
import chat.simplex.common.model.ChatModel
|
||||
import chat.simplex.common.model.SharedPreference
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.views.usersettings.IncognitoView
|
||||
import chat.simplex.common.views.usersettings.SettingsActionItem
|
||||
import chat.simplex.res.MR
|
||||
import java.net.URI
|
||||
|
||||
@@ -25,85 +29,98 @@ fun PasteToConnectView(chatModel: ChatModel, close: () -> Unit) {
|
||||
val connectionLink = remember { mutableStateOf("") }
|
||||
val clipboard = LocalClipboardManager.current
|
||||
PasteToConnectLayout(
|
||||
chatModel.incognito.value,
|
||||
chatModel = chatModel,
|
||||
incognitoPref = chatModel.controller.appPrefs.incognito,
|
||||
connectionLink = connectionLink,
|
||||
pasteFromClipboard = {
|
||||
connectionLink.value = clipboard.getText()?.text ?: return@PasteToConnectLayout
|
||||
},
|
||||
connectViaLink = { connReqUri ->
|
||||
try {
|
||||
val uri = URI(connReqUri)
|
||||
withUriAction(uri) { linkType ->
|
||||
val action = suspend {
|
||||
Log.d(TAG, "connectViaUri: connecting")
|
||||
if (connectViaUri(chatModel, linkType, uri)) {
|
||||
close()
|
||||
}
|
||||
}
|
||||
if (linkType == ConnectionLinkType.GROUP) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.connect_via_group_link),
|
||||
text = generalGetString(MR.strings.you_will_join_group),
|
||||
confirmText = generalGetString(MR.strings.connect_via_link_verb),
|
||||
onConfirm = { withApi { action() } }
|
||||
)
|
||||
} else action()
|
||||
}
|
||||
} catch (e: RuntimeException) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.invalid_connection_link),
|
||||
text = generalGetString(MR.strings.this_string_is_not_a_connection_link)
|
||||
)
|
||||
}
|
||||
},
|
||||
close = close
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PasteToConnectLayout(
|
||||
chatModelIncognito: Boolean,
|
||||
chatModel: ChatModel,
|
||||
incognitoPref: SharedPreference<Boolean>,
|
||||
connectionLink: MutableState<String>,
|
||||
pasteFromClipboard: () -> Unit,
|
||||
connectViaLink: (String) -> Unit,
|
||||
close: () -> Unit
|
||||
) {
|
||||
val incognito = remember { mutableStateOf(incognitoPref.get()) }
|
||||
|
||||
fun connectViaLink(connReqUri: String) {
|
||||
try {
|
||||
val uri = URI(connReqUri)
|
||||
withUriAction(uri) { linkType ->
|
||||
val action = suspend {
|
||||
Log.d(TAG, "connectViaUri: connecting")
|
||||
if (connectViaUri(chatModel, linkType, uri, incognito = incognito.value)) {
|
||||
close()
|
||||
}
|
||||
}
|
||||
if (linkType == ConnectionLinkType.GROUP) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.connect_via_group_link),
|
||||
text = generalGetString(MR.strings.you_will_join_group),
|
||||
confirmText = if (incognito.value) generalGetString(MR.strings.connect_via_link_incognito) else generalGetString(MR.strings.connect_via_link_verb),
|
||||
onConfirm = { withApi { action() } }
|
||||
)
|
||||
} else action()
|
||||
}
|
||||
} catch (e: RuntimeException) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.invalid_connection_link),
|
||||
text = generalGetString(MR.strings.this_string_is_not_a_connection_link)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING),
|
||||
verticalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
AppBarTitle(stringResource(MR.strings.connect_via_link), false)
|
||||
Text(stringResource(MR.strings.paste_connection_link_below_to_connect))
|
||||
|
||||
InfoAboutIncognito(
|
||||
chatModelIncognito,
|
||||
true,
|
||||
generalGetString(MR.strings.incognito_random_profile_from_contact_description),
|
||||
generalGetString(MR.strings.profile_will_be_sent_to_contact_sending_link)
|
||||
)
|
||||
|
||||
Box(Modifier.padding(top = DEFAULT_PADDING, bottom = 6.dp)) {
|
||||
TextEditor(connectionLink, Modifier.height(180.dp), contentPadding = PaddingValues())
|
||||
TextEditor(
|
||||
connectionLink,
|
||||
Modifier.height(180.dp),
|
||||
contentPadding = PaddingValues(),
|
||||
placeholder = stringResource(MR.strings.paste_the_link_you_received_to_connect_with_your_contact)
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
Modifier.fillMaxWidth().padding(bottom = 6.dp),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
) {
|
||||
if (connectionLink.value == "") {
|
||||
SimpleButton(text = stringResource(MR.strings.paste_button), icon = painterResource(MR.images.ic_content_paste)) {
|
||||
pasteFromClipboard()
|
||||
}
|
||||
} else {
|
||||
SimpleButton(text = stringResource(MR.strings.clear_verb), icon = painterResource(MR.images.ic_close)) {
|
||||
connectionLink.value = ""
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.weight(1f).fillMaxWidth())
|
||||
SimpleButton(text = stringResource(MR.strings.connect_button), icon = painterResource(MR.images.ic_link)) {
|
||||
connectViaLink(connectionLink.value)
|
||||
}
|
||||
if (connectionLink.value == "") {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_content_paste),
|
||||
stringResource(MR.strings.paste_button),
|
||||
click = pasteFromClipboard,
|
||||
)
|
||||
} else {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_close),
|
||||
stringResource(MR.strings.clear_verb),
|
||||
click = { connectionLink.value = "" },
|
||||
)
|
||||
}
|
||||
|
||||
Text(annotatedStringResource(MR.strings.you_can_also_connect_by_clicking_the_link))
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_link),
|
||||
stringResource(MR.strings.connect_button),
|
||||
click = { connectViaLink(connectionLink.value) },
|
||||
)
|
||||
|
||||
IncognitoToggle(incognitoPref, incognito) { ModalManager.start.showModal { IncognitoView() } }
|
||||
|
||||
SectionTextFooter(
|
||||
buildAnnotatedString {
|
||||
append(sharedProfileInfo(chatModel, incognito.value))
|
||||
append("\n\n")
|
||||
append(annotatedStringResource(MR.strings.you_can_also_connect_by_clicking_the_link))
|
||||
}
|
||||
)
|
||||
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
@@ -117,17 +134,11 @@ fun PasteToConnectLayout(
|
||||
fun PreviewPasteToConnectTextbox() {
|
||||
SimpleXTheme {
|
||||
PasteToConnectLayout(
|
||||
chatModelIncognito = false,
|
||||
chatModel = ChatModel,
|
||||
incognitoPref = SharedPreference({ false }, {}),
|
||||
connectionLink = remember { mutableStateOf("") },
|
||||
pasteFromClipboard = {},
|
||||
connectViaLink = { link ->
|
||||
try {
|
||||
println(link)
|
||||
// withApi { chatModel.controller.apiConnect(link) }
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
},
|
||||
close = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ fun QRCode(
|
||||
bitmap = qr,
|
||||
contentDescription = stringResource(MR.strings.image_descr_qr_code),
|
||||
Modifier
|
||||
.widthIn(max = 500.dp)
|
||||
.widthIn(max = 360.dp)
|
||||
.then(modifier)
|
||||
.clickable {
|
||||
scope.launch {
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
package chat.simplex.common.views.newchat
|
||||
|
||||
import SectionBottomSpacer
|
||||
import SectionTextFooter
|
||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import chat.simplex.common.platform.Log
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.platform.TAG
|
||||
import chat.simplex.common.model.ChatModel
|
||||
import chat.simplex.common.model.json
|
||||
import chat.simplex.common.ui.theme.DEFAULT_PADDING
|
||||
import chat.simplex.common.ui.theme.SimpleXTheme
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.views.usersettings.*
|
||||
import chat.simplex.res.MR
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
@@ -26,36 +26,6 @@ import java.net.URI
|
||||
@Composable
|
||||
expect fun ScanToConnectView(chatModel: ChatModel, close: () -> Unit)
|
||||
|
||||
@Composable
|
||||
fun QRCodeScanner(close: () -> Unit) {
|
||||
QRCodeScanner { connReqUri ->
|
||||
try {
|
||||
val uri = URI(connReqUri)
|
||||
withUriAction(uri) { linkType ->
|
||||
val action = suspend {
|
||||
Log.d(TAG, "connectViaUri: connecting")
|
||||
if (connectViaUri(ChatModel, linkType, uri)) {
|
||||
close()
|
||||
}
|
||||
}
|
||||
if (linkType == ConnectionLinkType.GROUP) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.connect_via_group_link),
|
||||
text = generalGetString(MR.strings.you_will_join_group),
|
||||
confirmText = generalGetString(MR.strings.connect_via_link_verb),
|
||||
onConfirm = { withApi { action() } }
|
||||
)
|
||||
} else action()
|
||||
}
|
||||
} catch (e: RuntimeException) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.invalid_QR_code),
|
||||
text = generalGetString(MR.strings.this_QR_code_is_not_a_link)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class ConnectionLinkType {
|
||||
CONTACT, INVITATION, GROUP
|
||||
}
|
||||
@@ -93,8 +63,8 @@ fun withUriAction(uri: URI, run: suspend (ConnectionLinkType) -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun connectViaUri(chatModel: ChatModel, action: ConnectionLinkType, uri: URI): Boolean {
|
||||
val r = chatModel.controller.apiConnect(uri.toString())
|
||||
suspend fun connectViaUri(chatModel: ChatModel, action: ConnectionLinkType, uri: URI, incognito: Boolean): Boolean {
|
||||
val r = chatModel.controller.apiConnect(incognito, uri.toString())
|
||||
if (r) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.connection_request_sent),
|
||||
@@ -110,28 +80,65 @@ suspend fun connectViaUri(chatModel: ChatModel, action: ConnectionLinkType, uri:
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ConnectContactLayout(chatModelIncognito: Boolean, close: () -> Unit) {
|
||||
fun ConnectContactLayout(
|
||||
chatModel: ChatModel,
|
||||
incognitoPref: SharedPreference<Boolean>,
|
||||
close: () -> Unit
|
||||
) {
|
||||
val incognito = remember { mutableStateOf(incognitoPref.get()) }
|
||||
|
||||
@Composable
|
||||
fun QRCodeScanner(close: () -> Unit) {
|
||||
QRCodeScanner { connReqUri ->
|
||||
try {
|
||||
val uri = URI(connReqUri)
|
||||
withUriAction(uri) { linkType ->
|
||||
val action = suspend {
|
||||
Log.d(TAG, "connectViaUri: connecting")
|
||||
if (connectViaUri(ChatModel, linkType, uri, incognito = incognito.value)) {
|
||||
close()
|
||||
}
|
||||
}
|
||||
if (linkType == ConnectionLinkType.GROUP) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.connect_via_group_link),
|
||||
text = generalGetString(MR.strings.you_will_join_group),
|
||||
confirmText = if (incognito.value) generalGetString(MR.strings.connect_via_link_incognito) else generalGetString(MR.strings.connect_via_link_verb),
|
||||
onConfirm = { withApi { action() } }
|
||||
)
|
||||
} else action()
|
||||
}
|
||||
} catch (e: RuntimeException) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.invalid_QR_code),
|
||||
text = generalGetString(MR.strings.this_QR_code_is_not_a_link)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
verticalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
AppBarTitle(stringResource(MR.strings.scan_QR_code), false)
|
||||
InfoAboutIncognito(
|
||||
chatModelIncognito,
|
||||
true,
|
||||
generalGetString(MR.strings.incognito_random_profile_description),
|
||||
generalGetString(MR.strings.your_profile_will_be_sent)
|
||||
)
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(ratio = 1F)
|
||||
.padding(bottom = 12.dp)
|
||||
) { QRCodeScanner(close) }
|
||||
Text(
|
||||
annotatedStringResource(MR.strings.if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link),
|
||||
lineHeight = 22.sp
|
||||
|
||||
IncognitoToggle(incognitoPref, incognito) { ModalManager.start.showModal { IncognitoView() } }
|
||||
|
||||
SectionTextFooter(
|
||||
buildAnnotatedString {
|
||||
append(sharedProfileInfo(chatModel, incognito.value))
|
||||
append("\n\n")
|
||||
append(annotatedStringResource(MR.strings.if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link))
|
||||
}
|
||||
)
|
||||
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
@@ -150,7 +157,8 @@ fun URI.getQueryParameter(param: String): String? {
|
||||
fun PreviewConnectContactLayout() {
|
||||
SimpleXTheme {
|
||||
ConnectContactLayout(
|
||||
chatModelIncognito = false,
|
||||
chatModel = ChatModel,
|
||||
incognitoPref = SharedPreference({ false }, {}),
|
||||
close = {},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ fun IncognitoLayout() {
|
||||
Text(generalGetString(MR.strings.incognito_info_protects))
|
||||
Text(generalGetString(MR.strings.incognito_info_allows))
|
||||
Text(generalGetString(MR.strings.incognito_info_share))
|
||||
Text(generalGetString(MR.strings.incognito_info_find))
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,16 +37,12 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit, drawerSt
|
||||
val user = chatModel.currentUser.value
|
||||
val stopped = chatModel.chatRunning.value == false
|
||||
|
||||
MaintainIncognitoState(chatModel)
|
||||
|
||||
if (user != null) {
|
||||
val requireAuth = remember { chatModel.controller.appPrefs.performLA.state }
|
||||
SettingsLayout(
|
||||
profile = user.profile,
|
||||
stopped,
|
||||
chatModel.chatDbEncrypted.value == true,
|
||||
chatModel.incognito,
|
||||
chatModel.controller.appPrefs.incognito,
|
||||
user.displayName,
|
||||
setPerformLA = setPerformLA,
|
||||
showModal = { modalView -> { ModalManager.start.showModal { modalView(chatModel) } } },
|
||||
@@ -118,8 +114,6 @@ fun SettingsLayout(
|
||||
profile: LocalProfile,
|
||||
stopped: Boolean,
|
||||
encrypted: Boolean,
|
||||
incognito: MutableState<Boolean>,
|
||||
incognitoPref: SharedPreference<Boolean>,
|
||||
userDisplayName: String,
|
||||
setPerformLA: (Boolean) -> Unit,
|
||||
showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit),
|
||||
@@ -155,7 +149,6 @@ fun SettingsLayout(
|
||||
}
|
||||
val profileHidden = rememberSaveable { mutableStateOf(false) }
|
||||
SettingsActionItem(painterResource(MR.images.ic_manage_accounts), stringResource(MR.strings.your_chat_profiles), { withAuth(generalGetString(MR.strings.auth_open_chat_profiles), generalGetString(MR.strings.auth_log_in_using_credential)) { showSettingsModalWithSearch { it, search -> UserProfilesView(it, search, profileHidden) } } }, disabled = stopped, extraPadding = true)
|
||||
SettingsIncognitoActionItem(incognitoPref, incognito, stopped) { showModal { IncognitoView() }() }
|
||||
SettingsActionItem(painterResource(MR.images.ic_qr_code), stringResource(MR.strings.your_simplex_contact_address), showCustomModal { it, close -> UserAddressView(it, shareViaProfile = it.currentUser.value!!.addressShared, close = close) }, disabled = stopped, extraPadding = true)
|
||||
ChatPreferencesItem(showCustomModal, stopped = stopped)
|
||||
}
|
||||
@@ -212,43 +205,6 @@ expect fun SettingsSectionApp(
|
||||
withAuth: (title: String, desc: String, block: () -> Unit) -> Unit
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun SettingsIncognitoActionItem(
|
||||
incognitoPref: SharedPreference<Boolean>,
|
||||
incognito: MutableState<Boolean>,
|
||||
stopped: Boolean,
|
||||
onClickInfo: () -> Unit,
|
||||
) {
|
||||
SettingsPreferenceItemWithInfo(
|
||||
if (incognito.value) painterResource(MR.images.ic_theater_comedy_filled) else painterResource(MR.images.ic_theater_comedy),
|
||||
if (incognito.value) Indigo else MaterialTheme.colors.secondary,
|
||||
stringResource(MR.strings.incognito),
|
||||
stopped,
|
||||
onClickInfo,
|
||||
incognitoPref,
|
||||
incognito
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MaintainIncognitoState(chatModel: ChatModel) {
|
||||
// Cache previous value and once it changes in background, update it via API
|
||||
var cachedIncognito by remember { mutableStateOf(chatModel.incognito.value) }
|
||||
LaunchedEffect(chatModel.incognito.value) {
|
||||
// Don't do anything if nothing changed
|
||||
if (cachedIncognito == chatModel.incognito.value) return@LaunchedEffect
|
||||
try {
|
||||
chatModel.controller.apiSetIncognito(chatModel.incognito.value)
|
||||
} catch (e: Exception) {
|
||||
// Rollback the state
|
||||
chatModel.controller.appPrefs.incognito.set(cachedIncognito)
|
||||
// Crash the app
|
||||
throw e
|
||||
}
|
||||
cachedIncognito = chatModel.incognito.value
|
||||
}
|
||||
}
|
||||
|
||||
@Composable private fun DatabaseItem(encrypted: Boolean, openDatabaseView: () -> Unit, stopped: Boolean) {
|
||||
SectionItemViewWithIcon(openDatabaseView) {
|
||||
Row(
|
||||
@@ -453,21 +409,6 @@ fun SettingsPreferenceItem(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsPreferenceItemWithInfo(
|
||||
icon: Painter,
|
||||
iconTint: Color,
|
||||
text: String,
|
||||
stopped: Boolean,
|
||||
onClickInfo: () -> Unit,
|
||||
pref: SharedPreference<Boolean>,
|
||||
prefState: MutableState<Boolean>? = null
|
||||
) {
|
||||
SettingsActionItemWithContent(icon, null, click = if (stopped) null else onClickInfo, iconColor = iconTint, extraPadding = true,) {
|
||||
SharedPreferenceToggleWithIcon(text, painterResource(MR.images.ic_info), stopped, onClickInfo, pref, prefState)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PreferenceToggle(
|
||||
text: String,
|
||||
@@ -523,8 +464,6 @@ fun PreviewSettingsLayout() {
|
||||
profile = LocalProfile.sampleData,
|
||||
stopped = false,
|
||||
encrypted = false,
|
||||
incognito = remember { mutableStateOf(false) },
|
||||
incognitoPref = SharedPreference({ false }, {}),
|
||||
userDisplayName = "Alice",
|
||||
setPerformLA = { _ -> },
|
||||
showModal = { {} },
|
||||
|
||||
@@ -7,9 +7,12 @@
|
||||
<string name="connect_via_contact_link">Connect via contact link?</string>
|
||||
<string name="connect_via_invitation_link">Connect via invitation link?</string>
|
||||
<string name="connect_via_group_link">Connect via group link?</string>
|
||||
<string name="connect_use_current_profile">Use current profile</string>
|
||||
<string name="connect_use_new_incognito_profile">Use new incognito profile</string>
|
||||
<string name="profile_will_be_sent_to_contact_sending_link">Your profile will be sent to the contact that you received this link from.</string>
|
||||
<string name="you_will_join_group">You will join a group this link refers to and connect to its group members.</string>
|
||||
<string name="connect_via_link_verb">Connect</string>
|
||||
<string name="connect_via_link_incognito">Connect incognito</string>
|
||||
|
||||
<!-- MainActivity.kt -->
|
||||
<string name="opening_database">Opening database…</string>
|
||||
@@ -443,7 +446,7 @@
|
||||
|
||||
|
||||
<!-- Pending contact connection alert dialogues -->
|
||||
<string name="you_invited_your_contact">You invited your contact</string>
|
||||
<string name="you_invited_a_contact">You invited a contact</string>
|
||||
<string name="you_accepted_connection">You accepted connection</string>
|
||||
<string name="delete_pending_connection__question">Delete pending connection?</string>
|
||||
<string name="contact_you_shared_link_with_wont_be_able_to_connect">The contact you shared this link with will NOT be able to connect!</string>
|
||||
@@ -489,11 +492,13 @@
|
||||
<string name="your_chat_profile_will_be_sent_to_your_contact">Your chat profile will be sent\nto your contact</string>
|
||||
<string name="if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link"><![CDATA[If you cannot meet in person, you can <b>scan QR code in the video call</b>, or your contact can share an invitation link.]]></string>
|
||||
<string name="share_invitation_link">Share 1-time link</string>
|
||||
<string name="paste_connection_link_below_to_connect">Paste the link you received into the box below to connect with your contact.</string>
|
||||
<string name="your_profile_will_be_sent">Your chat profile will be sent to your contact</string>
|
||||
<string name="paste_the_link_you_received_to_connect_with_your_contact">Paste the link you received to connect with your contact…</string>
|
||||
<string name="learn_more">Learn more</string>
|
||||
<string name="learn_more_about_address">About SimpleX address</string>
|
||||
|
||||
<string name="connect__a_new_random_profile_will_be_shared">A new random profile will be shared.</string>
|
||||
<string name="connect__your_profile_will_be_shared">Your profile %1$s will be shared.</string>
|
||||
|
||||
<!-- Add Contact Learn More - AddContactLearnMore.kt -->
|
||||
<string name="scan_qr_to_connect_to_contact">To connect, your contact can scan QR code or use the link in the app.</string>
|
||||
<string name="if_you_cant_meet_in_person">If you can\'t meet in person, show QR code in a video call, or share the link.</string>
|
||||
@@ -1247,7 +1252,6 @@
|
||||
<string name="group_is_decentralized">The group is fully decentralized – it is visible only to the members.</string>
|
||||
<string name="group_display_name_field">Group display name:</string>
|
||||
<string name="group_full_name_field">Group full name:</string>
|
||||
<string name="group_unsupported_incognito_main_profile_sent">Incognito mode is not supported here - your main profile will be sent to group members</string>
|
||||
<string name="group_main_profile_sent">Your chat profile will be sent to group members</string>
|
||||
|
||||
|
||||
@@ -1301,13 +1305,10 @@
|
||||
<!-- Incognito mode -->
|
||||
<string name="incognito">Incognito</string>
|
||||
<string name="incognito_random_profile">Your random profile</string>
|
||||
<string name="incognito_random_profile_description">A random profile will be sent to your contact</string>
|
||||
<string name="incognito_random_profile_from_contact_description">A random profile will be sent to the contact that you received this link from</string>
|
||||
|
||||
<string name="incognito_info_protects">Incognito mode protects the privacy of your main profile name and image — for each new contact a new random profile is created.</string>
|
||||
<string name="incognito_info_protects">Incognito mode protects your privacy by using a new random profile for each contact.</string>
|
||||
<string name="incognito_info_allows">It allows having many anonymous connections without any shared data between them in a single chat profile.</string>
|
||||
<string name="incognito_info_share">When you share an incognito profile with somebody, this profile will be used for the groups they invite you to.</string>
|
||||
<string name="incognito_info_find">To find the profile used for an incognito connection, tap the contact or group name on top of the chat.</string>
|
||||
|
||||
<!-- Default themes -->
|
||||
<string name="theme_system">System</string>
|
||||
|
||||
@@ -201,7 +201,7 @@
|
||||
<string name="mark_unread">Označit jako nepřečteno</string>
|
||||
<string name="mute_chat">Ztlumit</string>
|
||||
<string name="unmute_chat">Zrušit ztlumení</string>
|
||||
<string name="you_invited_your_contact">Pozvali jste kontakt</string>
|
||||
<string name="you_invited_a_contact">Pozvali jste kontakt</string>
|
||||
<string name="contact_you_shared_link_with_wont_be_able_to_connect">Kontakt, se kterým jste tento odkaz sdíleli, se NEBUDE moci připojit!</string>
|
||||
<string name="connection_you_accepted_will_be_cancelled">Připojení, které jste přijali, bude zrušeno!</string>
|
||||
<string name="icon_descr_help">help</string>
|
||||
|
||||
@@ -292,7 +292,7 @@
|
||||
<string name="mute_chat">Stummschalten</string>
|
||||
<string name="unmute_chat">Stummschaltung aufheben</string>
|
||||
<!-- Pending contact connection alert dialogues -->
|
||||
<string name="you_invited_your_contact">Sie haben Ihren Kontakt eingeladen</string>
|
||||
<string name="you_invited_a_contact">Sie haben Ihren Kontakt eingeladen</string>
|
||||
<string name="you_accepted_connection">Sie haben die Verbindung akzeptiert</string>
|
||||
<string name="delete_pending_connection__question">Ausstehende Verbindung löschen?</string>
|
||||
<string name="contact_you_shared_link_with_wont_be_able_to_connect">Der Kontakt, mit dem Sie diesen Link geteilt haben, kann sich NICHT verbinden!</string>
|
||||
|
||||
@@ -914,7 +914,7 @@
|
||||
<string name="you_are_observer">Tu rol es observador</string>
|
||||
<string name="verify_security_code">Comprobar código de seguridad</string>
|
||||
<string name="you_accepted_connection">Has aceptado la conexión</string>
|
||||
<string name="you_invited_your_contact">Has invitado a tu contacto</string>
|
||||
<string name="you_invited_a_contact">Has invitado a tu contacto</string>
|
||||
<string name="you_will_be_connected_when_group_host_device_is_online">Te conectarás al grupo cuando el dispositivo anfitrión esté en línea, por favor espera o compruébalo más tarde.</string>
|
||||
<string name="your_settings">Tu configuración</string>
|
||||
<string name="your_SMP_servers">Servidores SMP</string>
|
||||
|
||||
@@ -1232,7 +1232,7 @@
|
||||
<string name="group_preview_you_are_invited">sinut on kutsuttu ryhmään</string>
|
||||
<string name="unmute_chat">Poista mykistys</string>
|
||||
<string name="you_accepted_connection">Hyväksyit yhteyden</string>
|
||||
<string name="you_invited_your_contact">Kutsuit kontaktisi</string>
|
||||
<string name="you_invited_a_contact">Kutsuit kontaktisi</string>
|
||||
<string name="call_connection_via_relay">releellä</string>
|
||||
<string name="database_downgrade_warning">Varoitus: saatat menettää joitain tietoja!</string>
|
||||
<string name="icon_descr_address">SimpleX Osoite</string>
|
||||
|
||||
@@ -221,7 +221,7 @@
|
||||
<string name="mark_read">Marquer comme lu</string>
|
||||
<string name="mark_unread">Marquer non lu</string>
|
||||
<string name="set_contact_name">Définir le nom du contact</string>
|
||||
<string name="you_invited_your_contact">Vous avez invité votre contact</string>
|
||||
<string name="you_invited_a_contact">Vous avez invité votre contact</string>
|
||||
<string name="you_accepted_connection">Vous avez accepté la connexion</string>
|
||||
<string name="delete_pending_connection__question">Supprimer la connexion en attente \?</string>
|
||||
<string name="connection_you_accepted_will_be_cancelled">La connexion que vous avez acceptée sera annulée !</string>
|
||||
|
||||
@@ -568,7 +568,7 @@
|
||||
<string name="icon_descr_address">Indirizzo di SimpleX</string>
|
||||
<string name="icon_descr_simplex_team">Squadra di SimpleX</string>
|
||||
<string name="you_accepted_connection">Hai accettato la connessione</string>
|
||||
<string name="you_invited_your_contact">Hai invitato il contatto</string>
|
||||
<string name="you_invited_a_contact">Hai invitato il contatto</string>
|
||||
<string name="your_chat_profile_will_be_sent_to_your_contact">Il tuo profilo di chat verrà inviato
|
||||
\nal tuo contatto</string>
|
||||
<string name="alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry">Il tuo contatto deve essere in linea per completare la connessione.
|
||||
|
||||
@@ -1182,7 +1182,7 @@
|
||||
<string name="waiting_for_video">ממתין לסרטון</string>
|
||||
<string name="waiting_for_file">ממתין לקובץ</string>
|
||||
<string name="voice_messages_prohibited">הודעות קוליות אסורות!</string>
|
||||
<string name="you_invited_your_contact">הזמנת את איש הקשר שלך</string>
|
||||
<string name="you_invited_a_contact">הזמנת את איש הקשר שלך</string>
|
||||
<string name="you_can_share_your_address">באפשרותכם לשתף את הכתובת שלכם כקישור או כקוד QR – כל אחד יכול להתחבר אליכם.</string>
|
||||
<string name="you_can_accept_or_reject_connection">כאשר אנשים מבקשים להתחבר, באפשרותך לקבל או לדחות זאת.</string>
|
||||
<string name="you_can_also_connect_by_clicking_the_link"><![CDATA[באפשרותכם גם להתחבר על־ידי לחיצה על הקישור. אם הוא נפתח בדפדפן, ליחצו על הכפתור <b>פתח באפליקציה</b>.]]></string>
|
||||
|
||||
@@ -715,7 +715,7 @@
|
||||
<string name="thank_you_for_installing_simplex">SimpleX Chatをご利用いただきありがとうございます!</string>
|
||||
<string name="use_camera_button">カメラ</string>
|
||||
<string name="you_accepted_connection">繋がりを承認しました</string>
|
||||
<string name="you_invited_your_contact">連絡先に招待を送りました</string>
|
||||
<string name="you_invited_a_contact">連絡先に招待を送りました</string>
|
||||
<string name="connection_you_accepted_will_be_cancelled">承認ずみの接続がキャンセルされます!</string>
|
||||
<string name="contact_you_shared_link_with_wont_be_able_to_connect">あなたからリンクを受けた連絡先が接続できなくなります!</string>
|
||||
<string name="icon_descr_address">SimpleXアドレス</string>
|
||||
|
||||
@@ -682,7 +682,7 @@
|
||||
<string name="connection_you_accepted_will_be_cancelled">De door u geaccepteerde verbinding wordt geannuleerd!</string>
|
||||
<string name="contact_you_shared_link_with_wont_be_able_to_connect">Het contact met wie je deze link hebt gedeeld, kan GEEN verbinding maken!</string>
|
||||
<string name="you_accepted_connection">Je hebt de verbinding geaccepteerd</string>
|
||||
<string name="you_invited_your_contact">Je hebt je contactpersoon uitgenodigd</string>
|
||||
<string name="you_invited_a_contact">Je hebt je contactpersoon uitgenodigd</string>
|
||||
<string name="alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry">Uw contactpersoon moet online zijn om de verbinding te voltooien.
|
||||
\nU kunt deze verbinding verbreken en het contact verwijderen (en later proberen met een nieuwe link).</string>
|
||||
<string name="image_descr_qr_code">QR code</string>
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
<string name="unmute_chat">Wyłącz wyciszenie</string>
|
||||
<string name="contact_wants_to_connect_with_you">chce się z Tobą połączyć!</string>
|
||||
<string name="you_accepted_connection">Zaakceptowałeś połączenie</string>
|
||||
<string name="you_invited_your_contact">Zaprosiłeś swój kontakt</string>
|
||||
<string name="you_invited_a_contact">Zaprosiłeś swój kontakt</string>
|
||||
<string name="alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry">Twój kontakt musi być online, aby połączenie zostało zakończone.
|
||||
\nMożesz anulować to połączenie i usunąć kontakt (i spróbować później z nowym linkiem).</string>
|
||||
<string name="connect_button">Połącz</string>
|
||||
|
||||
@@ -473,7 +473,7 @@
|
||||
<string name="simplex_service_notification_text">Recebendo mensagens…</string>
|
||||
<string name="large_file">Aruivo grande!</string>
|
||||
<string name="mark_read">Marcado como lido</string>
|
||||
<string name="you_invited_your_contact">Você convidou seu contato</string>
|
||||
<string name="you_invited_a_contact">Você convidou seu contato</string>
|
||||
<string name="invalid_QR_code">Código QR inválido</string>
|
||||
<string name="icon_descr_more_button">Mais</string>
|
||||
<string name="you_will_be_connected_when_group_host_device_is_online">Você será conectado ao grupo quando o dispositivo do host do grupo estiver online, por favor aguarde ou verifique mais tarde!</string>
|
||||
|
||||
@@ -294,7 +294,7 @@
|
||||
<string name="mute_chat">Без звука</string>
|
||||
<string name="unmute_chat">Уведомлять</string>
|
||||
<!-- Pending contact connection alert dialogues -->
|
||||
<string name="you_invited_your_contact">Вы пригласили Ваш контакт</string>
|
||||
<string name="you_invited_a_contact">Вы пригласили Ваш контакт</string>
|
||||
<string name="you_accepted_connection">Вы приняли приглашение соединиться</string>
|
||||
<string name="delete_pending_connection__question">Удалить ожидаемое соединение?</string>
|
||||
<string name="contact_you_shared_link_with_wont_be_able_to_connect">Контакт, которому Вы отправили эту ссылку, не сможет соединиться!</string>
|
||||
|
||||
@@ -1126,7 +1126,7 @@
|
||||
<string name="to_start_a_new_chat_help_header">เพื่อเริ่มแชทใหม่</string>
|
||||
<string name="gallery_video_button">วิดีโอ</string>
|
||||
<string name="unmute_chat">เปิดเสียง</string>
|
||||
<string name="you_invited_your_contact">คุณได้เชิญผู้ติดต่อของคุณ</string>
|
||||
<string name="you_invited_a_contact">คุณได้เชิญผู้ติดต่อของคุณ</string>
|
||||
<string name="you_accepted_connection">คุณยอมรับการเชื่อมต่อ</string>
|
||||
<string name="contact_wants_to_connect_with_you">ต้องการเชื่อมต่อกับคุณ!</string>
|
||||
<string name="alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry">ผู้ติดต่อของคุณจะต้องออนไลน์เพื่อให้การเชื่อมต่อเสร็จสมบูรณ์
|
||||
|
||||
@@ -226,7 +226,7 @@
|
||||
<string name="mobile_tap_open_in_mobile_app_then_tap_connect_in_app"><![CDATA[📱 мобільний: торкніться <b>Відкрийте в мобільному додатку</b>, потім торкніться <b>Підключіть</b> в додатку.]]></string>
|
||||
<string name="mute_chat">Вимкнути звук</string>
|
||||
<string name="unmute_chat">Увімкнути звук</string>
|
||||
<string name="you_invited_your_contact">Ви запросили свого контакта</string>
|
||||
<string name="you_invited_a_contact">Ви запросили свого контакта</string>
|
||||
<string name="contact_you_shared_link_with_wont_be_able_to_connect">Контакт, якому ви надали це посилання, НЕ зможе підключитися!</string>
|
||||
<string name="icon_descr_profile_image_placeholder">заповнювач зображення профілю</string>
|
||||
<string name="image_descr_qr_code">QR-код</string>
|
||||
|
||||
@@ -902,7 +902,7 @@
|
||||
<string name="voice_messages_prohibited">语音消息禁止发送!</string>
|
||||
<string name="you_need_to_allow_to_send_voice">您需要允许您的联系人发送语音消息才能发送它们。</string>
|
||||
<string name="scan_QR_code">扫描二维码</string>
|
||||
<string name="you_invited_your_contact">您邀请了您的联系人</string>
|
||||
<string name="you_invited_a_contact">您邀请了您的联系人</string>
|
||||
<string name="contact_wants_to_connect_with_you">想要与您连接!</string>
|
||||
<string name="alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry">您的联系人需要在线才能完成连接。
|
||||
\n您可以取消此连接并删除联系人(稍后尝试使用新链接)。</string>
|
||||
|
||||
@@ -533,7 +533,7 @@
|
||||
<string name="you_can_connect_to_simplex_chat_founder"><![CDATA[你可以透過 <font color="#0088ff">連接到 SimpleX Chat 開發人員提出任何問題並同意更新</font>。]]></string>
|
||||
<string name="to_start_a_new_chat_help_header">開啟新的對話</string>
|
||||
<string name="set_contact_name">設定聯絡人名稱</string>
|
||||
<string name="you_invited_your_contact">你已邀請了你的聯絡人</string>
|
||||
<string name="you_invited_a_contact">你已邀請了你的聯絡人</string>
|
||||
<string name="you_accepted_connection">你接受了連接</string>
|
||||
<string name="delete_pending_connection__question">刪除等待中的連接?</string>
|
||||
<string name="contact_you_shared_link_with_wont_be_able_to_connect">當聯絡人發現此連結後,嘗試點擊的聯絡人將無法連接!</string>
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
package chat.simplex.common.views.helpers
|
||||
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.key.*
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.*
|
||||
import chat.simplex.common.DialogParams
|
||||
import chat.simplex.res.MR
|
||||
@@ -21,6 +27,8 @@ actual fun DefaultDialog(
|
||||
) {
|
||||
Dialog(
|
||||
undecorated = true,
|
||||
transparent = true,
|
||||
resizable = false,
|
||||
title = "",
|
||||
onCloseRequest = onDismissRequest,
|
||||
onPreviewKeyEvent = { event ->
|
||||
@@ -29,7 +37,12 @@ actual fun DefaultDialog(
|
||||
} else false
|
||||
}
|
||||
) {
|
||||
content()
|
||||
Surface(
|
||||
Modifier
|
||||
.border(border = BorderStroke(1.dp, MaterialTheme.colors.secondary.copy(alpha = 0.3F)), shape = RoundedCornerShape(8))
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ import chat.simplex.common.model.ChatModel
|
||||
@Composable
|
||||
actual fun ScanToConnectView(chatModel: ChatModel, close: () -> Unit) {
|
||||
ConnectContactLayout(
|
||||
chatModelIncognito = chatModel.incognito.value,
|
||||
chatModel = chatModel,
|
||||
incognitoPref = chatModel.controller.appPrefs.incognito,
|
||||
close = close
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user