ui: offer to upgrade address and group link when sharing it (#6114)

* ios: offer to upgrade address and group link when sharing it

* android

* update button
This commit is contained in:
Evgeny
2025-07-27 23:22:36 +01:00
committed by GitHub
parent 890fccf92f
commit 6585875e92
32 changed files with 966 additions and 664 deletions
@@ -6732,12 +6732,20 @@ enum class RatchetSyncState {
@SerialName("agreed") Agreed
}
interface SimplexAddress {
val connLinkContact: CreatedConnLink
val shortLinkDataSet: Boolean
// TODO update condition
val shouldBeUpgraded: Boolean get() = connLinkContact.connShortLink == null || !shortLinkDataSet
}
@Serializable
data class UserContactLinkRec(
val connLinkContact: CreatedConnLink,
val shortLinkDataSet: Boolean,
override val connLinkContact: CreatedConnLink,
override val shortLinkDataSet: Boolean,
val addressSettings: AddressSettings
)
): SimplexAddress
@Serializable
data class AddressSettings(
@@ -6752,11 +6760,11 @@ data class AutoAccept(val acceptIncognito: Boolean)
@Serializable
data class GroupLink(
val userContactLinkId: Long,
val connLinkContact: CreatedConnLink,
val shortLinkDataSet: Boolean,
override val connLinkContact: CreatedConnLink,
override val shortLinkDataSet: Boolean,
val groupLinkId: String,
val acceptMemberRole: GroupMemberRole
) {
): SimplexAddress {
companion object {
val nullableStateSaver: Saver<GroupLink?, List<Any?>> = Saver(
save = { groupLink ->
@@ -1,8 +1,8 @@
package chat.simplex.common.views.chat.group
import SectionBottomSpacer
import SectionItemView
import SectionViewWithButton
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
@@ -11,6 +11,7 @@ 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.text.style.TextAlign
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
@@ -36,6 +37,7 @@ fun GroupLinkView(
var groupLinkVar by rememberSaveable(stateSaver = GroupLink.nullableStateSaver) { mutableStateOf(groupLink) }
val groupLinkMemberRole = rememberSaveable { mutableStateOf(groupLink?.acceptMemberRole) }
var creatingLink by rememberSaveable { mutableStateOf(false) }
val clipboard = LocalClipboardManager.current
fun createLink() {
creatingLink = true
withBGApi {
@@ -48,7 +50,7 @@ fun GroupLinkView(
creatingLink = false
}
}
fun addShortLink() {
fun addShortLink(shareOnCompletion: Boolean = false) {
creatingLink = true
withBGApi {
val link = chatModel.controller.apiAddGroupShortLink(rhId, groupInfo.groupId)
@@ -56,10 +58,60 @@ fun GroupLinkView(
groupLinkVar = link
groupLinkMemberRole.value = link.acceptMemberRole
onGroupLinkUpdated?.invoke(link)
if (shareOnCompletion) {
clipboard.shareText(link.connLinkContact.simplexChatUri(short = true))
}
}
creatingLink = false
}
}
fun showAddShortLinkAlert(shareAddress: (() -> Unit)? = null) {
AlertManager.shared.showAlertDialogButtonsColumn(
title = generalGetString(MR.strings.share_group_profile_via_link),
text = generalGetString(MR.strings.share_group_profile_via_link_alert_text),
buttons = {
Column {
SectionItemView({
AlertManager.shared.hideAlert()
addShortLink(shareOnCompletion = shareAddress != null)
}) {
Text(
generalGetString(MR.strings.share_profile_via_link_alert_confirm),
Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = MaterialTheme.colors.primary
)
}
if (shareAddress != null) {
// Delete without notification
SectionItemView({
AlertManager.shared.hideAlert()
shareAddress()
}) {
Text(
generalGetString(MR.strings.share_old_link_alert_button),
Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = MaterialTheme.colors.primary
)
}
}
// Cancel
SectionItemView({
AlertManager.shared.hideAlert()
}) {
Text(
stringResource(MR.strings.cancel_verb),
Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = MaterialTheme.colors.primary
)
}
}
}
)
}
LaunchedEffect(Unit) {
if (groupLink == null && !creatingLink) {
createLink()
@@ -71,7 +123,7 @@ fun GroupLinkView(
groupLinkMemberRole,
creatingLink,
createLink = ::createLink,
addShortLink = ::addShortLink,
showAddShortLinkAlert = ::showAddShortLinkAlert,
updateLink = {
val role = groupLinkMemberRole.value
if (role != null) {
@@ -117,7 +169,7 @@ fun GroupLinkLayout(
groupLinkMemberRole: MutableState<GroupMemberRole?>,
creatingLink: Boolean,
createLink: () -> Unit,
addShortLink: () -> Unit,
showAddShortLinkAlert: ((() -> Unit)?) -> Unit,
updateLink: () -> Unit,
deleteLink: () -> Unit,
creatingGroup: Boolean = false,
@@ -182,7 +234,15 @@ fun GroupLinkLayout(
SimpleButton(
stringResource(MR.strings.share_link),
icon = painterResource(MR.images.ic_share),
click = { clipboard.shareText(groupLink.connLinkContact.simplexChatUri(short = showShortLink.value)) }
click = {
if (groupLink.shouldBeUpgraded) {
showAddShortLinkAlert {
clipboard.shareText(groupLink.connLinkContact.simplexChatUri(short = showShortLink.value))
}
} else {
clipboard.shareText(groupLink.connLinkContact.simplexChatUri(short = showShortLink.value))
}
}
)
if (creatingGroup && close != null) {
ContinueButton(close)
@@ -195,10 +255,10 @@ fun GroupLinkLayout(
)
}
}
if (groupLink.connLinkContact.connShortLink == null) {
AddShortLinkButton(text = stringResource(MR.strings.add_short_link), addShortLink)
} else if (!groupLink.shortLinkDataSet) {
AddShortLinkButton(text = stringResource(MR.strings.share_group_profile_via_link), addShortLink)
if (groupLink.shouldBeUpgraded) {
AddShortLinkButton(text = stringResource(MR.strings.upgrade_group_link)) {
showAddShortLinkAlert(null)
}
}
}
}
@@ -535,14 +535,16 @@ private fun InviteView(rhId: Long?, connLinkInvitation: CreatedConnLink, contact
@Composable
fun ToggleShortLinkButton(short: MutableState<Boolean>) {
Text(
stringResource(if (short.value) MR.strings.full_link_button_text else MR.strings.short_link_button_text),
modifier = Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null
) { short.value = !short.value },
style = MaterialTheme.typography.body2, fontSize = 14.sp, color = MaterialTheme.colors.primary
)
if (appPrefs.developerTools.state.value) {
Text(
stringResource(if (short.value) MR.strings.full_link_button_text else MR.strings.short_link_button_text),
modifier = Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null
) { short.value = !short.value },
style = MaterialTheme.typography.body2, fontSize = 14.sp, color = MaterialTheme.colors.primary
)
}
}
@Composable
@@ -16,16 +16,17 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.style.TextAlign
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.common.model.*
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.chat.ShareAddressButton
import chat.simplex.common.views.helpers.*
import chat.simplex.common.model.ChatModel
import chat.simplex.common.model.MsgContent
import chat.simplex.common.platform.*
import chat.simplex.common.views.chat.*
import chat.simplex.common.views.newchat.*
import chat.simplex.res.MR
@@ -40,6 +41,7 @@ fun UserAddressView(
val shareViaProfile = remember { mutableStateOf(shareViaProfile) }
var progressIndicator by remember { mutableStateOf(false) }
val user = remember { chatModel.currentUser }
val clipboard = LocalClipboardManager.current
KeyChangeEffect(user.value?.remoteHostId, user.value?.userId) {
close()
}
@@ -85,24 +87,64 @@ fun UserAddressView(
}
}
fun addShortLink() {
fun addShortLink(shareOnCompletion: Boolean = false) {
withBGApi {
progressIndicator = true
val userAddress = chatModel.controller.apiAddMyAddressShortLink(user.value?.remoteHostId)
if (userAddress != null) {
chatModel.userAddress.value = userAddress
if (shareOnCompletion) {
clipboard.shareText(userAddress.connLinkContact.simplexChatUri(short = true))
}
}
progressIndicator = false
}
}
fun showAddShortLinkAlert() {
AlertManager.shared.showAlertDialogStacked(
fun showAddShortLinkAlert(shareAddress: (() -> Unit)? = null) {
AlertManager.shared.showAlertDialogButtonsColumn(
title = generalGetString(MR.strings.share_profile_via_link),
text = generalGetString(MR.strings.share_profile_via_link_alert_text),
confirmText = generalGetString(MR.strings.share_profile_via_link_alert_confirm),
onConfirm = {
addShortLink()
buttons = {
Column {
SectionItemView({
AlertManager.shared.hideAlert()
addShortLink(shareOnCompletion = shareAddress != null)
}) {
Text(
generalGetString(MR.strings.share_profile_via_link_alert_confirm),
Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = MaterialTheme.colors.primary
)
}
if (shareAddress != null) {
// Delete without notification
SectionItemView({
AlertManager.shared.hideAlert()
shareAddress()
}) {
Text(
generalGetString(MR.strings.share_old_address_alert_button),
Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = MaterialTheme.colors.primary
)
}
}
// Cancel
SectionItemView({
AlertManager.shared.hideAlert()
}) {
Text(
stringResource(MR.strings.cancel_verb),
Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
color = MaterialTheme.colors.primary
)
}
}
}
)
}
@@ -113,15 +155,14 @@ fun UserAddressView(
}
}
val userAddress = remember { chatModel.userAddress }
val clipboard = LocalClipboardManager.current
val uriHandler = LocalUriHandler.current
val showLayout = @Composable {
UserAddressLayout(
user = user.value,
userAddress = userAddress.value,
shareViaProfile,
createAddress = { createAddress() },
showAddShortLinkAlert = { showAddShortLinkAlert() },
createAddress = ::createAddress,
showAddShortLinkAlert = ::showAddShortLinkAlert,
learnMore = {
ModalManager.start.showModal {
UserAddressLearnMore()
@@ -196,7 +237,7 @@ private fun UserAddressLayout(
userAddress: UserContactLinkRec?,
shareViaProfile: MutableState<Boolean>,
createAddress: () -> Unit,
showAddShortLinkAlert: () -> Unit,
showAddShortLinkAlert: ((() -> Unit)?) -> Unit,
learnMore: () -> Unit,
share: (String) -> Unit,
sendEmail: (UserContactLinkRec) -> Unit,
@@ -235,15 +276,19 @@ private fun UserAddressLayout(
titleButton = if (userAddress.connLinkContact.connShortLink != null) {{ ToggleShortLinkButton(showShortLink) }} else null
) {
SimpleXCreatedLinkQRCode(userAddress.connLinkContact, short = showShortLink.value)
ShareAddressButton { share(userAddress.connLinkContact.simplexChatUri(short = showShortLink.value)) }
if (userAddress.shouldBeUpgraded) {
AddShortLinkButton(text = stringResource(MR.strings.add_short_link)) { showAddShortLinkAlert(null) }
}
ShareAddressButton {
if (userAddress.shouldBeUpgraded) {
showAddShortLinkAlert { share(userAddress.connLinkContact.simplexChatUri(short = showShortLink.value)) }
} else {
share(userAddress.connLinkContact.simplexChatUri(short = showShortLink.value))
}
}
// ShareViaEmailButton { sendEmail(userAddress) }
BusinessAddressToggle(addressSettingsState) { saveAddressSettings(addressSettingsState.value, savedAddressSettingsState) }
AddressSettingsButton(user, userAddress, shareViaProfile, setProfileAddress, saveAddressSettings)
if (userAddress.connLinkContact.connShortLink == null) {
AddShortLinkButton(text = stringResource(MR.strings.add_short_link), showAddShortLinkAlert)
} else if (!userAddress.shortLinkDataSet) {
AddShortLinkButton(text = stringResource(MR.strings.share_profile_via_link), showAddShortLinkAlert)
}
if (addressSettingsState.value.businessAddress) {
SectionTextFooter(stringResource(MR.strings.add_your_team_members_to_conversations))
@@ -284,7 +329,7 @@ private fun CreateAddressButton(onClick: () -> Unit) {
@Composable
private fun AddShortLinkButton(text: String, onClick: () -> Unit) {
SettingsActionItem(
painterResource(MR.images.ic_add),
painterResource(MR.images.ic_arrow_upward),
text,
onClick,
iconColor = MaterialTheme.colors.primary,
@@ -1103,11 +1103,16 @@
<string name="address_settings">Address settings</string>
<string name="business_address">Business address</string>
<string name="add_your_team_members_to_conversations">Add your team members to the conversations.</string>
<string name="add_short_link">Add short link</string>
<string name="share_profile_via_link">Share profile with address</string>
<string name="share_profile_via_link_alert_text">Profile will be shared with the address.</string>
<string name="share_profile_via_link_alert_confirm">Share profile</string>
<string name="share_group_profile_via_link">Share group profile via link</string>
<string name="add_short_link">Upgrade address</string>
<string name="share_profile_via_link">Upgrade address?</string>
<string name="share_profile_via_link_alert_text">The address will be short, and your profile will be shared via the address.</string>
<string name="share_profile_via_link_alert_confirm">Upgrade</string>
<string name="upgrade_group_link">Upgrade group link</string>
<string name="share_group_profile_via_link">Upgrade group link?</string>
<string name="share_group_profile_via_link_alert_text">The link will be short, and group profile will be shared via the link.</string>
<string name="share_profile_via_link_alert_confirm">Upgrade</string>
<string name="share_old_address_alert_button">Share old address</string>
<string name="share_old_link_alert_button">Share old link</string>
<!-- CreateSimpleXAddress.kt -->
<string name="continue_to_next_step">Continue</string>