mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-06-30 20:21:51 +00:00
kotlin, labels
This commit is contained in:
@@ -659,7 +659,7 @@ struct GroupChatInfoView: View {
|
||||
}
|
||||
|
||||
private func channelWebAccessButton() -> some View {
|
||||
let title: LocalizedStringKey = groupInfo.useRelays ? "Channel page & name" : "Group page & name"
|
||||
let title: LocalizedStringKey = groupInfo.useRelays ? "Channel webpage" : "Group webpage"
|
||||
return NavigationLink {
|
||||
ChannelWebAccessView(groupInfo: $groupInfo)
|
||||
.navigationBarTitle(title)
|
||||
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
package chat.simplex.common.views.chat.group
|
||||
|
||||
import SectionBottomSpacer
|
||||
import SectionItemView
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
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.*
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.views.usersettings.*
|
||||
import chat.simplex.res.MR
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
@Composable
|
||||
fun ChannelWebPageView(
|
||||
rhId: Long?,
|
||||
groupInfo: GroupInfo,
|
||||
chatModel: ChatModel,
|
||||
close: () -> Unit
|
||||
) {
|
||||
val isChannel = groupInfo.useRelays
|
||||
val access = groupInfo.groupProfile.publicGroup?.publicGroupAccess
|
||||
val webPage = rememberSaveable { mutableStateOf(access?.groupWebPage ?: "") }
|
||||
val allowEmbedding = rememberSaveable { mutableStateOf(access?.allowEmbedding ?: false) }
|
||||
val groupRelays = remember { mutableStateListOf<GroupRelay>() }
|
||||
|
||||
val dataUnchanged = webPage.value.trim() == (access?.groupWebPage ?: "") &&
|
||||
allowEmbedding.value == (access?.allowEmbedding ?: false)
|
||||
|
||||
val save: () -> Unit = {
|
||||
withBGApi {
|
||||
val trimmedPage = webPage.value.trim()
|
||||
val newAccess = PublicGroupAccess(
|
||||
groupWebPage = trimmedPage.ifEmpty { null },
|
||||
groupDomain = access?.groupDomain,
|
||||
domainWebPage = access?.domainWebPage ?: false,
|
||||
allowEmbedding = allowEmbedding.value
|
||||
)
|
||||
val gp = groupInfo.groupProfile.copy(
|
||||
publicGroup = groupInfo.groupProfile.publicGroup?.copy(publicGroupAccess = newAccess)
|
||||
)
|
||||
val gInfo = chatModel.controller.apiUpdateGroup(rhId, groupInfo.groupId, gp, isChannel)
|
||||
if (gInfo != null) {
|
||||
withContext(Dispatchers.Main) {
|
||||
chatModel.chatsContext.updateGroup(rhId, gInfo)
|
||||
}
|
||||
close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val closeWithAlert = {
|
||||
if (dataUnchanged) {
|
||||
close()
|
||||
} else {
|
||||
AlertManager.shared.showAlertDialogStacked(
|
||||
title = generalGetString(MR.strings.save_preferences_question),
|
||||
confirmText = generalGetString(if (isChannel) MR.strings.save_and_notify_channel_subscribers else MR.strings.save_and_notify_group_members),
|
||||
dismissText = generalGetString(MR.strings.exit_without_saving),
|
||||
onConfirm = save,
|
||||
onDismiss = close,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
val relays = chatModel.controller.apiGetGroupRelays(groupInfo.groupId)
|
||||
groupRelays.clear()
|
||||
groupRelays.addAll(relays)
|
||||
}
|
||||
|
||||
BackHandler(onBack = closeWithAlert)
|
||||
ModalView(close = closeWithAlert) {
|
||||
ChannelWebPageLayout(
|
||||
isChannel = isChannel,
|
||||
webPage = webPage,
|
||||
allowEmbedding = allowEmbedding,
|
||||
groupRelays = groupRelays,
|
||||
groupInfo = groupInfo,
|
||||
dataUnchanged = dataUnchanged,
|
||||
save = save
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ChannelWebPageLayout(
|
||||
isChannel: Boolean,
|
||||
webPage: MutableState<String>,
|
||||
allowEmbedding: MutableState<Boolean>,
|
||||
groupRelays: List<GroupRelay>,
|
||||
groupInfo: GroupInfo,
|
||||
dataUnchanged: Boolean,
|
||||
save: () -> Unit
|
||||
) {
|
||||
val clipboard = LocalClipboardManager.current
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(if (isChannel) MR.strings.channel_webpage else MR.strings.group_webpage))
|
||||
|
||||
SectionView(stringResource(MR.strings.web_page).uppercase()) {
|
||||
SectionItemView {
|
||||
ProfileNameField(webPage, stringResource(MR.strings.web_page_url_placeholder))
|
||||
}
|
||||
PreferenceToggle(stringResource(MR.strings.allow_embedding), checked = allowEmbedding.value) {
|
||||
allowEmbedding.value = it
|
||||
}
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.web_page_footer))
|
||||
|
||||
val embedCode = embedCode(groupRelays, groupInfo)
|
||||
if (embedCode != null) {
|
||||
SectionView(stringResource(MR.strings.embed_code).uppercase()) {
|
||||
SectionItemView {
|
||||
Text(
|
||||
embedCode,
|
||||
style = MaterialTheme.typography.body2.copy(fontFamily = FontFamily.Monospace, fontSize = 12.sp),
|
||||
maxLines = 6,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
SectionItemView({
|
||||
clipboard.setText(AnnotatedString(embedCode))
|
||||
showToast(generalGetString(MR.strings.copied))
|
||||
}) {
|
||||
Icon(painterResource(MR.images.ic_content_copy), null, tint = MaterialTheme.colors.primary)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(stringResource(MR.strings.copy_embed_code), color = MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SectionView {
|
||||
SectionItemView(save, disabled = dataUnchanged) {
|
||||
Text(
|
||||
stringResource(MR.strings.save_verb),
|
||||
color = if (dataUnchanged) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
private fun embedCode(groupRelays: List<GroupRelay>, groupInfo: GroupInfo): String? {
|
||||
val pg = groupInfo.groupProfile.publicGroup ?: return null
|
||||
val relayUrls = groupRelays.mapNotNull { it.relayCap.baseWebUrl }
|
||||
if (relayUrls.isEmpty()) return null
|
||||
val urls = relayUrls.joinToString(",")
|
||||
return """<div data-simplex-group-preview
|
||||
data-relay-urls="$urls"
|
||||
data-public-group-id="${pg.publicGroupId}"
|
||||
data-group-link="${pg.groupLink}"></div>
|
||||
<script src="https://simplex.chat/js/channel-preview.js"></script>"""
|
||||
}
|
||||
+30
@@ -13,6 +13,7 @@ import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.*
|
||||
@@ -27,6 +28,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
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
|
||||
@@ -173,6 +175,9 @@ fun ModalData.GroupChatInfoView(
|
||||
manageGroupLink = {
|
||||
ModalManager.end.showModal(cardScreen = true) { GroupLinkView(chatModel, rhId, groupInfo, groupLink, onGroupLinkUpdated, isChannel = groupInfo.useRelays, shareGroupInfo = groupInfo) }
|
||||
},
|
||||
manageWebPage = {
|
||||
ModalManager.end.showCustomModal { close -> ChannelWebPageView(rhId, groupInfo, chatModel, close) }
|
||||
},
|
||||
onSearchClicked = onSearchClicked,
|
||||
deletingItems = deletingItems
|
||||
)
|
||||
@@ -502,6 +507,7 @@ fun ModalData.GroupChatInfoLayout(
|
||||
clearChat: () -> Unit,
|
||||
leaveGroup: () -> Unit,
|
||||
manageGroupLink: () -> Unit,
|
||||
manageWebPage: () -> Unit,
|
||||
close: () -> Unit = { ModalManager.closeAllModalsEverywhere()},
|
||||
onSearchClicked: () -> Unit,
|
||||
deletingItems: State<Boolean>
|
||||
@@ -608,6 +614,7 @@ fun ModalData.GroupChatInfoLayout(
|
||||
if (groupInfo.isOwner && groupLink != null) {
|
||||
anyTopSectionRowShow = true
|
||||
ChannelLinkButton(manageGroupLink)
|
||||
ChannelWebPageButton(groupInfo, manageWebPage)
|
||||
} else if (channelLink != null) {
|
||||
anyTopSectionRowShow = true
|
||||
ChannelLinkQRCodeSection(channelLink)
|
||||
@@ -930,6 +937,18 @@ private fun GroupChatInfoHeader(cInfo: ChatInfo, groupInfo: GroupInfo) {
|
||||
modifier = Modifier.combinedClickable(onClick = copyDisplayName, onLongClick = copyDisplayName).onRightClick(copyDisplayName)
|
||||
)
|
||||
ChatInfoDescription(cInfo, displayName, copyNameToClipboard)
|
||||
val webPage = groupInfo.groupProfile.publicGroup?.publicGroupAccess?.groupWebPage
|
||||
if (webPage != null) {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
Text(
|
||||
webPage,
|
||||
style = MaterialTheme.typography.body2,
|
||||
color = MaterialTheme.colors.primary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.clickable { uriHandler.openUriCatching(webPage) }
|
||||
)
|
||||
}
|
||||
if (groupInfo.useRelays) {
|
||||
val count = groupInfo.groupSummary.publicMemberCount
|
||||
if (count != null && count > 0) {
|
||||
@@ -1191,6 +1210,16 @@ private fun ChannelLinkButton(onClick: () -> Unit) {
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ChannelWebPageButton(groupInfo: GroupInfo, onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_travel_explore),
|
||||
stringResource(if (groupInfo.useRelays) MR.strings.channel_webpage else MR.strings.group_webpage),
|
||||
onClick,
|
||||
iconColor = MaterialTheme.colors.secondary
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ChannelLinkQRCodeSection(groupLink: String) {
|
||||
val clipboard = LocalClipboardManager.current
|
||||
@@ -1395,6 +1424,7 @@ fun PreviewGroupChatInfoLayout() {
|
||||
clearChat = {},
|
||||
leaveGroup = {},
|
||||
manageGroupLink = {},
|
||||
manageWebPage = {},
|
||||
onSearchClicked = {},
|
||||
deletingItems = remember { mutableStateOf(true) }
|
||||
)
|
||||
|
||||
@@ -1918,6 +1918,14 @@
|
||||
<string name="button_welcome_message">Welcome message</string>
|
||||
<string name="group_link">Group link</string>
|
||||
<string name="channel_link">Channel link</string>
|
||||
<string name="channel_webpage">Channel webpage</string>
|
||||
<string name="group_webpage">Group webpage</string>
|
||||
<string name="web_page">Web page</string>
|
||||
<string name="web_page_url_placeholder">Web page URL</string>
|
||||
<string name="allow_embedding">Allow embedding</string>
|
||||
<string name="web_page_footer">Set a web page URL where your channel preview is hosted. Allow embedding to let any website embed the preview.</string>
|
||||
<string name="embed_code">Embed code</string>
|
||||
<string name="copy_embed_code">Copy embed code</string>
|
||||
<string name="create_group_link">Create group link</string>
|
||||
<string name="button_create_group_link">Create link</string>
|
||||
<string name="delete_link_question">Delete link?</string>
|
||||
|
||||
Reference in New Issue
Block a user