desktop: enhancements to remote hosts experience (#3428)
This commit is contained in:
parent
9442121efa
commit
48d7afc959
@ -126,7 +126,7 @@ fun processIntent(intent: Intent?) {
|
|||||||
when (intent?.action) {
|
when (intent?.action) {
|
||||||
"android.intent.action.VIEW" -> {
|
"android.intent.action.VIEW" -> {
|
||||||
val uri = intent.data
|
val uri = intent.data
|
||||||
if (uri != null) connectIfOpenedViaUri(chatModel.remoteHostId, uri.toURI(), ChatModel)
|
if (uri != null) connectIfOpenedViaUri(chatModel.remoteHostId(), uri.toURI(), ChatModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ class SimplexApp: Application(), LifecycleEventObserver {
|
|||||||
updatingChatsMutex.withLock {
|
updatingChatsMutex.withLock {
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
val currentUserId = chatModel.currentUser.value?.userId
|
val currentUserId = chatModel.currentUser.value?.userId
|
||||||
val chats = ArrayList(chatController.apiGetChats(chatModel.remoteHostId))
|
val chats = ArrayList(chatController.apiGetChats(chatModel.remoteHostId()))
|
||||||
/** Active user can be changed in background while [ChatController.apiGetChats] is executing */
|
/** Active user can be changed in background while [ChatController.apiGetChats] is executing */
|
||||||
if (chatModel.currentUser.value?.userId == currentUserId) {
|
if (chatModel.currentUser.value?.userId == currentUserId) {
|
||||||
val currentChatId = chatModel.chatId.value
|
val currentChatId = chatModel.chatId.value
|
||||||
|
@ -111,7 +111,8 @@ object ChatModel {
|
|||||||
// remote controller
|
// remote controller
|
||||||
val remoteHosts = mutableStateListOf<RemoteHostInfo>()
|
val remoteHosts = mutableStateListOf<RemoteHostInfo>()
|
||||||
val currentRemoteHost = mutableStateOf<RemoteHostInfo?>(null)
|
val currentRemoteHost = mutableStateOf<RemoteHostInfo?>(null)
|
||||||
val remoteHostId: Long? get() = currentRemoteHost?.value?.remoteHostId
|
val remoteHostId: Long? @Composable get() = remember { currentRemoteHost }.value?.remoteHostId
|
||||||
|
fun remoteHostId(): Long? = currentRemoteHost.value?.remoteHostId
|
||||||
val newRemoteHostPairing = mutableStateOf<Pair<RemoteHostInfo?, RemoteHostSessionState>?>(null)
|
val newRemoteHostPairing = mutableStateOf<Pair<RemoteHostInfo?, RemoteHostSessionState>?>(null)
|
||||||
val remoteCtrlSession = mutableStateOf<RemoteCtrlSession?>(null)
|
val remoteCtrlSession = mutableStateOf<RemoteCtrlSession?>(null)
|
||||||
|
|
||||||
|
@ -1625,7 +1625,7 @@ object ChatController {
|
|||||||
|| (mc is MsgContent.MCVoice && file.fileSize <= MAX_VOICE_SIZE_AUTO_RCV && file.fileStatus !is CIFileStatus.RcvAccepted))) {
|
|| (mc is MsgContent.MCVoice && file.fileSize <= MAX_VOICE_SIZE_AUTO_RCV && file.fileStatus !is CIFileStatus.RcvAccepted))) {
|
||||||
withApi { receiveFile(rhId, r.user, file.fileId, encrypted = cItem.encryptLocalFile && chatController.appPrefs.privacyEncryptLocalFiles.get(), auto = true) }
|
withApi { receiveFile(rhId, r.user, file.fileId, encrypted = cItem.encryptLocalFile && chatController.appPrefs.privacyEncryptLocalFiles.get(), auto = true) }
|
||||||
}
|
}
|
||||||
if (cItem.showNotification && (allowedToShowNotification() || chatModel.chatId.value != cInfo.id || chatModel.remoteHostId != rhId)) {
|
if (cItem.showNotification && (allowedToShowNotification() || chatModel.chatId.value != cInfo.id || chatModel.remoteHostId() != rhId)) {
|
||||||
ntfManager.notifyMessageReceived(r.user, cInfo, cItem)
|
ntfManager.notifyMessageReceived(r.user, cInfo, cItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1913,7 +1913,7 @@ object ChatController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun activeUser(rhId: Long?, user: UserLike): Boolean =
|
private fun activeUser(rhId: Long?, user: UserLike): Boolean =
|
||||||
rhId == chatModel.remoteHostId && user.userId == chatModel.currentUser.value?.userId
|
rhId == chatModel.remoteHostId() && user.userId == chatModel.currentUser.value?.userId
|
||||||
|
|
||||||
private fun withCall(r: CR, contact: Contact, perform: (Call) -> Unit) {
|
private fun withCall(r: CR, contact: Contact, perform: (Call) -> Unit) {
|
||||||
val call = chatModel.activeCall.value
|
val call = chatModel.activeCall.value
|
||||||
|
@ -54,7 +54,7 @@ private fun sendCommand(chatModel: ChatModel, composeState: MutableState<Compose
|
|||||||
withApi {
|
withApi {
|
||||||
// show "in progress"
|
// show "in progress"
|
||||||
// TODO show active remote host in chat console?
|
// TODO show active remote host in chat console?
|
||||||
chatModel.controller.sendCmd(chatModel.remoteHostId, CC.Console(s))
|
chatModel.controller.sendCmd(chatModel.remoteHostId(), CC.Console(s))
|
||||||
composeState.value = ComposeState(useLinkPreviews = false)
|
composeState.value = ComposeState(useLinkPreviews = false)
|
||||||
// hide "in progress"
|
// hide "in progress"
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ fun CreateFirstProfile(chatModel: ChatModel, close: () -> Unit) {
|
|||||||
|
|
||||||
fun createProfileInProfiles(chatModel: ChatModel, displayName: String, close: () -> Unit) {
|
fun createProfileInProfiles(chatModel: ChatModel, displayName: String, close: () -> Unit) {
|
||||||
withApi {
|
withApi {
|
||||||
val rhId = chatModel.remoteHostId
|
val rhId = chatModel.remoteHostId()
|
||||||
val user = chatModel.controller.apiCreateActiveUser(
|
val user = chatModel.controller.apiCreateActiveUser(
|
||||||
rhId, Profile(displayName.trim(), "", null)
|
rhId, Profile(displayName.trim(), "", null)
|
||||||
) ?: return@withApi
|
) ?: return@withApi
|
||||||
|
@ -17,7 +17,7 @@ fun ScanCodeView(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit, close: ()
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(horizontal = DEFAULT_PADDING)
|
.padding(horizontal = DEFAULT_PADDING)
|
||||||
) {
|
) {
|
||||||
AppBarTitle(stringResource(MR.strings.scan_code), false)
|
AppBarTitle(stringResource(MR.strings.scan_code), withPadding = false)
|
||||||
Box(
|
Box(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
@ -63,7 +63,7 @@ private fun VerifyCodeLayout(
|
|||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
.padding(horizontal = DEFAULT_PADDING)
|
.padding(horizontal = DEFAULT_PADDING)
|
||||||
) {
|
) {
|
||||||
AppBarTitle(stringResource(MR.strings.security_code), false)
|
AppBarTitle(stringResource(MR.strings.security_code), withPadding = false)
|
||||||
val splitCode = splitToParts(connectionCode, 24)
|
val splitCode = splitToParts(connectionCode, 24)
|
||||||
Row(Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF), horizontalArrangement = Arrangement.Center) {
|
Row(Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF), horizontalArrangement = Arrangement.Center) {
|
||||||
if (connectionVerified) {
|
if (connectionVerified) {
|
||||||
|
@ -53,7 +53,7 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf
|
|||||||
val url = chatModel.appOpenUrl.value
|
val url = chatModel.appOpenUrl.value
|
||||||
if (url != null) {
|
if (url != null) {
|
||||||
chatModel.appOpenUrl.value = null
|
chatModel.appOpenUrl.value = null
|
||||||
connectIfOpenedViaUri(chatModel.remoteHostId, url, chatModel)
|
connectIfOpenedViaUri(chatModel.remoteHostId(), url, chatModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (appPlatform.isDesktop) {
|
if (appPlatform.isDesktop) {
|
||||||
|
@ -26,8 +26,7 @@ import chat.simplex.common.model.ChatModel.controller
|
|||||||
import chat.simplex.common.ui.theme.*
|
import chat.simplex.common.ui.theme.*
|
||||||
import chat.simplex.common.views.helpers.*
|
import chat.simplex.common.views.helpers.*
|
||||||
import chat.simplex.common.platform.*
|
import chat.simplex.common.platform.*
|
||||||
import chat.simplex.common.views.remote.ConnectDesktopView
|
import chat.simplex.common.views.remote.*
|
||||||
import chat.simplex.common.views.remote.connectMobileDevice
|
|
||||||
import chat.simplex.res.MR
|
import chat.simplex.res.MR
|
||||||
import dev.icerock.moko.resources.compose.stringResource
|
import dev.icerock.moko.resources.compose.stringResource
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@ -84,7 +83,7 @@ fun UserPicker(
|
|||||||
.filter { it }
|
.filter { it }
|
||||||
.collect {
|
.collect {
|
||||||
try {
|
try {
|
||||||
val updatedUsers = chatModel.controller.listUsers(chatModel.remoteHostId).sortedByDescending { it.user.activeUser }
|
val updatedUsers = chatModel.controller.listUsers(chatModel.remoteHostId()).sortedByDescending { it.user.activeUser }
|
||||||
var same = users.size == updatedUsers.size
|
var same = users.size == updatedUsers.size
|
||||||
if (same) {
|
if (same) {
|
||||||
for (i in 0 until minOf(users.size, updatedUsers.size)) {
|
for (i in 0 until minOf(users.size, updatedUsers.size)) {
|
||||||
@ -213,6 +212,14 @@ fun UserPicker(
|
|||||||
userPickerState.value = AnimatedViewState.GONE
|
userPickerState.value = AnimatedViewState.GONE
|
||||||
}
|
}
|
||||||
Divider(Modifier.requiredHeight(1.dp))
|
Divider(Modifier.requiredHeight(1.dp))
|
||||||
|
} else if (remoteHosts.isEmpty()) {
|
||||||
|
LinkAMobilePickerItem {
|
||||||
|
ModalManager.start.showModal {
|
||||||
|
ConnectMobileView()
|
||||||
|
}
|
||||||
|
userPickerState.value = AnimatedViewState.GONE
|
||||||
|
}
|
||||||
|
Divider(Modifier.requiredHeight(1.dp))
|
||||||
}
|
}
|
||||||
if (showSettings) {
|
if (showSettings) {
|
||||||
SettingsPickerItem(settingsClicked)
|
SettingsPickerItem(settingsClicked)
|
||||||
@ -384,6 +391,16 @@ private fun UseFromDesktopPickerItem(onClick: () -> Unit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun LinkAMobilePickerItem(onClick: () -> Unit) {
|
||||||
|
SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) {
|
||||||
|
val text = generalGetString(MR.strings.link_a_mobile)
|
||||||
|
Icon(painterResource(MR.images.ic_smartphone_300), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
|
||||||
|
Spacer(Modifier.width(DEFAULT_PADDING + 6.dp))
|
||||||
|
Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SettingsPickerItem(onClick: () -> Unit) {
|
private fun SettingsPickerItem(onClick: () -> Unit) {
|
||||||
SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) {
|
SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) {
|
||||||
|
@ -627,7 +627,7 @@ private fun afterSetCiTTL(
|
|||||||
try {
|
try {
|
||||||
updatingChatsMutex.withLock {
|
updatingChatsMutex.withLock {
|
||||||
// this is using current remote host on purpose - if it changes during update, it will load correct chats
|
// this is using current remote host on purpose - if it changes during update, it will load correct chats
|
||||||
val chats = m.controller.apiGetChats(m.remoteHostId)
|
val chats = m.controller.apiGetChats(m.remoteHostId())
|
||||||
m.updateChats(chats)
|
m.updateChats(chats)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -88,7 +88,7 @@ class AlertManager {
|
|||||||
onDismissRequest = { onDismissRequest?.invoke(); hideAlert() },
|
onDismissRequest = { onDismissRequest?.invoke(); hideAlert() },
|
||||||
title = alertTitle(title),
|
title = alertTitle(title),
|
||||||
buttons = {
|
buttons = {
|
||||||
AlertContent(text, hostDevice) {
|
AlertContent(text, hostDevice, true) {
|
||||||
Row(
|
Row(
|
||||||
Modifier.fillMaxWidth().padding(horizontal = DEFAULT_PADDING),
|
Modifier.fillMaxWidth().padding(horizontal = DEFAULT_PADDING),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
@ -14,6 +14,8 @@ import androidx.compose.desktop.ui.tooling.preview.Preview
|
|||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import chat.simplex.common.ui.theme.*
|
import chat.simplex.common.ui.theme.*
|
||||||
|
import chat.simplex.res.MR
|
||||||
|
import dev.icerock.moko.resources.compose.painterResource
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CloseSheetBar(close: (() -> Unit)?, showClose: Boolean = true, endButtons: @Composable RowScope.() -> Unit = {}) {
|
fun CloseSheetBar(close: (() -> Unit)?, showClose: Boolean = true, endButtons: @Composable RowScope.() -> Unit = {}) {
|
||||||
@ -47,23 +49,38 @@ fun CloseSheetBar(close: (() -> Unit)?, showClose: Boolean = true, endButtons: @
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AppBarTitle(title: String, withPadding: Boolean = true, bottomPadding: Dp = DEFAULT_PADDING * 1.5f) {
|
fun AppBarTitle(title: String, hostDevice: Pair<Long?, String>? = null, withPadding: Boolean = true, bottomPadding: Dp = DEFAULT_PADDING * 1.5f) {
|
||||||
val theme = CurrentColors.collectAsState()
|
val theme = CurrentColors.collectAsState()
|
||||||
val titleColor = CurrentColors.collectAsState().value.appColors.title
|
val titleColor = CurrentColors.collectAsState().value.appColors.title
|
||||||
val brush = if (theme.value.base == DefaultTheme.SIMPLEX)
|
val brush = if (theme.value.base == DefaultTheme.SIMPLEX)
|
||||||
Brush.linearGradient(listOf(titleColor.darker(0.2f), titleColor.lighter(0.35f)), Offset(0f, Float.POSITIVE_INFINITY), Offset(Float.POSITIVE_INFINITY, 0f))
|
Brush.linearGradient(listOf(titleColor.darker(0.2f), titleColor.lighter(0.35f)), Offset(0f, Float.POSITIVE_INFINITY), Offset(Float.POSITIVE_INFINITY, 0f))
|
||||||
else // color is not updated when changing themes if I pass null here
|
else // color is not updated when changing themes if I pass null here
|
||||||
Brush.linearGradient(listOf(titleColor, titleColor), Offset(0f, Float.POSITIVE_INFINITY), Offset(Float.POSITIVE_INFINITY, 0f))
|
Brush.linearGradient(listOf(titleColor, titleColor), Offset(0f, Float.POSITIVE_INFINITY), Offset(Float.POSITIVE_INFINITY, 0f))
|
||||||
Text(
|
Column {
|
||||||
title,
|
Text(
|
||||||
Modifier
|
title,
|
||||||
.fillMaxWidth()
|
Modifier
|
||||||
.padding(bottom = bottomPadding, start = if (withPadding) DEFAULT_PADDING else 0.dp, end = if (withPadding) DEFAULT_PADDING else 0.dp,),
|
.fillMaxWidth()
|
||||||
overflow = TextOverflow.Ellipsis,
|
.padding(start = if (withPadding) DEFAULT_PADDING else 0.dp, end = if (withPadding) DEFAULT_PADDING else 0.dp,),
|
||||||
style = MaterialTheme.typography.h1.copy(brush = brush),
|
overflow = TextOverflow.Ellipsis,
|
||||||
color = MaterialTheme.colors.primaryVariant,
|
style = MaterialTheme.typography.h1.copy(brush = brush),
|
||||||
textAlign = TextAlign.Center
|
color = MaterialTheme.colors.primaryVariant,
|
||||||
)
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
if (hostDevice != null) {
|
||||||
|
HostDeviceTitle(hostDevice)
|
||||||
|
}
|
||||||
|
Spacer(Modifier.height(bottomPadding))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun HostDeviceTitle(hostDevice: Pair<Long?, String>, extraPadding: Boolean = false) {
|
||||||
|
Row(Modifier.fillMaxWidth().padding(top = 5.dp, bottom = if (extraPadding) DEFAULT_PADDING * 2 else DEFAULT_PADDING_HALF), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center) {
|
||||||
|
Icon(painterResource(if (hostDevice.first == null) MR.images.ic_desktop else MR.images.ic_smartphone_300), null, Modifier.size(15.dp), tint = MaterialTheme.colors.secondary)
|
||||||
|
Spacer(Modifier.width(10.dp))
|
||||||
|
Text(hostDevice.second, color = MaterialTheme.colors.secondary)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview/*(
|
@Preview/*(
|
||||||
|
@ -373,7 +373,7 @@ inline fun <reified T> serializableSaver(): Saver<T, *> = Saver(
|
|||||||
fun UriHandler.openVerifiedSimplexUri(uri: String) {
|
fun UriHandler.openVerifiedSimplexUri(uri: String) {
|
||||||
val URI = try { URI.create(uri) } catch (e: Exception) { null }
|
val URI = try { URI.create(uri) } catch (e: Exception) { null }
|
||||||
if (URI != null) {
|
if (URI != null) {
|
||||||
connectIfOpenedViaUri(chatModel.remoteHostId, URI, ChatModel)
|
connectIfOpenedViaUri(chatModel.remoteHostId(), URI, ChatModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ fun AddContactLayout(
|
|||||||
.verticalScroll(rememberScrollState()),
|
.verticalScroll(rememberScrollState()),
|
||||||
verticalArrangement = Arrangement.SpaceBetween,
|
verticalArrangement = Arrangement.SpaceBetween,
|
||||||
) {
|
) {
|
||||||
AppBarTitle(stringResource(MR.strings.add_contact))
|
AppBarTitle(stringResource(MR.strings.add_contact), hostDevice(rh?.remoteHostId))
|
||||||
|
|
||||||
SectionView(stringResource(MR.strings.one_time_link_short).uppercase()) {
|
SectionView(stringResource(MR.strings.one_time_link_short).uppercase()) {
|
||||||
if (connReq.isNotEmpty()) {
|
if (connReq.isNotEmpty()) {
|
||||||
|
@ -58,6 +58,7 @@ fun AddGroupView(chatModel: ChatModel, rh: RemoteHostInfo?, close: () -> Unit) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
incognitoPref = chatModel.controller.appPrefs.incognito,
|
incognitoPref = chatModel.controller.appPrefs.incognito,
|
||||||
|
rhId,
|
||||||
close
|
close
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -66,6 +67,7 @@ fun AddGroupView(chatModel: ChatModel, rh: RemoteHostInfo?, close: () -> Unit) {
|
|||||||
fun AddGroupLayout(
|
fun AddGroupLayout(
|
||||||
createGroup: (Boolean, GroupProfile) -> Unit,
|
createGroup: (Boolean, GroupProfile) -> Unit,
|
||||||
incognitoPref: SharedPreference<Boolean>,
|
incognitoPref: SharedPreference<Boolean>,
|
||||||
|
rhId: Long?,
|
||||||
close: () -> Unit
|
close: () -> Unit
|
||||||
) {
|
) {
|
||||||
val bottomSheetModalState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
|
val bottomSheetModalState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
|
||||||
@ -98,7 +100,7 @@ fun AddGroupLayout(
|
|||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
.padding(horizontal = DEFAULT_PADDING)
|
.padding(horizontal = DEFAULT_PADDING)
|
||||||
) {
|
) {
|
||||||
AppBarTitle(stringResource(MR.strings.create_secret_group_title))
|
AppBarTitle(stringResource(MR.strings.create_secret_group_title), hostDevice(rhId))
|
||||||
Box(
|
Box(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@ -174,7 +176,8 @@ fun PreviewAddGroupLayout() {
|
|||||||
AddGroupLayout(
|
AddGroupLayout(
|
||||||
createGroup = { _, _ -> },
|
createGroup = { _, _ -> },
|
||||||
incognitoPref = SharedPreference({ false }, {}),
|
incognitoPref = SharedPreference({ false }, {}),
|
||||||
close = {}
|
close = {},
|
||||||
|
rhId = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,7 @@ fun ContactConnectionInfoView(
|
|||||||
connReq = connReqInvitation,
|
connReq = connReqInvitation,
|
||||||
contactConnection = contactConnection,
|
contactConnection = contactConnection,
|
||||||
focusAlias = focusAlias,
|
focusAlias = focusAlias,
|
||||||
|
rhId = rhId,
|
||||||
deleteConnection = { deleteContactConnectionAlert(rhId, contactConnection, chatModel, close) },
|
deleteConnection = { deleteContactConnectionAlert(rhId, contactConnection, chatModel, close) },
|
||||||
onLocalAliasChanged = { setContactAlias(rhId, contactConnection, it, chatModel) },
|
onLocalAliasChanged = { setContactAlias(rhId, contactConnection, it, chatModel) },
|
||||||
share = { if (connReqInvitation != null) clipboard.shareText(connReqInvitation) },
|
share = { if (connReqInvitation != null) clipboard.shareText(connReqInvitation) },
|
||||||
@ -80,6 +81,7 @@ private fun ContactConnectionInfoLayout(
|
|||||||
connReq: String?,
|
connReq: String?,
|
||||||
contactConnection: PendingContactConnection,
|
contactConnection: PendingContactConnection,
|
||||||
focusAlias: Boolean,
|
focusAlias: Boolean,
|
||||||
|
rhId: Long?,
|
||||||
deleteConnection: () -> Unit,
|
deleteConnection: () -> Unit,
|
||||||
onLocalAliasChanged: (String) -> Unit,
|
onLocalAliasChanged: (String) -> Unit,
|
||||||
share: () -> Unit,
|
share: () -> Unit,
|
||||||
@ -114,7 +116,8 @@ private fun ContactConnectionInfoLayout(
|
|||||||
stringResource(
|
stringResource(
|
||||||
if (contactConnection.initiated) MR.strings.you_invited_a_contact
|
if (contactConnection.initiated) MR.strings.you_invited_a_contact
|
||||||
else MR.strings.you_accepted_connection
|
else MR.strings.you_accepted_connection
|
||||||
)
|
),
|
||||||
|
hostDevice(rhId)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
stringResource(
|
stringResource(
|
||||||
@ -185,6 +188,7 @@ private fun PreviewContactConnectionInfoView() {
|
|||||||
connReq = "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D",
|
connReq = "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D",
|
||||||
contactConnection = PendingContactConnection.getSampleData(),
|
contactConnection = PendingContactConnection.getSampleData(),
|
||||||
focusAlias = false,
|
focusAlias = false,
|
||||||
|
rhId = null,
|
||||||
deleteConnection = {},
|
deleteConnection = {},
|
||||||
onLocalAliasChanged = {},
|
onLocalAliasChanged = {},
|
||||||
share = {},
|
share = {},
|
||||||
|
@ -67,7 +67,7 @@ fun PasteToConnectLayout(
|
|||||||
Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING),
|
Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING),
|
||||||
verticalArrangement = Arrangement.SpaceBetween,
|
verticalArrangement = Arrangement.SpaceBetween,
|
||||||
) {
|
) {
|
||||||
AppBarTitle(stringResource(MR.strings.connect_via_link), false)
|
AppBarTitle(stringResource(MR.strings.connect_via_link), hostDevice(rhId), withPadding = false)
|
||||||
|
|
||||||
Box(Modifier.padding(top = DEFAULT_PADDING, bottom = 6.dp)) {
|
Box(Modifier.padding(top = DEFAULT_PADDING, bottom = 6.dp)) {
|
||||||
TextEditor(
|
TextEditor(
|
||||||
|
@ -469,7 +469,7 @@ fun ConnectContactLayout(
|
|||||||
Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING),
|
Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING),
|
||||||
verticalArrangement = Arrangement.SpaceBetween
|
verticalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
AppBarTitle(stringResource(MR.strings.scan_QR_code), false)
|
AppBarTitle(stringResource(MR.strings.scan_QR_code), hostDevice(rh?.remoteHostId), withPadding = false)
|
||||||
Box(
|
Box(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
@ -26,7 +26,7 @@ fun HowItWorks(user: User?, onboardingStage: SharedPreference<OnboardingStage>?
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = DEFAULT_PADDING),
|
.padding(horizontal = DEFAULT_PADDING),
|
||||||
) {
|
) {
|
||||||
AppBarTitle(stringResource(MR.strings.how_simplex_works), false)
|
AppBarTitle(stringResource(MR.strings.how_simplex_works), withPadding = false)
|
||||||
ReadableText(MR.strings.many_people_asked_how_can_it_deliver)
|
ReadableText(MR.strings.many_people_asked_how_can_it_deliver)
|
||||||
ReadableText(MR.strings.to_protect_privacy_simplex_has_ids_for_queues)
|
ReadableText(MR.strings.to_protect_privacy_simplex_has_ids_for_queues)
|
||||||
ReadableText(MR.strings.you_control_servers_to_receive_your_contacts_to_send)
|
ReadableText(MR.strings.you_control_servers_to_receive_your_contacts_to_send)
|
||||||
|
@ -36,12 +36,10 @@ import dev.icerock.moko.resources.compose.painterResource
|
|||||||
import dev.icerock.moko.resources.compose.stringResource
|
import dev.icerock.moko.resources.compose.stringResource
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ConnectMobileView(
|
fun ConnectMobileView() {
|
||||||
m: ChatModel
|
|
||||||
) {
|
|
||||||
val connecting = rememberSaveable() { mutableStateOf(false) }
|
val connecting = rememberSaveable() { mutableStateOf(false) }
|
||||||
val remoteHosts = remember { chatModel.remoteHosts }
|
val remoteHosts = remember { chatModel.remoteHosts }
|
||||||
val deviceName = m.controller.appPrefs.deviceNameForRemoteAccess
|
val deviceName = chatModel.controller.appPrefs.deviceNameForRemoteAccess
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
controller.reloadRemoteHosts()
|
controller.reloadRemoteHosts()
|
||||||
}
|
}
|
||||||
@ -49,11 +47,11 @@ fun ConnectMobileView(
|
|||||||
deviceName = remember { deviceName.state },
|
deviceName = remember { deviceName.state },
|
||||||
remoteHosts = remoteHosts,
|
remoteHosts = remoteHosts,
|
||||||
connecting,
|
connecting,
|
||||||
connectedHost = remember { m.currentRemoteHost },
|
connectedHost = remember { chatModel.currentRemoteHost },
|
||||||
updateDeviceName = {
|
updateDeviceName = {
|
||||||
withBGApi {
|
withBGApi {
|
||||||
if (it != "") {
|
if (it != "") {
|
||||||
m.controller.setLocalDeviceName(it)
|
chatModel.controller.setLocalDeviceName(it)
|
||||||
deviceName.set(it)
|
deviceName.set(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ fun HelpLayout(userDisplayName: String) {
|
|||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
.padding(horizontal = DEFAULT_PADDING),
|
.padding(horizontal = DEFAULT_PADDING),
|
||||||
){
|
){
|
||||||
AppBarTitle(String.format(stringResource(MR.strings.personal_welcome), userDisplayName), false)
|
AppBarTitle(String.format(stringResource(MR.strings.personal_welcome), userDisplayName), withPadding = false)
|
||||||
ChatHelpView()
|
ChatHelpView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,13 +29,12 @@ import kotlinx.coroutines.launch
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ProtocolServersView(m: ChatModel, rhId: Long?, serverProtocol: ServerProtocol, close: () -> Unit) {
|
fun ProtocolServersView(m: ChatModel, rhId: Long?, serverProtocol: ServerProtocol, close: () -> Unit) {
|
||||||
// TODO close if remote host changes
|
var presetServers by remember(rhId) { mutableStateOf(emptyList<String>()) }
|
||||||
var presetServers by remember { mutableStateOf(emptyList<String>()) }
|
var servers by remember(rhId) {
|
||||||
var servers by remember {
|
|
||||||
mutableStateOf(m.userSMPServersUnsaved.value ?: emptyList())
|
mutableStateOf(m.userSMPServersUnsaved.value ?: emptyList())
|
||||||
}
|
}
|
||||||
val currServers = remember { mutableStateOf(servers) }
|
val currServers = remember(rhId) { mutableStateOf(servers) }
|
||||||
val testing = rememberSaveable { mutableStateOf(false) }
|
val testing = rememberSaveable(rhId) { mutableStateOf(false) }
|
||||||
val serversUnchanged = remember { derivedStateOf { servers == currServers.value || testing.value } }
|
val serversUnchanged = remember { derivedStateOf { servers == currServers.value || testing.value } }
|
||||||
val allServersDisabled = remember { derivedStateOf { servers.all { !it.enabled } } }
|
val allServersDisabled = remember { derivedStateOf { servers.all { !it.enabled } } }
|
||||||
val saveDisabled = remember {
|
val saveDisabled = remember {
|
||||||
@ -51,7 +50,12 @@ fun ProtocolServersView(m: ChatModel, rhId: Long?, serverProtocol: ServerProtoco
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
KeyChangeEffect(rhId) {
|
||||||
|
m.userSMPServersUnsaved.value = null
|
||||||
|
servers = emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(rhId) {
|
||||||
val res = m.controller.getUserProtoServers(rhId, serverProtocol)
|
val res = m.controller.getUserProtoServers(rhId, serverProtocol)
|
||||||
if (res != null) {
|
if (res != null) {
|
||||||
currServers.value = res.protoServers
|
currServers.value = res.protoServers
|
||||||
|
@ -22,7 +22,7 @@ fun ScanProtocolServerLayout(rhId: Long?, onNext: (ServerCfg) -> Unit) {
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(horizontal = DEFAULT_PADDING)
|
.padding(horizontal = DEFAULT_PADDING)
|
||||||
) {
|
) {
|
||||||
AppBarTitle(stringResource(MR.strings.smp_servers_scan_qr), false)
|
AppBarTitle(stringResource(MR.strings.smp_servers_scan_qr), withPadding = false)
|
||||||
Box(
|
Box(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
@ -158,7 +158,7 @@ fun SettingsLayout(
|
|||||||
SettingsActionItem(painterResource(MR.images.ic_qr_code), stringResource(MR.strings.your_simplex_contact_address), showCustomModal { it, close -> UserAddressView(it, it.currentUser.value?.remoteHostId, shareViaProfile = it.currentUser.value!!.addressShared, close = close) }, disabled = stopped, extraPadding = true)
|
SettingsActionItem(painterResource(MR.images.ic_qr_code), stringResource(MR.strings.your_simplex_contact_address), showCustomModal { it, close -> UserAddressView(it, it.currentUser.value?.remoteHostId, shareViaProfile = it.currentUser.value!!.addressShared, close = close) }, disabled = stopped, extraPadding = true)
|
||||||
ChatPreferencesItem(showCustomModal, stopped = stopped)
|
ChatPreferencesItem(showCustomModal, stopped = stopped)
|
||||||
if (appPlatform.isDesktop) {
|
if (appPlatform.isDesktop) {
|
||||||
SettingsActionItem(painterResource(MR.images.ic_smartphone), stringResource(if (remember { chatModel.remoteHosts }.isEmpty()) MR.strings.link_a_mobile else MR.strings.linked_mobiles), showModal { ConnectMobileView(it) }, disabled = stopped, extraPadding = true)
|
SettingsActionItem(painterResource(MR.images.ic_smartphone), stringResource(if (remember { chatModel.remoteHosts }.isEmpty()) MR.strings.link_a_mobile else MR.strings.linked_mobiles), showModal { ConnectMobileView() }, disabled = stopped, extraPadding = true)
|
||||||
} else {
|
} else {
|
||||||
SettingsActionItem(painterResource(MR.images.ic_desktop), stringResource(MR.strings.settings_section_title_use_from_desktop), showCustomModal{ it, close -> ConnectDesktopView(close) }, disabled = stopped, extraPadding = true)
|
SettingsActionItem(painterResource(MR.images.ic_desktop), stringResource(MR.strings.settings_section_title_use_from_desktop), showCustomModal{ it, close -> ConnectDesktopView(close) }, disabled = stopped, extraPadding = true)
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,7 @@ fun UserAddressView(
|
|||||||
UserAddressLayout(
|
UserAddressLayout(
|
||||||
userAddress = userAddress.value,
|
userAddress = userAddress.value,
|
||||||
shareViaProfile,
|
shareViaProfile,
|
||||||
|
rhId,
|
||||||
onCloseHandler,
|
onCloseHandler,
|
||||||
createAddress = {
|
createAddress = {
|
||||||
withApi {
|
withApi {
|
||||||
@ -169,6 +170,7 @@ fun UserAddressView(
|
|||||||
private fun UserAddressLayout(
|
private fun UserAddressLayout(
|
||||||
userAddress: UserContactLinkRec?,
|
userAddress: UserContactLinkRec?,
|
||||||
shareViaProfile: MutableState<Boolean>,
|
shareViaProfile: MutableState<Boolean>,
|
||||||
|
rhId: Long?,
|
||||||
onCloseHandler: MutableState<(close: () -> Unit) -> Unit>,
|
onCloseHandler: MutableState<(close: () -> Unit) -> Unit>,
|
||||||
createAddress: () -> Unit,
|
createAddress: () -> Unit,
|
||||||
learnMore: () -> Unit,
|
learnMore: () -> Unit,
|
||||||
@ -181,7 +183,7 @@ private fun UserAddressLayout(
|
|||||||
Column(
|
Column(
|
||||||
Modifier.verticalScroll(rememberScrollState()),
|
Modifier.verticalScroll(rememberScrollState()),
|
||||||
) {
|
) {
|
||||||
AppBarTitle(stringResource(MR.strings.simplex_address), false)
|
AppBarTitle(stringResource(MR.strings.simplex_address), hostDevice(rhId), withPadding = false)
|
||||||
Column(
|
Column(
|
||||||
Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF),
|
Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
@ -438,6 +440,7 @@ fun PreviewUserAddressLayoutNoAddress() {
|
|||||||
setProfileAddress = { _ -> },
|
setProfileAddress = { _ -> },
|
||||||
learnMore = {},
|
learnMore = {},
|
||||||
shareViaProfile = remember { mutableStateOf(false) },
|
shareViaProfile = remember { mutableStateOf(false) },
|
||||||
|
rhId = null,
|
||||||
onCloseHandler = remember { mutableStateOf({}) },
|
onCloseHandler = remember { mutableStateOf({}) },
|
||||||
sendEmail = {},
|
sendEmail = {},
|
||||||
)
|
)
|
||||||
@ -471,6 +474,7 @@ fun PreviewUserAddressLayoutAddressCreated() {
|
|||||||
setProfileAddress = { _ -> },
|
setProfileAddress = { _ -> },
|
||||||
learnMore = {},
|
learnMore = {},
|
||||||
shareViaProfile = remember { mutableStateOf(false) },
|
shareViaProfile = remember { mutableStateOf(false) },
|
||||||
|
rhId = null,
|
||||||
onCloseHandler = remember { mutableStateOf({}) },
|
onCloseHandler = remember { mutableStateOf({}) },
|
||||||
sendEmail = {},
|
sendEmail = {},
|
||||||
)
|
)
|
||||||
|
@ -18,7 +18,7 @@ fun VersionInfoView(info: CoreVersionInfo) {
|
|||||||
Column(
|
Column(
|
||||||
Modifier.padding(horizontal = DEFAULT_PADDING),
|
Modifier.padding(horizontal = DEFAULT_PADDING),
|
||||||
) {
|
) {
|
||||||
AppBarTitle(stringResource(MR.strings.app_version_title), false)
|
AppBarTitle(stringResource(MR.strings.app_version_title), withPadding = false)
|
||||||
if (appPlatform.isAndroid) {
|
if (appPlatform.isAndroid) {
|
||||||
Text(String.format(stringResource(MR.strings.app_version_name), BuildConfigCommon.ANDROID_VERSION_NAME))
|
Text(String.format(stringResource(MR.strings.app_version_name), BuildConfigCommon.ANDROID_VERSION_NAME))
|
||||||
Text(String.format(stringResource(MR.strings.app_version_code), BuildConfigCommon.ANDROID_VERSION_CODE))
|
Text(String.format(stringResource(MR.strings.app_version_code), BuildConfigCommon.ANDROID_VERSION_CODE))
|
||||||
|
Loading…
Reference in New Issue
Block a user