Added screens and implementations mostly with ai

This commit is contained in:
hayk888997
2026-02-23 05:06:47 +04:00
parent be5ec4b471
commit bfbb7955de
16 changed files with 1377 additions and 267 deletions
@@ -0,0 +1,136 @@
package chat.simplex.app.views.invitation_redesign
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontWeight
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.ChatController.appPrefs
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.newchat.*
import chat.simplex.res.MR
@Composable
fun ConnectBannerCard() {
val closeAll = { ModalManager.start.closeModals() }
Surface(
shape = RoundedCornerShape(18.dp),
color = MaterialTheme.appColors.sentMessage,
modifier = Modifier.fillMaxWidth()
) {
Box {
Column {
Row(
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Image(
painterResource(MR.images.ic_invitation_card_invite_someone),
contentDescription = stringResource(MR.strings.create_link_or_qr),
modifier = Modifier
.weight(1f)
.clickable {
ModalManager.start.showModalCloseable(endButtons = { AddContactLearnMoreButton() }) { _ ->
NewChatView(chatModel.currentRemoteHost.value, NewChatOption.INVITE, close = closeAll)
}
},
contentScale = ContentScale.FillWidth
)
Image(
painterResource(MR.images.ic_invitation_card_one_time_link),
contentDescription = stringResource(MR.strings.paste_link_scan),
modifier = Modifier
.weight(1f)
.clickable {
ModalManager.start.showModalCloseable(endButtons = { AddContactLearnMoreButton() }) { _ ->
NewChatView(chatModel.currentRemoteHost.value, NewChatOption.CONNECT, showQRCodeScanner = appPlatform.isAndroid, close = closeAll)
}
},
contentScale = ContentScale.FillWidth
)
}
Divider(color = MaterialTheme.colors.onSurface.copy(alpha = 0.06f))
Row(
Modifier.fillMaxWidth().padding(vertical = DEFAULT_PADDING_HALF),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Row(
Modifier
.weight(1f)
.clickable {
ModalManager.start.showModalCloseable(endButtons = { AddContactLearnMoreButton() }) { _ ->
NewChatView(chatModel.currentRemoteHost.value, NewChatOption.INVITE, close = closeAll)
}
},
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painterResource(MR.images.ic_repeat_one),
contentDescription = null,
modifier = Modifier.size(18.dp),
tint = MaterialTheme.colors.secondary
)
Spacer(Modifier.width(DEFAULT_PADDING_HALF))
Text(
stringResource(MR.strings.create_link_or_qr),
style = MaterialTheme.typography.body2.copy(fontWeight = FontWeight.Medium),
)
}
Row(
Modifier
.weight(1f)
.clickable {
ModalManager.start.showModalCloseable(endButtons = { AddContactLearnMoreButton() }) { _ ->
NewChatView(chatModel.currentRemoteHost.value, NewChatOption.CONNECT, showQRCodeScanner = appPlatform.isAndroid, close = closeAll)
}
},
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painterResource(MR.images.ic_qr_code),
contentDescription = null,
modifier = Modifier.size(18.dp),
tint = MaterialTheme.colors.secondary
)
Spacer(Modifier.width(DEFAULT_PADDING_HALF))
Text(
stringResource(MR.strings.paste_link_scan),
style = MaterialTheme.typography.body2.copy(fontWeight = FontWeight.Medium),
)
}
}
}
IconButton(
onClick = { appPrefs.connectBannerCardShown.set(true) },
modifier = Modifier.align(Alignment.TopEnd).padding(4.dp)
) {
Icon(
painterResource(MR.images.ic_close),
stringResource(MR.strings.back),
tint = MaterialTheme.colors.secondary
)
}
}
}
}
@Preview
@Composable
fun PreviewConnectBannerCard() {
SimpleXTheme {
ConnectBannerCard()
}
}
@@ -0,0 +1,147 @@
package chat.simplex.app.views.invitation_redesign
import SectionBottomSpacer
import SectionItemView
import SectionView
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
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.*
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.chat.item.CIFileViewScope
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.newchat.*
import chat.simplex.res.MR
@Composable
fun ModalData.ConnectViewLinkOrQrModal(rhId: Long?, close: () -> Unit) {
val showQRCodeScanner = remember { stateGetOrPut("showQRCodeScanner") { true } }
val pastedLink = rememberSaveable { mutableStateOf("") }
DisposableEffect(Unit) {
onDispose {
connectProgressManager.cancelConnectProgress()
}
}
ModalView(close) {
ColumnWithScrollBar(
Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
AppBarTitle(stringResource(MR.strings.connect_via_link), withPadding = false)
Spacer(Modifier.height(DEFAULT_PADDING))
Icon(
painterResource(MR.images.ic_add_link),
contentDescription = null,
modifier = Modifier.size(80.dp),
tint = MaterialTheme.colors.primary
)
Spacer(Modifier.height(DEFAULT_PADDING * 1.5f))
SectionView(stringResource(MR.strings.paste_the_link_you_received).uppercase(), headerBottomPadding = 5.dp) {
ConnectPasteLinkView(rhId, pastedLink, showQRCodeScanner, close)
}
if (appPlatform.isAndroid) {
Spacer(Modifier.height(10.dp))
SectionView(stringResource(MR.strings.or_scan_qr_code).uppercase(), headerBottomPadding = 5.dp) {
Box(Modifier.clip(RoundedCornerShape(DEFAULT_PADDING))) {
QRCodeScanner(showQRCodeScanner) { text ->
val linkVerified = strIsSimplexLink(text)
if (!linkVerified) {
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.invalid_qr_code),
text = generalGetString(MR.strings.code_you_scanned_is_not_simplex_link_qr_code)
)
}
connectFromScanner(rhId, text, close)
}
}
}
}
SectionBottomSpacer()
}
}
}
@Composable
private fun ConnectPasteLinkView(rhId: Long?, pastedLink: MutableState<String>, showQRCodeScanner: MutableState<Boolean>, close: () -> Unit) {
if (pastedLink.value.isEmpty()) {
val clipboard = LocalClipboardManager.current
SectionItemView({
val str = clipboard.getText()?.text ?: return@SectionItemView
val link = strHasSingleSimplexLink(str.trim())
if (link != null) {
pastedLink.value = link.text
showQRCodeScanner.value = false
withBGApi {
connectFromPaste(rhId, link.text, close) { pastedLink.value = "" }
}
} else {
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.invalid_contact_link),
text = generalGetString(MR.strings.the_text_you_pasted_is_not_a_link)
)
}
}) {
Box(Modifier.weight(1f)) {
Text(stringResource(MR.strings.tap_to_paste_link))
}
if (connectProgressManager.showConnectProgress != null) {
CIFileViewScope.progressIndicator(sizeMultiplier = 0.6f)
}
}
} else {
Row(
Modifier.padding(end = DEFAULT_PADDING),
verticalAlignment = Alignment.CenterVertically
) {
Box(Modifier.weight(1f)) {
LinkTextView(pastedLink.value, false)
}
if (connectProgressManager.showConnectProgress != null) {
CIFileViewScope.progressIndicator(sizeMultiplier = 0.6f)
}
}
}
}
private suspend fun connectFromScanner(rhId: Long?, text: String?, close: () -> Unit): Boolean {
if (text != null && strIsSimplexLink(text)) {
return connectFromPaste(rhId, text, close)
}
return false
}
private suspend fun connectFromPaste(rhId: Long?, link: String, close: () -> Unit, cleanup: (() -> Unit)? = null): Boolean =
planAndConnect(
rhId,
link,
close = close,
cleanup = cleanup
).await()
@Preview
@Composable
fun PreviewConnectViewLinkOrQrModal() {
SimpleXTheme {
ModalData().ConnectViewLinkOrQrModal(rhId = null, close = {})
}
}
@@ -0,0 +1,141 @@
package chat.simplex.app.views.invitation_redesign
import SectionBottomSpacer
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
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.text.font.FontWeight
import androidx.compose.ui.unit.dp
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.newchat.*
import chat.simplex.res.MR
@Composable
fun BoxScope.EmptyChatListView() {
var showInviteSomeone by remember { mutableStateOf(false) }
if (showInviteSomeone) {
BackHandler { showInviteSomeone = false }
Column(
Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
Row(Modifier.fillMaxWidth()) {
NavigationButtonBack(onButtonClicked = { showInviteSomeone = false })
}
Text(
stringResource(MR.strings.invite_someone),
style = MaterialTheme.typography.h1.copy(fontWeight = FontWeight.Bold),
)
Spacer(Modifier.height(DEFAULT_PADDING))
InviteSomeoneContent()
SectionBottomSpacer()
}
} else {
val closeAll = { ModalManager.start.closeModals() }
Column(
Modifier
.align(Alignment.Center)
.fillMaxWidth()
.padding(horizontal = DEFAULT_PADDING),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
stringResource(MR.strings.now_you_can),
style = MaterialTheme.typography.h1.copy(fontWeight = FontWeight.Bold),
)
Spacer(Modifier.height(DEFAULT_PADDING))
Surface(
shape = RoundedCornerShape(18.dp),
color = MaterialTheme.appColors.sentMessage,
modifier = Modifier.fillMaxWidth().clickable {
showInviteSomeone = true
}
) {
Column(
Modifier.fillMaxWidth().padding(DEFAULT_PADDING),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painterResource(MR.images.ic_invitation_card_invite_someone),
contentDescription = null,
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
painterResource(MR.images.ic_repeat_one),
contentDescription = null,
modifier = Modifier.size(18.dp),
tint = MaterialTheme.colors.secondary
)
Spacer(Modifier.width(DEFAULT_PADDING_HALF))
Text(
stringResource(MR.strings.invite_someone_to_chat),
style = MaterialTheme.typography.body1.copy(fontWeight = FontWeight.Medium),
)
}
}
}
Spacer(Modifier.height(DEFAULT_PADDING))
Surface(
shape = RoundedCornerShape(18.dp),
color = MaterialTheme.appColors.sentMessage,
modifier = Modifier.fillMaxWidth().clickable {
ModalManager.start.showModalCloseable(endButtons = { AddContactLearnMoreButton() }) { _ ->
NewChatView(chatModel.currentRemoteHost.value, NewChatOption.CONNECT, showQRCodeScanner = appPlatform.isAndroid, close = closeAll)
}
}
) {
Column(
Modifier.fillMaxWidth().padding(DEFAULT_PADDING),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painterResource(MR.images.ic_invitation_card_one_time_link),
contentDescription = null,
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
painterResource(MR.images.ic_qr_code),
contentDescription = null,
modifier = Modifier.size(18.dp),
tint = MaterialTheme.colors.secondary
)
Spacer(Modifier.width(DEFAULT_PADDING_HALF))
Text(
stringResource(MR.strings.connect_via_link_or_qr),
style = MaterialTheme.typography.body1.copy(fontWeight = FontWeight.Medium),
)
}
}
}
}
}
}
@Preview
@Composable
fun PreviewEmptyChatListView() {
SimpleXTheme {
Box(Modifier.fillMaxSize()) {
EmptyChatListView()
}
}
}
@@ -0,0 +1,160 @@
package chat.simplex.app.views.invitation_redesign
import SectionBottomSpacer
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.invitation_redesign.OneTimeLinkView
import chat.simplex.common.views.usersettings.UserAddressView
import chat.simplex.res.MR
@Composable
fun InviteSomeoneView(close: () -> Unit) {
ModalView(close) {
ColumnWithScrollBar(
Modifier.fillMaxSize().background(Color.White),
horizontalAlignment = Alignment.CenterHorizontally
) {
AppBarTitle(stringResource(MR.strings.invite_someone), withPadding = false)
Spacer(Modifier.height(DEFAULT_PADDING))
InviteSomeoneContent()
SectionBottomSpacer()
}
}
}
@Composable
fun InviteSomeoneContent() {
Surface(
shape = RoundedCornerShape(18.dp),
color = MaterialTheme.appColors.sentMessage,
modifier = Modifier
.fillMaxSize().background(Color.White)
.padding(horizontal = DEFAULT_PADDING)
.clickable {
ModalManager.start.showModalCloseable { close ->
OneTimeLinkView(rhId = chatModel.currentRemoteHost.value?.remoteHostId, close = close)
}
}
) {
Column(
Modifier.fillMaxWidth().padding(DEFAULT_PADDING),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painterResource(MR.images.ic_invitation_card_one_time_link),
contentDescription = null,
modifier = Modifier.fillMaxWidth()
)
}
}
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
Row(
Modifier.fillMaxWidth().padding(horizontal = DEFAULT_PADDING),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painterResource(MR.images.ic_repeat_one),
contentDescription = null,
modifier = Modifier.size(20.dp),
tint = MaterialTheme.colors.secondary
)
Spacer(Modifier.width(DEFAULT_PADDING_HALF))
Column {
Text(
stringResource(MR.strings.create_private_1_time_link),
style = MaterialTheme.typography.h3.copy(fontWeight = FontWeight.Bold),
)
Text(
stringResource(MR.strings.contact_can_use_link_or_scan_qr),
style = MaterialTheme.typography.body2,
color = MaterialTheme.colors.secondary
)
}
}
Spacer(Modifier.height(DEFAULT_PADDING * 1.5f))
Surface(
shape = RoundedCornerShape(18.dp),
color = MaterialTheme.appColors.sentMessage,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = DEFAULT_PADDING)
.clickable {
ModalManager.start.showModalCloseable { closeAddress ->
UserAddressView(chatModel = chatModel, shareViaProfile = false, autoCreateAddress = true, close = closeAddress)
}
}
) {
Column(
Modifier.fillMaxWidth().padding(DEFAULT_PADDING),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painterResource(MR.images.ic_invitation_card_public_address),
contentDescription = null,
modifier = Modifier.fillMaxWidth()
)
}
}
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
Row(
Modifier.fillMaxWidth().padding(horizontal = DEFAULT_PADDING),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painterResource(MR.images.ic_qr_code),
contentDescription = null,
modifier = Modifier.size(20.dp),
tint = MaterialTheme.colors.secondary
)
Spacer(Modifier.width(DEFAULT_PADDING_HALF))
Column {
Text(
stringResource(MR.strings.create_public_simplex_address),
style = MaterialTheme.typography.h3.copy(fontWeight = FontWeight.Bold),
)
Text(
stringResource(MR.strings.public_link_for_social_media_email_or_website),
style = MaterialTheme.typography.body2,
color = MaterialTheme.colors.secondary
)
}
}
}
@Preview
@Composable
fun PreviewInviteSomeoneView() {
SimpleXTheme {
ColumnWithScrollBar(
Modifier.fillMaxSize().background(Color.White),
horizontalAlignment = Alignment.CenterHorizontally
) {
AppBarTitle(stringResource(MR.strings.invite_someone), withPadding = false)
Spacer(Modifier.height(DEFAULT_PADDING))
InviteSomeoneContent()
SectionBottomSpacer()
}
}
}
@@ -0,0 +1,219 @@
package chat.simplex.app.views.invitation_redesign
import SectionBottomSpacer
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextOverflow
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.*
import chat.simplex.common.model.ChatModel.controller
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
import chat.simplex.common.views.newchat.*
import chat.simplex.res.MR
import kotlinx.coroutines.*
@Composable
fun OneTimeLinkView(rhId: Long?, close: () -> Unit) {
val contactConnection: MutableState<PendingContactConnection?> = rememberSaveable(stateSaver = serializableSaver()) { mutableStateOf(chatModel.showingInvitation.value?.conn) }
val connLinkInvitation by remember { derivedStateOf { chatModel.showingInvitation.value?.connLink ?: CreatedConnLink("", null) } }
val creatingConnReq = rememberSaveable { mutableStateOf(false) }
LaunchedEffect(Unit) {
if (
connLinkInvitation.connFullLink.isEmpty()
&& contactConnection.value == null
&& !creatingConnReq.value
) {
creatingConnReq.value = true
withBGApi {
val (r, alert) = controller.apiAddContact(rhId, incognito = controller.appPrefs.incognito.get())
if (r != null) {
withContext(Dispatchers.Main) {
chatModel.chatsContext.updateContactConnection(rhId, r.second)
chatModel.showingInvitation.value = ShowingInvitation(connId = r.second.id, connLink = r.first, connChatUsed = false, conn = r.second)
contactConnection.value = r.second
}
} else {
creatingConnReq.value = false
if (alert != null) {
alert()
}
}
}
}
}
DisposableEffect(Unit) {
onDispose {
if (chatModel.showingInvitation.value != null && ModalManager.start.openModalCount() <= 1) {
val conn = contactConnection.value
if (chatModel.showingInvitation.value?.connChatUsed == false && conn != null) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.keep_unused_invitation_question),
text = generalGetString(MR.strings.you_can_view_invitation_link_again),
confirmText = generalGetString(MR.strings.delete_verb),
dismissText = generalGetString(MR.strings.keep_invitation_link),
destructive = true,
onConfirm = {
withBGApi {
val chatInfo = ChatInfo.ContactConnection(conn)
controller.deleteChat(Chat(remoteHostId = rhId, chatInfo = chatInfo, chatItems = listOf()))
if (chatModel.chatId.value == chatInfo.id) {
chatModel.chatId.value = null
ModalManager.start.closeModals()
}
}
}
)
}
chatModel.showingInvitation.value = null
}
}
}
ModalView(close) {
OneTimeLinkContent(connLinkInvitation)
}
}
@Composable
fun OneTimeLinkContent(connLinkInvitation: CreatedConnLink) {
val showShortLink = remember { mutableStateOf(true) }
ColumnWithScrollBar(
Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(Modifier.height(DEFAULT_PADDING))
Image(
painterResource(MR.images.ic_invitation_one_time_link),
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = DEFAULT_PADDING * 3)
)
Spacer(Modifier.height(DEFAULT_PADDING))
Text(
stringResource(MR.strings.send_1_time_link_description),
style = MaterialTheme.typography.body1,
color = MaterialTheme.colors.secondary,
modifier = Modifier.padding(horizontal = DEFAULT_PADDING)
)
Spacer(Modifier.height(DEFAULT_PADDING))
if (connLinkInvitation.connFullLink.isNotEmpty()) {
OneTimeLinkBar(connLinkInvitation, showShortLink.value)
Spacer(Modifier.height(DEFAULT_PADDING))
Text(
stringResource(MR.strings.or_show_qr_code_in_person_or_video_call),
style = MaterialTheme.typography.body1,
color = MaterialTheme.colors.secondary,
modifier = Modifier.padding(horizontal = DEFAULT_PADDING)
)
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
Surface(
shape = RoundedCornerShape(18.dp),
color = MaterialTheme.colors.background,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = DEFAULT_PADDING)
) {
SimpleXCreatedLinkQRCode(
connLinkInvitation,
short = showShortLink.value,
onShare = { chatModel.markShowingInvitationUsed() }
)
}
} else {
Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
CircularProgressIndicator(
Modifier.size(36.dp).padding(4.dp),
color = MaterialTheme.colors.secondary,
strokeWidth = 3.dp
)
}
}
SectionBottomSpacer()
}
}
@Composable
private fun OneTimeLinkBar(connLinkInvitation: CreatedConnLink, short: Boolean) {
val clipboard = LocalClipboardManager.current
val link = connLinkInvitation.simplexChatUri(short)
Surface(
shape = RoundedCornerShape(24.dp),
color = MaterialTheme.appColors.sentMessage,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = DEFAULT_PADDING)
) {
Row(
Modifier
.padding(start = DEFAULT_PADDING, end = 4.dp)
.heightIn(min = 48.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
link,
style = MaterialTheme.typography.body2,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f)
)
IconButton(onClick = {
chatModel.markShowingInvitationUsed()
clipboard.setText(AnnotatedString(simplexChatLink(link)))
}) {
Icon(
painterResource(MR.images.ic_content_copy),
contentDescription = stringResource(MR.strings.copy_verb),
tint = MaterialTheme.colors.primary
)
}
IconButton(onClick = {
chatModel.markShowingInvitationUsed()
clipboard.shareText(simplexChatLink(link))
}) {
Icon(
painterResource(MR.images.ic_share),
contentDescription = stringResource(MR.strings.share_verb),
tint = MaterialTheme.colors.primary
)
}
}
}
}
@Preview
@Composable
fun PreviewOneTimeLinkView() {
SimpleXTheme {
OneTimeLinkContent(
connLinkInvitation = CreatedConnLink("https://smp16.simplex.im/i#pT0CA_nnqmLA", null)
)
}
}