mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-09-26 02:24:54 +00:00
refactor and simplify
This commit is contained in:
@@ -603,13 +603,6 @@ data class ThemeModeOverride (
|
||||
// cards above. DARK/BLACK: palette bg (cards already raised via founder's
|
||||
// formula in Section.kt). SIMPLEX: gradient bottom stop (darker), since the
|
||||
// canvas itself is a gradient drawn by themedBackgroundBrush.
|
||||
//
|
||||
// Reads CurrentColors.value directly rather than via MaterialTheme/CompositionLocal
|
||||
// because this helper is called from two scopes: @Composable bodies (SectionView,
|
||||
// SectionDivider) and DrawScope (sectionItemDivider's drawWithContent). DrawScope
|
||||
// can't call @Composable getters, so a snapshot read keeps one helper usable in
|
||||
// both places. State invalidation still works — CurrentColors is a MutableStateFlow,
|
||||
// reads are tracked by Compose snapshot system.
|
||||
fun canvasColorForCurrentTheme(): Color {
|
||||
val theme = CurrentColors.value
|
||||
val c = theme.colors
|
||||
|
||||
+1
-3
@@ -85,7 +85,7 @@ fun CreateProfile(chatModel: ChatModel, close: () -> Unit) {
|
||||
sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.surface)
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(MR.strings.create_profile), bottomPadding = DEFAULT_PADDING_HALF)
|
||||
@@ -239,7 +239,6 @@ private fun CreateFirstProfileMobile(chatModel: ChatModel, close: () -> Unit) {
|
||||
val refocusTrigger = remember { mutableStateOf(0) }
|
||||
ModalView(
|
||||
close = { onboardingBackAction(chatModel, close) },
|
||||
background = MaterialTheme.colors.surface,
|
||||
endButtons = { MigrateButton(refocusTrigger) }
|
||||
) {
|
||||
val displayName = rememberSaveable { mutableStateOf("") }
|
||||
@@ -318,7 +317,6 @@ private fun CreateFirstProfileDesktop(chatModel: ChatModel, close: () -> Unit) {
|
||||
CompositionLocalProvider(LocalAppBarHandler provides rememberAppBarHandler()) {
|
||||
ModalView(
|
||||
close = { onboardingBackAction(chatModel, close) },
|
||||
background = MaterialTheme.colors.surface,
|
||||
endButtons = { MigrateButton(refocusTrigger) }
|
||||
) {
|
||||
ColumnWithScrollBar(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
|
||||
+16
-16
@@ -576,7 +576,7 @@ fun ChatInfoLayout(
|
||||
SectionSpacer()
|
||||
|
||||
if (customUserProfile != null) {
|
||||
SectionView(generalGetString(MR.strings.incognito)) {
|
||||
SectionView(generalGetString(MR.strings.incognito), card = true) {
|
||||
SectionItemViewSpaceBetween {
|
||||
Text(generalGetString(MR.strings.incognito_random_profile))
|
||||
Text(customUserProfile.chatViewName, color = Indigo)
|
||||
@@ -585,7 +585,7 @@ fun ChatInfoLayout(
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
if (contact.ready && contact.active) {
|
||||
if (connectionCode != null) {
|
||||
VerifyCodeButton(contact.verified, verifyClicked)
|
||||
@@ -610,35 +610,35 @@ fun ChatInfoLayout(
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
ChatTTLOption(chatItemTTL, setChatItemTTL, deletingItems)
|
||||
SectionTextFooter(stringResource(MR.strings.chat_ttl_options_footer))
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.chat_ttl_options_footer))
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
|
||||
|
||||
val conn = contact.activeConn
|
||||
if (conn != null) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
InfoRow("E2E encryption", if (conn.connPQEnabled) "Quantum resistant" else "Standard")
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
|
||||
if (contact.contactLink != null) {
|
||||
SectionView(stringResource(MR.strings.address_section_title)) {
|
||||
SectionView(stringResource(MR.strings.address_section_title), card = true) {
|
||||
SimpleXLinkQRCode(contact.contactLink)
|
||||
val clipboard = LocalClipboardManager.current
|
||||
ShareAddressButton { clipboard.shareText(simplexChatLink(contact.contactLink)) }
|
||||
SectionTextFooter(stringResource(MR.strings.you_can_share_this_address_with_your_contacts).format(contact.displayName))
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.you_can_share_this_address_with_your_contacts).format(contact.displayName))
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
}
|
||||
|
||||
val chatSubStatus = chatModel.chatSubStatus.value
|
||||
if (contact.ready && contact.active && (chatSubStatus != null || cStats != null)) {
|
||||
SectionView(title = stringResource(MR.strings.conn_stats_section_title_servers)) {
|
||||
if (contact.ready && contact.active) {
|
||||
SectionView(title = stringResource(MR.strings.conn_stats_section_title_servers), card = true) {
|
||||
val chatSubStatus = chatModel.chatSubStatus.value
|
||||
if (chatSubStatus != null) {
|
||||
SectionItemView({
|
||||
AlertManager.shared.showAlertMsg(
|
||||
@@ -673,14 +673,14 @@ fun ChatInfoLayout(
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
}
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
ClearChatButton(clearChat)
|
||||
DeleteContactButton(deleteContact)
|
||||
}
|
||||
|
||||
if (developerTools) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(title = stringResource(MR.strings.section_title_for_console)) {
|
||||
SectionView(title = stringResource(MR.strings.section_title_for_console), card = true) {
|
||||
InfoRow(stringResource(MR.strings.info_row_local_name), chat.chatInfo.localDisplayName)
|
||||
InfoRow(stringResource(MR.strings.info_row_database_id), chat.chatInfo.apiId.toString())
|
||||
SectionItemView({
|
||||
|
||||
+13
-12
@@ -4,6 +4,7 @@ import InfoRow
|
||||
import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionItemView
|
||||
import SectionView
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
@@ -248,7 +249,7 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
|
||||
@Composable
|
||||
fun Details() {
|
||||
AppBarTitle(stringResource(if (ci.localNote) MR.strings.saved_message_title else if (sent) MR.strings.sent_message else MR.strings.received_message))
|
||||
Column {
|
||||
SectionView {
|
||||
InfoRow(stringResource(if (!ci.localNote) MR.strings.info_row_sent_at else MR.strings.info_row_created_at), localTimestamp(ci.meta.itemTs))
|
||||
if (!sent) {
|
||||
InfoRow(stringResource(MR.strings.info_row_received_at), localTimestamp(ci.meta.createdAt))
|
||||
@@ -285,17 +286,17 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
|
||||
fun HistoryTab() {
|
||||
ColumnWithScrollBar {
|
||||
Details()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = true)
|
||||
val versions = ciInfo.itemVersions
|
||||
if (versions.isNotEmpty()) {
|
||||
Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
|
||||
SectionView(contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Text(stringResource(MR.strings.edit_history), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = DEFAULT_PADDING))
|
||||
versions.forEachIndexed { i, ciVersion ->
|
||||
ItemVersionView(ciVersion, current = i == 0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
|
||||
SectionView(contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
Text(stringResource(MR.strings.no_history), color = MaterialTheme.colors.secondary)
|
||||
}
|
||||
@@ -310,8 +311,8 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
|
||||
fun QuoteTab(qi: CIQuote) {
|
||||
ColumnWithScrollBar {
|
||||
Details()
|
||||
SectionDividerSpaced()
|
||||
Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
|
||||
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = true)
|
||||
SectionView(contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Text(stringResource(MR.strings.in_reply_to), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = DEFAULT_PADDING))
|
||||
QuotedMsgView(qi)
|
||||
}
|
||||
@@ -324,8 +325,8 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
|
||||
fun ForwardedFromTab(forwardedFromItem: AChatItem) {
|
||||
ColumnWithScrollBar {
|
||||
Details()
|
||||
SectionDividerSpaced()
|
||||
Column {
|
||||
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = true)
|
||||
SectionView {
|
||||
Text(stringResource(if (local) MR.strings.saved_from_chat_item_info_title else MR.strings.forwarded_from_chat_item_info_title),
|
||||
style = MaterialTheme.typography.h2,
|
||||
modifier = Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING))
|
||||
@@ -387,17 +388,17 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
|
||||
fun DeliveryTab(memberDeliveryStatuses: List<MemberDeliveryStatus>) {
|
||||
ColumnWithScrollBar {
|
||||
Details()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = true)
|
||||
val mss = membersStatuses(chatModel, memberDeliveryStatuses)
|
||||
if (mss.isNotEmpty()) {
|
||||
Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
|
||||
SectionView(contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Text(stringResource(MR.strings.delivery), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = DEFAULT_PADDING))
|
||||
mss.forEach { (member, status, sentViaProxy) ->
|
||||
MemberDeliveryStatusView(member, status, sentViaProxy)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
|
||||
SectionView(contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
Text(stringResource(MR.strings.no_info_on_delivery), color = MaterialTheme.colors.secondary)
|
||||
}
|
||||
@@ -441,7 +442,7 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
|
||||
return numTabs
|
||||
}
|
||||
|
||||
Column(Modifier.fillMaxSize().background(MaterialTheme.colors.surface)) {
|
||||
Column {
|
||||
if (numTabs() > 1) {
|
||||
Box(
|
||||
Modifier
|
||||
|
||||
+8
-6
@@ -90,27 +90,27 @@ private fun ContactPreferencesLayout(
|
||||
TimedMessagesFeatureSection(featuresAllowed, contact.mergedPreferences.timedMessages, timedMessages, onTTLUpdated) { allowed, ttl ->
|
||||
applyPrefs(featuresAllowed.copy(timedMessagesAllowed = allowed, timedMessagesTTL = ttl ?: currentFeaturesAllowed.timedMessagesTTL))
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true)
|
||||
val allowFullDeletion: MutableState<ContactFeatureAllowed> = remember(featuresAllowed) { mutableStateOf(featuresAllowed.fullDelete) }
|
||||
FeatureSection(ChatFeature.FullDelete, user.fullPreferences.fullDelete.allow, contact.mergedPreferences.fullDelete, allowFullDeletion) {
|
||||
applyPrefs(featuresAllowed.copy(fullDelete = it))
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true)
|
||||
val allowReactions: MutableState<ContactFeatureAllowed> = remember(featuresAllowed) { mutableStateOf(featuresAllowed.reactions) }
|
||||
FeatureSection(ChatFeature.Reactions, user.fullPreferences.reactions.allow, contact.mergedPreferences.reactions, allowReactions) {
|
||||
applyPrefs(featuresAllowed.copy(reactions = it))
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true)
|
||||
val allowVoice: MutableState<ContactFeatureAllowed> = remember(featuresAllowed) { mutableStateOf(featuresAllowed.voice) }
|
||||
FeatureSection(ChatFeature.Voice, user.fullPreferences.voice.allow, contact.mergedPreferences.voice, allowVoice) {
|
||||
applyPrefs(featuresAllowed.copy(voice = it))
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true)
|
||||
val allowCalls: MutableState<ContactFeatureAllowed> = remember(featuresAllowed) { mutableStateOf(featuresAllowed.calls) }
|
||||
FeatureSection(ChatFeature.Calls, user.fullPreferences.calls.allow, contact.mergedPreferences.calls, allowCalls) {
|
||||
applyPrefs(featuresAllowed.copy(calls = it))
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
|
||||
ResetSaveButtons(
|
||||
reset = reset,
|
||||
save = savePrefs,
|
||||
@@ -139,6 +139,7 @@ private fun FeatureSection(
|
||||
icon = feature.iconFilled(),
|
||||
iconTint = if (enabled.forUser) SimplexGreen else if (enabled.forContact) WarningYellow else Color.Red,
|
||||
leadingIcon = true,
|
||||
card = true,
|
||||
) {
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.chat_preferences_you_allow),
|
||||
@@ -174,6 +175,7 @@ private fun TimedMessagesFeatureSection(
|
||||
icon = ChatFeature.TimedMessages.iconFilled(),
|
||||
iconTint = if (enabled.forUser) SimplexGreen else if (enabled.forContact) WarningYellow else Color.Red,
|
||||
leadingIcon = true,
|
||||
card = true,
|
||||
) {
|
||||
PreferenceToggle(
|
||||
generalGetString(MR.strings.chat_preferences_you_allow),
|
||||
@@ -205,7 +207,7 @@ private fun TimedMessagesFeatureSection(
|
||||
|
||||
@Composable
|
||||
private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Boolean) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
SectionItemView(reset, disabled = disabled) {
|
||||
Text(stringResource(MR.strings.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
}
|
||||
|
||||
+3
-3
@@ -175,7 +175,7 @@ fun AddGroupMembersLayout(
|
||||
)
|
||||
}
|
||||
} else {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
if (creatingGroup) {
|
||||
SectionItemView(openMemberAdmission) {
|
||||
Text(stringResource(MR.strings.set_member_admission))
|
||||
@@ -195,8 +195,8 @@ fun AddGroupMembersLayout(
|
||||
SectionCustomFooter {
|
||||
InviteSectionFooter(selectedContactsCount = selectedContacts.size, allowModifyMembers, clearSelection)
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.select_contacts)) {
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
SectionView(stringResource(MR.strings.select_contacts), card = true) {
|
||||
SectionItemView(padding = PaddingValues(start = DEFAULT_PADDING, end = DEFAULT_PADDING_HALF)) {
|
||||
SearchRowView(searchText)
|
||||
}
|
||||
|
||||
+4
-4
@@ -106,7 +106,7 @@ private fun AddGroupRelayLayout(
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
} else if (availableRelays.isEmpty()) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
SectionItemView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Text(
|
||||
generalGetString(MR.strings.no_available_relays),
|
||||
@@ -115,7 +115,7 @@ private fun AddGroupRelayLayout(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
AddRelaysButton(
|
||||
onClick = onAddRelays,
|
||||
disabled = selectedRelayIds.isEmpty() || isAdding
|
||||
@@ -131,8 +131,8 @@ private fun AddGroupRelayLayout(
|
||||
fontSize = 14.sp
|
||||
)
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.select_relays)) {
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
SectionView(generalGetString(MR.strings.select_relays), card = true) {
|
||||
availableRelays.forEach { item ->
|
||||
val selected = item.relayId in selectedRelayIds
|
||||
SectionItemView(
|
||||
|
||||
+2
-2
@@ -44,7 +44,7 @@ fun ChannelMembersView(
|
||||
|
||||
if (groupInfo.isOwner) {
|
||||
val subscriberCount = groupInfo.groupSummary.publicMemberCount ?: (members.size + 1).toLong()
|
||||
SectionView(title = subscriberCountStr(subscriberCount)) {
|
||||
SectionView(title = subscriberCountStr(subscriberCount), card = true) {
|
||||
SectionItemView(minHeight = 54.dp, padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
ChannelMemberRow(groupInfo.membership, user = true, showRole = true)
|
||||
}
|
||||
@@ -61,7 +61,7 @@ fun ChannelMembersView(
|
||||
}
|
||||
} else {
|
||||
val owners = members.filter { it.memberRole >= GroupMemberRole.Owner }
|
||||
SectionView(title = generalGetString(MR.strings.channel_members_section_owners)) {
|
||||
SectionView(title = generalGetString(MR.strings.channel_members_section_owners), card = true) {
|
||||
owners.forEachIndexed { index, member ->
|
||||
if (index > 0) {
|
||||
Divider()
|
||||
|
||||
+17
-19
@@ -584,7 +584,7 @@ fun ModalData.GroupChatInfoLayout(
|
||||
SectionSpacer()
|
||||
|
||||
if (groupInfo.useRelays && groupInfo.membership.memberIncognito) {
|
||||
SectionView(generalGetString(MR.strings.incognito)) {
|
||||
SectionView(generalGetString(MR.strings.incognito), card = true) {
|
||||
SectionItemViewSpaceBetween {
|
||||
Text(generalGetString(MR.strings.incognito_random_profile))
|
||||
Text(groupInfo.membership.chatViewName, color = Indigo)
|
||||
@@ -600,7 +600,7 @@ fun ModalData.GroupChatInfoLayout(
|
||||
|| groupInfo.membership.supportChat != null)
|
||||
|
||||
if (groupInfo.useRelays) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
if (groupInfo.isOwner && groupLink != null) {
|
||||
anyTopSectionRowShow = true
|
||||
ChannelLinkButton(manageGroupLink)
|
||||
@@ -630,7 +630,7 @@ fun ModalData.GroupChatInfoLayout(
|
||||
SectionTextFooter(stringResource(MR.strings.you_can_share_channel_link_anybody_will_be_able_to_connect))
|
||||
}
|
||||
} else {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
if (groupInfo.canAddMembers && groupInfo.businessChat == null) {
|
||||
anyTopSectionRowShow = true
|
||||
if (groupLink == null) {
|
||||
@@ -658,9 +658,9 @@ fun ModalData.GroupChatInfoLayout(
|
||||
}
|
||||
}
|
||||
if (anyTopSectionRowShow) {
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
}
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
if (groupInfo.isOwner && groupInfo.businessChat?.chatType == null) {
|
||||
val editProfileTitleId = if (groupInfo.useRelays) MR.strings.button_edit_channel_profile else MR.strings.button_edit_group_profile
|
||||
EditGroupProfileButton(editProfileTitleId, editGroupProfile)
|
||||
@@ -677,9 +677,9 @@ fun ModalData.GroupChatInfoLayout(
|
||||
else if (groupInfo.businessChat == null) MR.strings.only_group_owners_can_change_prefs
|
||||
else MR.strings.only_chat_owners_can_change_prefs
|
||||
SectionTextFooter(stringResource(footerId))
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
if (!groupInfo.useRelays) {
|
||||
if (activeSortedMembers.filter { it.memberCurrent }.size <= SMALL_GROUPS_RCPS_MEM_LIMIT) {
|
||||
SendReceiptsOption(currentUser, sendReceipts, setSendReceipts)
|
||||
@@ -697,12 +697,12 @@ fun ModalData.GroupChatInfoLayout(
|
||||
}
|
||||
}
|
||||
ChatTTLOption(chatItemTTL, setChatItemTTL, deletingItems)
|
||||
SectionTextFooter(stringResource(MR.strings.chat_ttl_options_footer))
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.chat_ttl_options_footer))
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = true)
|
||||
|
||||
if (!groupInfo.nextConnectPrepared && !groupInfo.useRelays) {
|
||||
SectionView(title = String.format(generalGetString(MR.strings.group_info_section_title_num_members), activeSortedMembers.count() + 1)) {
|
||||
SectionView(title = String.format(generalGetString(MR.strings.group_info_section_title_num_members), activeSortedMembers.count() + 1), card = true) {
|
||||
if (groupInfo.canAddMembers) {
|
||||
val onAddMembersClick = if (chat.chatInfo.incognito) ::cantInviteIncognitoAlert else addMembers
|
||||
val tint = if (chat.chatInfo.incognito) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
||||
@@ -718,18 +718,16 @@ fun ModalData.GroupChatInfoLayout(
|
||||
MemberListSearchRowView(searchText)
|
||||
}
|
||||
}
|
||||
SectionItemView(minHeight = 54.dp, padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
MemberRow(groupInfo.membership, user = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!groupInfo.nextConnectPrepared && !groupInfo.useRelays) {
|
||||
item {
|
||||
SectionItemView(minHeight = 54.dp, padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
MemberRow(groupInfo.membership, user = true)
|
||||
}
|
||||
}
|
||||
items(filteredMembers.value, key = { it.groupMemberId }) { member ->
|
||||
Divider()
|
||||
val showMenu = remember(member.groupMemberId) { mutableStateOf(false) }
|
||||
val showMenu = remember { mutableStateOf(false) }
|
||||
val canBeSelected = groupInfo.membership.memberRole >= member.memberRole && member.memberRole < GroupMemberRole.Moderator
|
||||
SectionItemViewLongClickable(
|
||||
click = {
|
||||
@@ -760,9 +758,9 @@ fun ModalData.GroupChatInfoLayout(
|
||||
}
|
||||
item {
|
||||
if (!groupInfo.nextConnectPrepared && !groupInfo.useRelays) {
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
|
||||
}
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
if (groupInfo.useRelays && (groupInfo.isOwner || activeSortedMembers.any { it.memberRole == GroupMemberRole.Relay })) {
|
||||
ChannelRelaysButton(chat.remoteHostId, groupInfo, showMemberInfo)
|
||||
}
|
||||
@@ -788,7 +786,7 @@ fun ModalData.GroupChatInfoLayout(
|
||||
|
||||
if (developerTools) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(title = stringResource(MR.strings.section_title_for_console)) {
|
||||
SectionView(title = stringResource(MR.strings.section_title_for_console), card = true) {
|
||||
InfoRow(stringResource(MR.strings.info_row_local_name), groupInfo.localDisplayName)
|
||||
InfoRow(stringResource(MR.strings.info_row_database_id), groupInfo.apiId.toString())
|
||||
}
|
||||
|
||||
+90
-93
@@ -3,7 +3,6 @@ package chat.simplex.common.views.chat.group
|
||||
import SectionBottomSpacer
|
||||
import SectionItemView
|
||||
import SectionViewWithButton
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
@@ -191,110 +190,108 @@ fun GroupLinkLayout(
|
||||
)
|
||||
}
|
||||
|
||||
Box(Modifier.fillMaxSize().background(MaterialTheme.colors.surface)) {
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(if (isChannel) MR.strings.channel_link else MR.strings.group_link))
|
||||
Text(
|
||||
stringResource(if (isChannel) MR.strings.you_can_share_channel_link_anybody_will_be_able_to_connect else MR.strings.you_can_share_group_link_anybody_will_be_able_to_connect),
|
||||
Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = 12.dp),
|
||||
lineHeight = 22.sp
|
||||
)
|
||||
Column(
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
if (groupLink == null) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(horizontal = DEFAULT_PADDING, vertical = 10.dp)
|
||||
) {
|
||||
SimpleButton(stringResource(MR.strings.button_create_group_link), icon = painterResource(MR.images.ic_add_link), disabled = creatingLink, click = createLink)
|
||||
if (creatingGroup && close != null) {
|
||||
ContinueButton(close)
|
||||
}
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(if (isChannel) MR.strings.channel_link else MR.strings.group_link))
|
||||
Text(
|
||||
stringResource(if (isChannel) MR.strings.you_can_share_channel_link_anybody_will_be_able_to_connect else MR.strings.you_can_share_group_link_anybody_will_be_able_to_connect),
|
||||
Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = 12.dp),
|
||||
lineHeight = 22.sp
|
||||
)
|
||||
Column(
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
if (groupLink == null) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(horizontal = DEFAULT_PADDING, vertical = 10.dp)
|
||||
) {
|
||||
SimpleButton(stringResource(MR.strings.button_create_group_link), icon = painterResource(MR.images.ic_add_link), disabled = creatingLink, click = createLink)
|
||||
if (creatingGroup && close != null) {
|
||||
ContinueButton(close)
|
||||
}
|
||||
} else {
|
||||
if (!isChannel) {
|
||||
RoleSelectionRow(groupInfo, groupLinkMemberRole)
|
||||
}
|
||||
} else {
|
||||
if (!isChannel) {
|
||||
RoleSelectionRow(groupInfo, groupLinkMemberRole)
|
||||
}
|
||||
var initialLaunch by remember { mutableStateOf(true) }
|
||||
LaunchedEffect(groupLinkMemberRole.value) {
|
||||
if (!initialLaunch) {
|
||||
updateLink()
|
||||
}
|
||||
var initialLaunch by remember { mutableStateOf(true) }
|
||||
LaunchedEffect(groupLinkMemberRole.value) {
|
||||
if (!initialLaunch) {
|
||||
updateLink()
|
||||
}
|
||||
initialLaunch = false
|
||||
}
|
||||
val showShortLink = remember { mutableStateOf(true) }
|
||||
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
|
||||
SectionViewWithButton(
|
||||
titleButton =
|
||||
if (!isChannel && groupLink.connLinkContact.connShortLink != null) {
|
||||
{ ToggleShortLinkButton(showShortLink) }
|
||||
} else null) {
|
||||
SimpleXCreatedLinkQRCode(groupLink.connLinkContact, short = showShortLink.value)
|
||||
}
|
||||
if (!isChannel && groupLink.shouldBeUpgraded) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_add),
|
||||
stringResource(MR.strings.upgrade_group_link),
|
||||
click = { showAddShortLinkAlert(null) },
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
}
|
||||
val clipboard = LocalClipboardManager.current
|
||||
initialLaunch = false
|
||||
}
|
||||
val showShortLink = remember { mutableStateOf(true) }
|
||||
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
|
||||
SectionViewWithButton(
|
||||
titleButton =
|
||||
if (!isChannel && groupLink.connLinkContact.connShortLink != null) {
|
||||
{ ToggleShortLinkButton(showShortLink) }
|
||||
} else null) {
|
||||
SimpleXCreatedLinkQRCode(groupLink.connLinkContact, short = showShortLink.value)
|
||||
}
|
||||
if (!isChannel && groupLink.shouldBeUpgraded) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_share),
|
||||
stringResource(MR.strings.share_link),
|
||||
click = {
|
||||
if (!isChannel && groupLink.shouldBeUpgraded) {
|
||||
showAddShortLinkAlert {
|
||||
clipboard.shareText(groupLink.connLinkContact.simplexChatUri(short = showShortLink.value))
|
||||
}
|
||||
} else {
|
||||
painterResource(MR.images.ic_add),
|
||||
stringResource(MR.strings.upgrade_group_link),
|
||||
click = { showAddShortLinkAlert(null) },
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
}
|
||||
val clipboard = LocalClipboardManager.current
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_share),
|
||||
stringResource(MR.strings.share_link),
|
||||
click = {
|
||||
if (!isChannel && groupLink.shouldBeUpgraded) {
|
||||
showAddShortLinkAlert {
|
||||
clipboard.shareText(groupLink.connLinkContact.simplexChatUri(short = showShortLink.value))
|
||||
}
|
||||
} else {
|
||||
clipboard.shareText(groupLink.connLinkContact.simplexChatUri(short = showShortLink.value))
|
||||
}
|
||||
},
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
if (shareGroupInfo != null && isChannel) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_forward),
|
||||
stringResource(MR.strings.share_via_chat),
|
||||
click = {
|
||||
chatModel.sharedContent.value = SharedContent.ChatLink(shareGroupInfo)
|
||||
chatModel.chatId.value = null
|
||||
ModalManager.closeAllModalsEverywhere()
|
||||
},
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
if (shareGroupInfo != null && isChannel) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_forward),
|
||||
stringResource(MR.strings.share_via_chat),
|
||||
click = {
|
||||
chatModel.sharedContent.value = SharedContent.ChatLink(shareGroupInfo)
|
||||
chatModel.chatId.value = null
|
||||
ModalManager.closeAllModalsEverywhere()
|
||||
},
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
}
|
||||
if (!creatingGroup && !isChannel) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_delete),
|
||||
stringResource(MR.strings.delete_link),
|
||||
click = deleteLink,
|
||||
iconColor = Color.Red,
|
||||
textColor = Color.Red,
|
||||
)
|
||||
}
|
||||
if (creatingGroup && close != null) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_check),
|
||||
stringResource(MR.strings.continue_to_next_step),
|
||||
click = close,
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (!creatingGroup && !isChannel) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_delete),
|
||||
stringResource(MR.strings.delete_link),
|
||||
click = deleteLink,
|
||||
iconColor = Color.Red,
|
||||
textColor = Color.Red,
|
||||
)
|
||||
}
|
||||
if (creatingGroup && close != null) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_check),
|
||||
stringResource(MR.strings.continue_to_next_step),
|
||||
click = close,
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -424,7 +424,7 @@ fun GroupMemberInfoLayout(
|
||||
val canRemove = member.canBeRemoved(groupInfo) && member.memberRole != GroupMemberRole.Relay
|
||||
if (canBlockForAll || canRemove) {
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
if (canBlockForAll) {
|
||||
if (member.blockedByAdmin) {
|
||||
UnblockForAllButton(unblockForAll)
|
||||
@@ -446,7 +446,7 @@ fun GroupMemberInfoLayout(
|
||||
@Composable
|
||||
fun NonAdminBlockSection() {
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
if (member.blockedByAdmin) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_back_hand),
|
||||
@@ -543,7 +543,7 @@ fun GroupMemberInfoLayout(
|
||||
|| member.supportChat != null)
|
||||
|
||||
if (member.memberActive) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
if (showMemberSupportChat) {
|
||||
SupportChatButton()
|
||||
}
|
||||
@@ -559,14 +559,14 @@ fun GroupMemberInfoLayout(
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
} else if (groupInfo.useRelays && member.memberCurrent && showMemberSupportChat) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
SupportChatButton()
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
|
||||
if (member.contactLink != null) {
|
||||
SectionView(stringResource(MR.strings.address_section_title)) {
|
||||
SectionView(stringResource(MR.strings.address_section_title), card = true) {
|
||||
SimpleXLinkQRCode(member.contactLink)
|
||||
val clipboard = LocalClipboardManager.current
|
||||
ShareAddressButton { clipboard.shareText(simplexChatLink(member.contactLink)) }
|
||||
@@ -577,8 +577,8 @@ fun GroupMemberInfoLayout(
|
||||
} else {
|
||||
ConnectViaAddressButton(onClick = { connectViaAddress(member.contactLink) })
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.you_can_share_this_address_with_your_contacts).format(member.displayName))
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.you_can_share_this_address_with_your_contacts).format(member.displayName))
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
|
||||
@@ -591,7 +591,7 @@ fun GroupMemberInfoLayout(
|
||||
} else {
|
||||
stringResource(MR.strings.member_info_section_title_member)
|
||||
}
|
||||
SectionView(title = memberSectionTitle) {
|
||||
SectionView(title = memberSectionTitle, card = true) {
|
||||
val titleId = if (groupInfo.useRelays) MR.strings.info_row_channel
|
||||
else if (groupInfo.businessChat == null) MR.strings.info_row_group
|
||||
else MR.strings.info_row_chat
|
||||
@@ -628,7 +628,7 @@ fun GroupMemberInfoLayout(
|
||||
}
|
||||
if (cStats != null) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(title = stringResource(MR.strings.conn_stats_section_title_servers)) {
|
||||
SectionView(title = stringResource(MR.strings.conn_stats_section_title_servers), card = true) {
|
||||
val subStatus = cStats.subStatus
|
||||
if (subStatus != null) {
|
||||
SectionItemView({
|
||||
@@ -664,7 +664,7 @@ fun GroupMemberInfoLayout(
|
||||
val connFailedErr = member.activeConn?.connFailedErr
|
||||
if (connFailedErr != null) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(title = stringResource(MR.strings.info_row_connection_failed), icon = painterResource(MR.images.ic_warning), iconTint = Color.Red, leadingIcon = true) {
|
||||
SectionView(title = stringResource(MR.strings.info_row_connection_failed), icon = painterResource(MR.images.ic_warning), iconTint = Color.Red, leadingIcon = true, card = true) {
|
||||
SectionItemView {
|
||||
Text(
|
||||
connFailedErr,
|
||||
@@ -682,7 +682,7 @@ fun GroupMemberInfoLayout(
|
||||
|
||||
if (developerTools) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(title = stringResource(MR.strings.section_title_for_console)) {
|
||||
SectionView(title = stringResource(MR.strings.section_title_for_console), card = true) {
|
||||
InfoRow(stringResource(MR.strings.info_row_local_name), member.localDisplayName)
|
||||
InfoRow(stringResource(MR.strings.info_row_database_id), member.groupMemberId.toString())
|
||||
val conn = member.activeConn
|
||||
|
||||
+16
-16
@@ -186,33 +186,33 @@ private fun GroupPreferencesLayout(
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
}
|
||||
TimedMessagesPreference()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
DirectMessagesPreference()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
FullDeletePreference()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
ReactionsPreference()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
VoicePreference()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
FilesPreference()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
SimplexLinksPreference()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
ReportsPreference()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
HistoryPreference()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
SupportPreference(disabled = true)
|
||||
} else {
|
||||
TimedMessagesPreference()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
FullDeletePreference()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
ReactionsPreference()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
HistoryPreference()
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
SupportPreference(notice = generalGetString(MR.strings.chat_with_admins_relay_note), onEnable = { revert ->
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.enable_chats_with_admins_question),
|
||||
@@ -225,7 +225,7 @@ private fun GroupPreferencesLayout(
|
||||
})
|
||||
}
|
||||
if (groupInfo.isOwner) {
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
|
||||
val saveTextId = if (groupInfo.useRelays) MR.strings.save_and_notify_channel_subscribers
|
||||
else MR.strings.save_and_notify_group_members
|
||||
ResetSaveButtons(
|
||||
@@ -260,7 +260,7 @@ private fun FeatureSection(
|
||||
notice: String? = null,
|
||||
onSelected: (GroupFeatureEnabled, GroupMemberRole?) -> Unit
|
||||
) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
val on = enableFeature.value == GroupFeatureEnabled.ON
|
||||
val icon = if (on) feature.iconFilled() else feature.icon
|
||||
val iconTint = if (on) SimplexGreen else MaterialTheme.colors.secondary
|
||||
@@ -325,7 +325,7 @@ private fun FeatureSection(
|
||||
|
||||
@Composable
|
||||
private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Boolean, saveTextId: StringResource) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
SectionItemView(reset, disabled = disabled) {
|
||||
Text(stringResource(MR.strings.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
}
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ fun GroupProfileLayout(
|
||||
sheetState = bottomSheetModalState,
|
||||
sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp)
|
||||
) {
|
||||
ModalView(close = closeWithAlert, background = MaterialTheme.colors.surface) {
|
||||
ModalView(close = closeWithAlert) {
|
||||
ColumnWithScrollBar {
|
||||
Column(
|
||||
Modifier.fillMaxWidth()
|
||||
|
||||
+3
-3
@@ -85,7 +85,7 @@ private fun MemberAdmissionLayout(
|
||||
}
|
||||
}
|
||||
if (groupInfo.isOwner) {
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
|
||||
ResetSaveButtons(
|
||||
reset = reset,
|
||||
save = saveAdmission,
|
||||
@@ -109,7 +109,7 @@ private fun AdmissionSection(
|
||||
groupInfo: GroupInfo,
|
||||
onSelected: (MemberCriteria?) -> Unit
|
||||
) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
if (groupInfo.isOwner) {
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(admissionStageStrId),
|
||||
@@ -131,7 +131,7 @@ private fun AdmissionSection(
|
||||
|
||||
@Composable
|
||||
private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Boolean) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
SectionItemView(reset, disabled = disabled) {
|
||||
Text(stringResource(MR.strings.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
}
|
||||
|
||||
+5
-3
@@ -4,6 +4,7 @@ import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionItemView
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
import TextIconSpaced
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
@@ -64,7 +65,6 @@ fun GroupWelcomeView(m: ChatModel, rhId: Long?, groupInfo: GroupInfo, close: ()
|
||||
else -> showUnsavedChangesAlert({ save(close) }, close)
|
||||
}
|
||||
},
|
||||
background = MaterialTheme.colors.surface,
|
||||
) {
|
||||
GroupWelcomeLayout(
|
||||
welcomeText,
|
||||
@@ -160,8 +160,10 @@ private fun TextPreview(text: String, linkMode: SimplexLinkMode, markdown: Boole
|
||||
|
||||
@Composable
|
||||
private fun SaveButton(save: () -> Unit, disabled: Boolean) {
|
||||
SectionItemView(save, disabled = disabled) {
|
||||
Text(stringResource(MR.strings.save_and_update_group_profile), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
SectionView {
|
||||
SectionItemView(save, disabled = disabled) {
|
||||
Text(stringResource(MR.strings.save_and_update_group_profile), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+72
-68
@@ -1,6 +1,5 @@
|
||||
package chat.simplex.common.views.chatlist
|
||||
|
||||
import CARD_ITEM_PADDING
|
||||
import InfoRow
|
||||
import InfoRowTwoValues
|
||||
import SectionBottomSpacer
|
||||
@@ -30,7 +29,6 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.model.AgentSMPServerStatsData
|
||||
@@ -153,7 +151,7 @@ enum class PresentedServerType {
|
||||
|
||||
@Composable
|
||||
private fun ServerSessionsView(sess: ServerSessions) {
|
||||
SectionView(generalGetString(MR.strings.servers_info_transport_sessions_section_header)) {
|
||||
SectionView(generalGetString(MR.strings.servers_info_transport_sessions_section_header), card = true) {
|
||||
InfoRow(
|
||||
generalGetString(MR.strings.servers_info_sessions_connected),
|
||||
numOrDash(sess.ssConnected)
|
||||
@@ -220,7 +218,7 @@ private fun SMPServersListView(servers: List<SMPServerSummary>, statsStartedAt:
|
||||
val sortedServers = servers.sortedWith(compareBy<SMPServerSummary> { !it.hasSubs }
|
||||
.thenBy { serverAddress(it.smpServer) })
|
||||
|
||||
SectionView(header) {
|
||||
SectionView(header, card = true) {
|
||||
sortedServers.map { svr -> SMPServerView(srvSumm = svr, statsStartedAt = statsStartedAt, rh = rh) }
|
||||
}
|
||||
if (footer != null) {
|
||||
@@ -288,14 +286,14 @@ private fun XFTPServerInProgressIcon(srvSumm: XFTPServerSummary) {
|
||||
private fun XFTPServersListView(servers: List<XFTPServerSummary>, statsStartedAt: Instant, header: String? = null, rh: RemoteHostInfo?) {
|
||||
val sortedServers = servers.sortedBy { serverAddress(it.xftpServer) }
|
||||
|
||||
SectionView(header) {
|
||||
SectionView(header, card = true) {
|
||||
sortedServers.map { svr -> XFTPServerView(svr, statsStartedAt, rh) }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SMPStatsView(stats: AgentSMPServerStatsData, statsStartedAt: Instant, remoteHostInfo: RemoteHostInfo?) {
|
||||
SectionView(generalGetString(MR.strings.servers_info_statistics_section_header)) {
|
||||
SectionView(generalGetString(MR.strings.servers_info_statistics_section_header), card = true) {
|
||||
InfoRow(
|
||||
generalGetString(MR.strings.servers_info_messages_sent),
|
||||
numOrDash(stats._sentDirect + stats._sentViaProxy)
|
||||
@@ -326,20 +324,19 @@ private fun SMPStatsView(stats: AgentSMPServerStatsData, statsStartedAt: Instant
|
||||
private fun SMPSubscriptionsSection(totals: SMPTotals) {
|
||||
Column {
|
||||
Row(
|
||||
Modifier.padding(start = DEFAULT_PADDING + DEFAULT_PADDING_HALF, bottom = 8.dp),
|
||||
Modifier.padding(start = DEFAULT_PADDING, bottom = 5.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(DEFAULT_SPACE_AFTER_ICON * 2)
|
||||
) {
|
||||
Text(
|
||||
generalGetString(MR.strings.servers_info_subscriptions_section_header),
|
||||
generalGetString(MR.strings.servers_info_subscriptions_section_header).uppercase(),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
style = MaterialTheme.typography.body2,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
fontSize = 12.sp
|
||||
)
|
||||
SubscriptionStatusIndicatorView(totals.subs, totals.sessions.hasSess)
|
||||
}
|
||||
SectionView {
|
||||
Column(Modifier.padding(PaddingValues()).fillMaxWidth()) {
|
||||
InfoRow(
|
||||
generalGetString(MR.strings.servers_info_subscriptions_connections_subscribed),
|
||||
numOrDash(totals.subs.ssActive)
|
||||
@@ -357,20 +354,19 @@ private fun SMPSubscriptionsSection(totals: SMPTotals) {
|
||||
private fun SMPSubscriptionsSection(subs: SMPServerSubs, summary: SMPServerSummary, rh: RemoteHostInfo?) {
|
||||
Column {
|
||||
Row(
|
||||
Modifier.padding(start = DEFAULT_PADDING + DEFAULT_PADDING_HALF, bottom = 8.dp),
|
||||
Modifier.padding(start = DEFAULT_PADDING, bottom = 5.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(DEFAULT_SPACE_AFTER_ICON * 2)
|
||||
) {
|
||||
Text(
|
||||
generalGetString(MR.strings.servers_info_subscriptions_section_header),
|
||||
generalGetString(MR.strings.servers_info_subscriptions_section_header).uppercase(),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
style = MaterialTheme.typography.body2,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
fontSize = 12.sp
|
||||
)
|
||||
SubscriptionStatusIndicatorView(subs, summary.sessionsOrNew.hasSess)
|
||||
}
|
||||
SectionView {
|
||||
Column(Modifier.padding(PaddingValues()).fillMaxWidth()) {
|
||||
InfoRow(
|
||||
generalGetString(MR.strings.servers_info_subscriptions_connections_subscribed),
|
||||
numOrDash(subs.ssActive)
|
||||
@@ -419,7 +415,7 @@ private fun reconnectServerAlert(rh: RemoteHostInfo?, server: String) {
|
||||
|
||||
@Composable
|
||||
fun XFTPStatsView(stats: AgentXFTPServerStatsData, statsStartedAt: Instant, rh: RemoteHostInfo?) {
|
||||
SectionView(generalGetString(MR.strings.servers_info_statistics_section_header)) {
|
||||
SectionView(generalGetString(MR.strings.servers_info_statistics_section_header), card = true) {
|
||||
InfoRow(
|
||||
generalGetString(MR.strings.servers_info_uploaded),
|
||||
prettySize(stats._uploadsSize)
|
||||
@@ -448,12 +444,12 @@ fun XFTPStatsView(stats: AgentXFTPServerStatsData, statsStartedAt: Instant, rh:
|
||||
|
||||
@Composable
|
||||
private fun IndentedInfoRow(title: String, desc: String) {
|
||||
InfoRow(title, desc, padding = PaddingValues(start = 24.dp + CARD_ITEM_PADDING, end = CARD_ITEM_PADDING))
|
||||
InfoRow(title, desc, padding = PaddingValues(start = 24.dp + DEFAULT_PADDING, end = DEFAULT_PADDING))
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DetailedSMPStatsLayout(stats: AgentSMPServerStatsData, statsStartedAt: Instant) {
|
||||
SectionView(generalGetString(MR.strings.servers_info_detailed_statistics_sent_messages_header)) {
|
||||
SectionView(generalGetString(MR.strings.servers_info_detailed_statistics_sent_messages_header), card = true) {
|
||||
InfoRow(generalGetString(MR.strings.servers_info_detailed_statistics_sent_messages_total), numOrDash(stats._sentDirect + stats._sentViaProxy))
|
||||
InfoRowTwoValues(generalGetString(MR.strings.sent_directly), generalGetString(MR.strings.attempts_label), stats._sentDirect, stats._sentDirectAttempts)
|
||||
InfoRowTwoValues(generalGetString(MR.strings.sent_via_proxy), generalGetString(MR.strings.attempts_label), stats._sentViaProxy, stats._sentViaProxyAttempts)
|
||||
@@ -469,7 +465,7 @@ fun DetailedSMPStatsLayout(stats: AgentSMPServerStatsData, statsStartedAt: Insta
|
||||
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(generalGetString(MR.strings.servers_info_detailed_statistics_received_messages_header)) {
|
||||
SectionView(generalGetString(MR.strings.servers_info_detailed_statistics_received_messages_header), card = true) {
|
||||
InfoRow(generalGetString(MR.strings.servers_info_detailed_statistics_received_total), numOrDash(stats._recvMsgs))
|
||||
SectionItemView {
|
||||
Text(generalGetString(MR.strings.servers_info_detailed_statistics_receive_errors), color = MaterialTheme.colors.onBackground)
|
||||
@@ -487,7 +483,7 @@ fun DetailedSMPStatsLayout(stats: AgentSMPServerStatsData, statsStartedAt: Insta
|
||||
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(generalGetString(MR.strings.connections)) {
|
||||
SectionView(generalGetString(MR.strings.connections), card = true) {
|
||||
InfoRow(generalGetString(MR.strings.created), numOrDash(stats._connCreated))
|
||||
InfoRow(generalGetString(MR.strings.secured), numOrDash(stats._connSecured))
|
||||
InfoRow(generalGetString(MR.strings.completed), numOrDash(stats._connCompleted))
|
||||
@@ -506,7 +502,7 @@ fun DetailedSMPStatsLayout(stats: AgentSMPServerStatsData, statsStartedAt: Insta
|
||||
|
||||
@Composable
|
||||
fun DetailedXFTPStatsLayout(stats: AgentXFTPServerStatsData, statsStartedAt: Instant) {
|
||||
SectionView(generalGetString(MR.strings.uploaded_files)) {
|
||||
SectionView(generalGetString(MR.strings.uploaded_files), card = true) {
|
||||
InfoRow(generalGetString(MR.strings.size), prettySize(stats._uploadsSize))
|
||||
InfoRowTwoValues(generalGetString(MR.strings.chunks_uploaded), generalGetString(MR.strings.attempts_label), stats._uploads, stats._uploadAttempts)
|
||||
InfoRow(generalGetString(MR.strings.upload_errors), numOrDash(stats._uploadErrs))
|
||||
@@ -514,7 +510,7 @@ fun DetailedXFTPStatsLayout(stats: AgentXFTPServerStatsData, statsStartedAt: Ins
|
||||
InfoRow(generalGetString(MR.strings.deletion_errors), numOrDash(stats._deleteErrs))
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.downloaded_files)) {
|
||||
SectionView(generalGetString(MR.strings.downloaded_files), card = true) {
|
||||
InfoRow(generalGetString(MR.strings.size), prettySize(stats._downloadsSize))
|
||||
InfoRowTwoValues(generalGetString(MR.strings.chunks_downloaded), generalGetString(MR.strings.attempts_label), stats._downloads, stats._downloadAttempts)
|
||||
SectionItemView {
|
||||
@@ -532,27 +528,31 @@ fun DetailedXFTPStatsLayout(stats: AgentXFTPServerStatsData, statsStartedAt: Ins
|
||||
|
||||
@Composable
|
||||
fun XFTPServerSummaryLayout(summary: XFTPServerSummary, statsStartedAt: Instant, rh: RemoteHostInfo?) {
|
||||
SectionView(generalGetString(MR.strings.server_address)) {
|
||||
SectionView(generalGetString(MR.strings.server_address), card = true) {
|
||||
SelectionContainer {
|
||||
Text(
|
||||
summary.xftpServer,
|
||||
Modifier.padding(start = CARD_ITEM_PADDING, top = 5.dp, end = CARD_ITEM_PADDING, bottom = 10.dp),
|
||||
Modifier.padding(start = DEFAULT_PADDING, top = 5.dp, end = DEFAULT_PADDING, bottom = 10.dp),
|
||||
style = TextStyle(
|
||||
fontFamily = FontFamily.Monospace, fontSize = 16.sp,
|
||||
color = MaterialTheme.colors.secondary
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
if (summary.stats != null || summary.sessions != null) {
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
|
||||
if (summary.stats != null) {
|
||||
SectionDividerSpaced()
|
||||
XFTPStatsView(stats = summary.stats, rh = rh, statsStartedAt = statsStartedAt)
|
||||
}
|
||||
if (summary.stats != null) {
|
||||
XFTPStatsView(stats = summary.stats, rh = rh, statsStartedAt = statsStartedAt)
|
||||
if (summary.sessions != null) {
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
}
|
||||
}
|
||||
|
||||
if (summary.sessions != null) {
|
||||
SectionDividerSpaced()
|
||||
ServerSessionsView(summary.sessions)
|
||||
if (summary.sessions != null) {
|
||||
ServerSessionsView(summary.sessions)
|
||||
}
|
||||
}
|
||||
|
||||
SectionBottomSpacer()
|
||||
@@ -560,32 +560,38 @@ fun XFTPServerSummaryLayout(summary: XFTPServerSummary, statsStartedAt: Instant,
|
||||
|
||||
@Composable
|
||||
fun SMPServerSummaryLayout(summary: SMPServerSummary, statsStartedAt: Instant, rh: RemoteHostInfo?) {
|
||||
SectionView(generalGetString(MR.strings.server_address)) {
|
||||
SectionView(generalGetString(MR.strings.server_address), card = true) {
|
||||
SelectionContainer {
|
||||
Text(
|
||||
summary.smpServer,
|
||||
Modifier.padding(start = CARD_ITEM_PADDING, top = 5.dp, end = CARD_ITEM_PADDING, bottom = 10.dp),
|
||||
Modifier.padding(start = DEFAULT_PADDING, top = 5.dp, end = DEFAULT_PADDING, bottom = 10.dp),
|
||||
style = TextStyle(
|
||||
fontFamily = FontFamily.Monospace, fontSize = 16.sp,
|
||||
color = MaterialTheme.colors.secondary
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
if (summary.stats != null || summary.subs != null || summary.sessions != null) {
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
|
||||
if (summary.stats != null) {
|
||||
SectionDividerSpaced()
|
||||
SMPStatsView(stats = summary.stats, remoteHostInfo = rh, statsStartedAt = statsStartedAt)
|
||||
}
|
||||
if (summary.stats != null) {
|
||||
SMPStatsView(stats = summary.stats, remoteHostInfo = rh, statsStartedAt = statsStartedAt)
|
||||
if (summary.subs != null || summary.sessions != null) {
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
}
|
||||
}
|
||||
|
||||
if (summary.subs != null) {
|
||||
SectionDividerSpaced()
|
||||
SMPSubscriptionsSection(subs = summary.subs, summary = summary, rh = rh)
|
||||
}
|
||||
if (summary.subs != null) {
|
||||
SMPSubscriptionsSection(subs = summary.subs, summary = summary, rh = rh)
|
||||
if (summary.sessions != null) {
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
}
|
||||
|
||||
if (summary.sessions != null) {
|
||||
SectionDividerSpaced()
|
||||
ServerSessionsView(summary.sessions)
|
||||
if (summary.sessions != null) {
|
||||
ServerSessionsView(summary.sessions)
|
||||
}
|
||||
}
|
||||
|
||||
SectionBottomSpacer()
|
||||
@@ -809,18 +815,16 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta
|
||||
) {
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
if (showUserSelection) {
|
||||
SectionView {
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.servers_info_target),
|
||||
userOptions,
|
||||
selectedUserCategory,
|
||||
icon = null,
|
||||
enabled = remember { mutableStateOf(true) },
|
||||
onSelected = {
|
||||
selectedUserCategory.value = it
|
||||
}
|
||||
)
|
||||
}
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.servers_info_target),
|
||||
userOptions,
|
||||
selectedUserCategory,
|
||||
icon = null,
|
||||
enabled = remember { mutableStateOf(true) },
|
||||
onSelected = {
|
||||
selectedUserCategory.value = it
|
||||
}
|
||||
)
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
when (index) {
|
||||
@@ -835,7 +839,7 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta
|
||||
val statsStartedAt = it.statsStartedAt
|
||||
|
||||
SMPStatsView(totals.stats, statsStartedAt, rh)
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
SMPSubscriptionsSection(totals)
|
||||
SectionDividerSpaced()
|
||||
|
||||
@@ -843,7 +847,7 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta
|
||||
SMPServersListView(
|
||||
servers = currentlyUsedSMPServers,
|
||||
statsStartedAt = statsStartedAt,
|
||||
header = generalGetString(MR.strings.servers_info_connected_servers_section_header),
|
||||
header = generalGetString(MR.strings.servers_info_connected_servers_section_header).uppercase(),
|
||||
rh = rh
|
||||
)
|
||||
SectionDividerSpaced()
|
||||
@@ -853,7 +857,7 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta
|
||||
SMPServersListView(
|
||||
servers = previouslyUsedSMPServers,
|
||||
statsStartedAt = statsStartedAt,
|
||||
header = generalGetString(MR.strings.servers_info_previously_connected_servers_section_header),
|
||||
header = generalGetString(MR.strings.servers_info_previously_connected_servers_section_header).uppercase(),
|
||||
rh = rh
|
||||
)
|
||||
SectionDividerSpaced()
|
||||
@@ -863,11 +867,11 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta
|
||||
SMPServersListView(
|
||||
servers = proxySMPServers,
|
||||
statsStartedAt = statsStartedAt,
|
||||
header = generalGetString(MR.strings.servers_info_proxied_servers_section_header),
|
||||
header = generalGetString(MR.strings.servers_info_proxied_servers_section_header).uppercase(),
|
||||
footer = generalGetString(MR.strings.servers_info_proxied_servers_section_footer),
|
||||
rh = rh
|
||||
)
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
}
|
||||
|
||||
ServerSessionsView(totals.sessions)
|
||||
@@ -884,13 +888,13 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta
|
||||
val previouslyUsedXFTPServers = xftpSummary.previouslyUsedXFTPServers
|
||||
|
||||
XFTPStatsView(totals.stats, statsStartedAt, rh)
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
|
||||
if (currentlyUsedXFTPServers.isNotEmpty()) {
|
||||
XFTPServersListView(
|
||||
currentlyUsedXFTPServers,
|
||||
statsStartedAt,
|
||||
generalGetString(MR.strings.servers_info_connected_servers_section_header),
|
||||
generalGetString(MR.strings.servers_info_connected_servers_section_header).uppercase(),
|
||||
rh
|
||||
)
|
||||
SectionDividerSpaced()
|
||||
@@ -900,7 +904,7 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta
|
||||
XFTPServersListView(
|
||||
previouslyUsedXFTPServers,
|
||||
statsStartedAt,
|
||||
generalGetString(MR.strings.servers_info_previously_connected_servers_section_header),
|
||||
generalGetString(MR.strings.servers_info_previously_connected_servers_section_header).uppercase(),
|
||||
rh
|
||||
)
|
||||
SectionDividerSpaced()
|
||||
@@ -913,7 +917,7 @@ fun ModalData.ServersSummaryView(rh: RemoteHostInfo?, serversSummary: MutableSta
|
||||
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
ReconnectAllServersButton(rh)
|
||||
ResetStatisticsButton(rh, resetStats = { resetStats() })
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
package chat.simplex.common.views.chatlist
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.*
|
||||
@@ -26,7 +25,7 @@ import chat.simplex.res.MR
|
||||
fun ShareListView(chatModel: ChatModel, stopped: Boolean) {
|
||||
var searchInList by rememberSaveable { mutableStateOf("") }
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
Box(Modifier.fillMaxSize().background(MaterialTheme.colors.surface)) {
|
||||
Box(Modifier.fillMaxSize().themedBackground(bgLayerSize = LocalAppBarHandler.current?.backgroundGraphicsLayerSize, bgLayer = LocalAppBarHandler.current?.backgroundGraphicsLayer)) {
|
||||
val sharedContent = chatModel.sharedContent.value
|
||||
var isMediaOrFileAttachment = false
|
||||
var isVoice = false
|
||||
|
||||
+80
-83
@@ -1,7 +1,6 @@
|
||||
package chat.simplex.common.views.chatlist
|
||||
|
||||
import SectionCustomFooter
|
||||
import SectionDivider
|
||||
import SectionItemView
|
||||
import TextIconSpaced
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
@@ -72,101 +71,99 @@ fun TagListView(rhId: Long?, chat: Chat? = null, close: () -> Unit, reorderMode:
|
||||
}
|
||||
val topPaddingToContent = topPaddingToContent(false)
|
||||
|
||||
Box(Modifier.fillMaxSize().background(MaterialTheme.colors.surface)) {
|
||||
LazyColumnWithScrollBar(
|
||||
modifier = if (reorderMode) Modifier.dragContainer(dragDropState) else Modifier,
|
||||
state = listState,
|
||||
contentPadding = PaddingValues(
|
||||
top = if (oneHandUI.value) WindowInsets.statusBars.asPaddingValues().calculateTopPadding() else topPaddingToContent,
|
||||
bottom = if (oneHandUI.value) WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + AppBarHeight * fontSizeSqrtMultiplier else 0.dp
|
||||
),
|
||||
verticalArrangement = if (oneHandUI.value) Arrangement.Bottom else Arrangement.Top,
|
||||
) {
|
||||
@Composable fun CreateList() {
|
||||
SectionItemView({
|
||||
ModalManager.start.showModalCloseable { close ->
|
||||
TagListEditor(rhId = rhId, close = close, chat = chat)
|
||||
}
|
||||
}) {
|
||||
Icon(painterResource(MR.images.ic_add), stringResource(MR.strings.create_list), tint = MaterialTheme.colors.primary)
|
||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||
Text(stringResource(MR.strings.create_list), color = MaterialTheme.colors.primary)
|
||||
LazyColumnWithScrollBar(
|
||||
modifier = if (reorderMode) Modifier.dragContainer(dragDropState) else Modifier,
|
||||
state = listState,
|
||||
contentPadding = PaddingValues(
|
||||
top = if (oneHandUI.value) WindowInsets.statusBars.asPaddingValues().calculateTopPadding() else topPaddingToContent,
|
||||
bottom = if (oneHandUI.value) WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + AppBarHeight * fontSizeSqrtMultiplier else 0.dp
|
||||
),
|
||||
verticalArrangement = if (oneHandUI.value) Arrangement.Bottom else Arrangement.Top,
|
||||
) {
|
||||
@Composable fun CreateList() {
|
||||
SectionItemView({
|
||||
ModalManager.start.showModalCloseable { close ->
|
||||
TagListEditor(rhId = rhId, close = close, chat = chat)
|
||||
}
|
||||
}) {
|
||||
Icon(painterResource(MR.images.ic_add), stringResource(MR.strings.create_list), tint = MaterialTheme.colors.primary)
|
||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||
Text(stringResource(MR.strings.create_list), color = MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
|
||||
if (oneHandUI.value && !reorderMode) {
|
||||
item {
|
||||
CreateList()
|
||||
}
|
||||
if (oneHandUI.value && !reorderMode) {
|
||||
item {
|
||||
CreateList()
|
||||
}
|
||||
itemsIndexed(userTags.value, key = { _, item -> item.chatTagId }) { index, tag ->
|
||||
DraggableItem(dragDropState, index) { isDragging ->
|
||||
val elevation by animateDpAsState(if (isDragging) 4.dp else 0.dp)
|
||||
}
|
||||
itemsIndexed(userTags.value, key = { _, item -> item.chatTagId }) { index, tag ->
|
||||
DraggableItem(dragDropState, index) { isDragging ->
|
||||
val elevation by animateDpAsState(if (isDragging) 4.dp else 0.dp)
|
||||
|
||||
Card(
|
||||
elevation = elevation,
|
||||
backgroundColor = if (isDragging) colors.surface else Color.Unspecified
|
||||
) {
|
||||
Column {
|
||||
val selected = chatTagIds.value.contains(tag.chatTagId)
|
||||
Card(
|
||||
elevation = elevation,
|
||||
backgroundColor = if (isDragging) colors.surface else Color.Unspecified
|
||||
) {
|
||||
Column {
|
||||
val selected = chatTagIds.value.contains(tag.chatTagId)
|
||||
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.sizeIn(minHeight = DEFAULT_MIN_SECTION_ITEM_HEIGHT)
|
||||
.clickable(
|
||||
enabled = !saving.value && !reorderMode,
|
||||
onClick = {
|
||||
if (chat == null) {
|
||||
ModalManager.start.showModalCloseable { close ->
|
||||
TagListEditor(
|
||||
rhId = rhId,
|
||||
tagId = tag.chatTagId,
|
||||
close = close,
|
||||
emoji = tag.chatTagEmoji,
|
||||
name = tag.chatTagText,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
saving.value = true
|
||||
setTag(rhId = rhId, tagId = if (selected) null else tag.chatTagId, chat = chat, close = {
|
||||
saving.value = false
|
||||
close()
|
||||
})
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.sizeIn(minHeight = DEFAULT_MIN_SECTION_ITEM_HEIGHT)
|
||||
.clickable(
|
||||
enabled = !saving.value && !reorderMode,
|
||||
onClick = {
|
||||
if (chat == null) {
|
||||
ModalManager.start.showModalCloseable { close ->
|
||||
TagListEditor(
|
||||
rhId = rhId,
|
||||
tagId = tag.chatTagId,
|
||||
close = close,
|
||||
emoji = tag.chatTagEmoji,
|
||||
name = tag.chatTagText,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
.padding(PaddingValues(horizontal = DEFAULT_PADDING, vertical = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL)),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (tag.chatTagEmoji != null) {
|
||||
ReactionIcon(tag.chatTagEmoji, fontSize = 14.sp)
|
||||
} else {
|
||||
Icon(painterResource(MR.images.ic_label), null, Modifier.size(18.sp.toDp()), tint = MaterialTheme.colors.onBackground)
|
||||
}
|
||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||
Text(
|
||||
tag.chatTagText,
|
||||
color = MenuTextColor,
|
||||
fontWeight = if (selected) FontWeight.Medium else FontWeight.Normal
|
||||
} else {
|
||||
saving.value = true
|
||||
setTag(rhId = rhId, tagId = if (selected) null else tag.chatTagId, chat = chat, close = {
|
||||
saving.value = false
|
||||
close()
|
||||
})
|
||||
}
|
||||
},
|
||||
)
|
||||
if (selected) {
|
||||
Spacer(Modifier.weight(1f))
|
||||
Icon(painterResource(MR.images.ic_done_filled), null, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
|
||||
} else if (reorderMode) {
|
||||
Spacer(Modifier.weight(1f))
|
||||
Icon(painterResource(MR.images.ic_drag_handle), null, Modifier.size(20.dp), tint = MaterialTheme.colors.secondary)
|
||||
}
|
||||
.padding(PaddingValues(horizontal = DEFAULT_PADDING, vertical = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL)),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (tag.chatTagEmoji != null) {
|
||||
ReactionIcon(tag.chatTagEmoji, fontSize = 14.sp)
|
||||
} else {
|
||||
Icon(painterResource(MR.images.ic_label), null, Modifier.size(18.sp.toDp()), tint = MaterialTheme.colors.onBackground)
|
||||
}
|
||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||
Text(
|
||||
tag.chatTagText,
|
||||
color = MenuTextColor,
|
||||
fontWeight = if (selected) FontWeight.Medium else FontWeight.Normal
|
||||
)
|
||||
if (selected) {
|
||||
Spacer(Modifier.weight(1f))
|
||||
Icon(painterResource(MR.images.ic_done_filled), null, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
|
||||
} else if (reorderMode) {
|
||||
Spacer(Modifier.weight(1f))
|
||||
Icon(painterResource(MR.images.ic_drag_handle), null, Modifier.size(20.dp), tint = MaterialTheme.colors.secondary)
|
||||
}
|
||||
SectionDivider()
|
||||
}
|
||||
Divider(Modifier.padding(horizontal = 8.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!oneHandUI.value && !reorderMode) {
|
||||
item {
|
||||
CreateList()
|
||||
}
|
||||
}
|
||||
if (!oneHandUI.value && !reorderMode) {
|
||||
item {
|
||||
CreateList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -119,7 +119,7 @@ fun DatabaseEncryptionLayout(
|
||||
ChatStoppedView()
|
||||
SectionSpacer()
|
||||
}
|
||||
SectionView(if (migration) generalGetString(MR.strings.database_passphrase) else null) {
|
||||
SectionView(if (migration) generalGetString(MR.strings.database_passphrase) else null, card = true) {
|
||||
SavePassphraseSetting(
|
||||
useKeychain.value,
|
||||
initialRandomDBPassphrase.value,
|
||||
|
||||
+6
-6
@@ -170,7 +170,7 @@ fun DatabaseLayout(
|
||||
AppBarTitle(stringResource(MR.strings.your_chat_database))
|
||||
|
||||
if (!chatModel.desktopNoUserNoRemote) {
|
||||
SectionView(stringResource(MR.strings.messages_section_title)) {
|
||||
SectionView(stringResource(MR.strings.messages_section_title), card = true) {
|
||||
TtlOptions(chatItemTTL, enabled = rememberUpdatedState(!stopped && !progressIndicator), onChatItemTTLSelected)
|
||||
}
|
||||
SectionTextFooter(
|
||||
@@ -184,14 +184,14 @@ fun DatabaseLayout(
|
||||
}
|
||||
}
|
||||
)
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
}
|
||||
val toggleEnabled = remember { chatModel.remoteHosts }.none { it.sessionState is RemoteHostSessionState.Connected }
|
||||
if (chatModel.localUserCreated.value == true) {
|
||||
// still show the toggle in case database was stopped when the user opened this screen because it can be in the following situations:
|
||||
// - database was stopped after migration and the app relaunched
|
||||
// - something wrong happened with database operations and the database couldn't be launched when it should
|
||||
SectionView(stringResource(MR.strings.run_chat_section)) {
|
||||
SectionView(stringResource(MR.strings.run_chat_section), card = true) {
|
||||
if (!toggleEnabled) {
|
||||
SectionItemView(disconnectAllHosts) {
|
||||
Text(generalGetString(MR.strings.disconnect_remote_hosts), Modifier.fillMaxWidth(), color = WarningOrange)
|
||||
@@ -200,10 +200,10 @@ fun DatabaseLayout(
|
||||
RunChatSetting(stopped, toggleEnabled && !progressIndicator, startChat, stopChatAlert)
|
||||
}
|
||||
if (stopped) SectionTextFooter(stringResource(MR.strings.you_must_use_the_most_recent_version_of_database))
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
}
|
||||
|
||||
SectionView(stringResource(MR.strings.chat_database_section)) {
|
||||
SectionView(stringResource(MR.strings.chat_database_section), card = true) {
|
||||
if (chatModel.localUserCreated.value != true && !toggleEnabled) {
|
||||
SectionItemView(disconnectAllHosts) {
|
||||
Text(generalGetString(MR.strings.disconnect_remote_hosts), Modifier.fillMaxWidth(), color = WarningOrange)
|
||||
@@ -262,7 +262,7 @@ fun DatabaseLayout(
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(stringResource(MR.strings.files_and_media_section)) {
|
||||
SectionView(stringResource(MR.strings.files_and_media_section), card = true) {
|
||||
val deleteFilesDisabled = operationsDisabled || appFilesCountAndSize.value.first == 0
|
||||
SectionItemView(
|
||||
deleteAppFilesAndMedia,
|
||||
|
||||
+2
-9
@@ -25,14 +25,7 @@ import dev.icerock.moko.resources.ImageResource
|
||||
import kotlin.math.max
|
||||
|
||||
@Composable
|
||||
private fun defaultProfileIconColor(): Color =
|
||||
if (CurrentColors.value.base == DefaultTheme.LIGHT)
|
||||
MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.91f)
|
||||
else
|
||||
MaterialTheme.colors.secondaryVariant
|
||||
|
||||
@Composable
|
||||
fun ChatInfoImage(chatInfo: ChatInfo, size: Dp, iconColor: Color = defaultProfileIconColor(), shadow: Boolean = false) {
|
||||
fun ChatInfoImage(chatInfo: ChatInfo, size: Dp, iconColor: Color = MaterialTheme.colors.secondaryVariant, shadow: Boolean = false) {
|
||||
val icon =
|
||||
when (chatInfo) {
|
||||
is ChatInfo.Group -> chatInfo.groupInfo.chatIconName
|
||||
@@ -59,7 +52,7 @@ fun ProfileImage(
|
||||
size: Dp,
|
||||
image: String? = null,
|
||||
icon: ImageResource = MR.images.ic_account_circle_filled,
|
||||
color: Color = defaultProfileIconColor(),
|
||||
color: Color = MaterialTheme.colors.secondaryVariant,
|
||||
backgroundColor: Color? = null,
|
||||
blurred: Boolean = false,
|
||||
async: Boolean = false
|
||||
|
||||
+87
-82
@@ -6,8 +6,9 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.layout.Layout
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
@@ -30,41 +31,71 @@ val CARD_PADDING = 16.dp
|
||||
val ICON_TEXT_SPACING = 5.dp
|
||||
val CARD_ITEM_PADDING = CARD_PADDING - 1.dp
|
||||
|
||||
// Set to true by SectionView around its inner Column. SectionItemView reads it
|
||||
// to decide whether to draw the 2dp bottom divider. False default keeps
|
||||
// standalone usage (alerts, pickers, custom contexts) unaffected.
|
||||
internal val LocalInSectionCard = staticCompositionLocalOf { false }
|
||||
|
||||
|
||||
@Composable
|
||||
private fun Modifier.sectionItemDivider(): Modifier {
|
||||
if (!LocalInSectionCard.current) return this
|
||||
return this.drawWithContent {
|
||||
drawContent()
|
||||
drawLine(canvasColorForCurrentTheme(), Offset(0f, size.height), Offset(size.width, size.height), strokeWidth = 2.dp.toPx())
|
||||
private fun CardColumnLayout(
|
||||
contentPadding: PaddingValues = PaddingValues(),
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val dividerColor = canvasColorForCurrentTheme()
|
||||
val dividerPx = with(LocalDensity.current) { 2.dp.toPx() }
|
||||
val childBottoms = remember { mutableListOf<Float>() }
|
||||
Layout(
|
||||
content = content,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = CARD_PADDING)
|
||||
.fillMaxWidth()
|
||||
.clip(SectionCardShape)
|
||||
.background(sectionCardColor())
|
||||
.padding(contentPadding)
|
||||
.drawBehind {
|
||||
for (i in 0 until childBottoms.size - 1) {
|
||||
val y = childBottoms[i]
|
||||
drawLine(dividerColor, Offset(0f, y), Offset(size.width, y), strokeWidth = dividerPx)
|
||||
}
|
||||
}
|
||||
) { measurables, constraints ->
|
||||
val placeables = measurables.map { it.measure(constraints) }
|
||||
childBottoms.clear()
|
||||
var y = 0f
|
||||
placeables.forEach { p ->
|
||||
y += p.height
|
||||
childBottoms.add(y)
|
||||
}
|
||||
layout(constraints.maxWidth, y.toInt()) {
|
||||
var yPos = 0
|
||||
placeables.forEach { p ->
|
||||
p.placeRelative(0, yPos)
|
||||
yPos += p.height
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SectionView(title: String? = null, contentPadding: PaddingValues = PaddingValues(), headerBottomPadding: Dp = 8.dp, content: (@Composable ColumnScope.() -> Unit)) {
|
||||
val cardColor = sectionCardColor()
|
||||
private fun CardColumn(
|
||||
card: Boolean,
|
||||
contentPadding: PaddingValues = PaddingValues(),
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
if (card) {
|
||||
CardColumnLayout(contentPadding, content)
|
||||
} else {
|
||||
Column(Modifier.padding(contentPadding).fillMaxWidth()) { content() }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SectionView(title: String? = null, contentPadding: PaddingValues = PaddingValues(), headerBottomPadding: Dp = DEFAULT_PADDING, card: Boolean = false, content: (@Composable ColumnScope.() -> Unit)) {
|
||||
Column {
|
||||
if (title != null) {
|
||||
Text(
|
||||
title, color = MaterialTheme.colors.secondary, style = MaterialTheme.typography.body2,
|
||||
modifier = Modifier.padding(start = DEFAULT_PADDING + DEFAULT_PADDING_HALF, bottom = headerBottomPadding), fontSize = 14.sp, fontWeight = FontWeight.Medium
|
||||
modifier = Modifier.padding(start = if (card) DEFAULT_PADDING + DEFAULT_PADDING_HALF else DEFAULT_PADDING, bottom = if (card) 8.dp else headerBottomPadding),
|
||||
fontSize = if (card) 14.sp else 12.sp,
|
||||
fontWeight = if (card) FontWeight.Medium else FontWeight.Normal
|
||||
)
|
||||
}
|
||||
CompositionLocalProvider(LocalInSectionCard provides true) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(horizontal = CARD_PADDING)
|
||||
.fillMaxWidth()
|
||||
.clip(SectionCardShape)
|
||||
.background(cardColor)
|
||||
.padding(contentPadding)
|
||||
) { content() }
|
||||
}
|
||||
CardColumn(card, contentPadding) { content() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,37 +106,28 @@ fun SectionView(
|
||||
iconTint: Color = MaterialTheme.colors.secondary,
|
||||
leadingIcon: Boolean = false,
|
||||
padding: PaddingValues = PaddingValues(),
|
||||
card: Boolean = false,
|
||||
content: (@Composable ColumnScope.() -> Unit)
|
||||
) {
|
||||
val cardColor = sectionCardColor()
|
||||
Column {
|
||||
val iconSize = with(LocalDensity.current) { 21.sp.toDp() }
|
||||
Row(Modifier.padding(start = DEFAULT_PADDING + DEFAULT_PADDING_HALF, bottom = 5.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Row(Modifier.padding(start = if (card) DEFAULT_PADDING + DEFAULT_PADDING_HALF else DEFAULT_PADDING, bottom = 5.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
if (leadingIcon) Icon(icon, null, Modifier.padding(end = DEFAULT_PADDING_HALF).size(iconSize), tint = iconTint)
|
||||
Text(title, color = MaterialTheme.colors.secondary, style = MaterialTheme.typography.body2, fontSize = 14.sp, fontWeight = FontWeight.Medium)
|
||||
Text(title, color = MaterialTheme.colors.secondary, style = MaterialTheme.typography.body2, fontSize = if (card) 14.sp else 12.sp, fontWeight = if (card) FontWeight.Medium else FontWeight.Normal)
|
||||
if (!leadingIcon) Icon(icon, null, Modifier.padding(start = DEFAULT_PADDING_HALF).size(iconSize), tint = iconTint)
|
||||
}
|
||||
CompositionLocalProvider(LocalInSectionCard provides true) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(horizontal = CARD_PADDING)
|
||||
.fillMaxWidth()
|
||||
.clip(SectionCardShape)
|
||||
.background(cardColor)
|
||||
.padding(padding)
|
||||
) { content() }
|
||||
}
|
||||
CardColumn(card, padding) { content() }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SectionViewWithButton(title: String? = null, titleButton: (@Composable () -> Unit)?, contentPadding: PaddingValues = PaddingValues(), headerBottomPadding: Dp = 8.dp, content: (@Composable ColumnScope.() -> Unit)) {
|
||||
val cardColor = sectionCardColor()
|
||||
fun SectionViewWithButton(title: String? = null, titleButton: (@Composable () -> Unit)?, contentPadding: PaddingValues = PaddingValues(), headerBottomPadding: Dp = DEFAULT_PADDING, card: Boolean = false, content: (@Composable ColumnScope.() -> Unit)) {
|
||||
Column {
|
||||
if (title != null || titleButton != null) {
|
||||
Row(modifier = Modifier.padding(start = DEFAULT_PADDING + DEFAULT_PADDING_HALF, end = DEFAULT_PADDING + DEFAULT_PADDING_HALF, bottom = headerBottomPadding).fillMaxWidth()) {
|
||||
val hPadding = if (card) DEFAULT_PADDING + DEFAULT_PADDING_HALF else DEFAULT_PADDING
|
||||
Row(modifier = Modifier.padding(start = hPadding, end = hPadding, bottom = if (card) 8.dp else headerBottomPadding).fillMaxWidth()) {
|
||||
if (title != null) {
|
||||
Text(title, color = MaterialTheme.colors.secondary, style = MaterialTheme.typography.body2, fontSize = 14.sp, fontWeight = FontWeight.Medium)
|
||||
Text(title, color = MaterialTheme.colors.secondary, style = MaterialTheme.typography.body2, fontSize = if (card) 14.sp else 12.sp, fontWeight = if (card) FontWeight.Medium else FontWeight.Normal)
|
||||
}
|
||||
if (titleButton != null) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
@@ -113,16 +135,7 @@ fun SectionViewWithButton(title: String? = null, titleButton: (@Composable () ->
|
||||
}
|
||||
}
|
||||
}
|
||||
CompositionLocalProvider(LocalInSectionCard provides true) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(horizontal = CARD_PADDING)
|
||||
.fillMaxWidth()
|
||||
.clip(SectionCardShape)
|
||||
.background(cardColor)
|
||||
.padding(contentPadding)
|
||||
) { content() }
|
||||
}
|
||||
CardColumn(card, contentPadding) { content() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,19 +185,18 @@ fun <T> SectionViewSelectableCards(
|
||||
@Composable
|
||||
fun SectionItemView(
|
||||
click: (() -> Unit)? = null,
|
||||
minHeight: Dp = DEFAULT_MIN_SECTION_ITEM_HEIGHT + 8.dp,
|
||||
minHeight: Dp = DEFAULT_MIN_SECTION_ITEM_HEIGHT,
|
||||
disabled: Boolean = false,
|
||||
extraPadding: Boolean = false,
|
||||
padding: PaddingValues = if (extraPadding)
|
||||
PaddingValues(start = DEFAULT_PADDING * 1.7f, end = CARD_ITEM_PADDING, top = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL, bottom = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL)
|
||||
PaddingValues(start = DEFAULT_PADDING * 1.7f, end = DEFAULT_PADDING, top = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL, bottom = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL)
|
||||
else
|
||||
PaddingValues(horizontal = CARD_ITEM_PADDING, vertical = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL),
|
||||
PaddingValues(horizontal = DEFAULT_PADDING, vertical = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL),
|
||||
content: (@Composable RowScope.() -> Unit)
|
||||
) {
|
||||
val modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.sizeIn(minHeight = minHeight)
|
||||
.sectionItemDivider()
|
||||
Row(
|
||||
if (click == null || disabled) modifier.padding(padding) else modifier.clickable(onClick = click).padding(padding),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
@@ -196,13 +208,13 @@ fun SectionItemView(
|
||||
@Composable
|
||||
fun SectionItemViewWithoutMinPadding(
|
||||
click: (() -> Unit)? = null,
|
||||
minHeight: Dp = DEFAULT_MIN_SECTION_ITEM_HEIGHT + 8.dp,
|
||||
minHeight: Dp = DEFAULT_MIN_SECTION_ITEM_HEIGHT,
|
||||
disabled: Boolean = false,
|
||||
extraPadding: Boolean = false,
|
||||
padding: PaddingValues = if (extraPadding)
|
||||
PaddingValues(start = DEFAULT_PADDING * 1.7f, end = CARD_ITEM_PADDING)
|
||||
PaddingValues(start = DEFAULT_PADDING * 1.7f, end = DEFAULT_PADDING)
|
||||
else
|
||||
PaddingValues(horizontal = CARD_ITEM_PADDING),
|
||||
PaddingValues(horizontal = DEFAULT_PADDING),
|
||||
content: (@Composable RowScope.() -> Unit)
|
||||
) {
|
||||
SectionItemView(click, minHeight, disabled, extraPadding, padding, content)
|
||||
@@ -212,19 +224,18 @@ fun SectionItemViewWithoutMinPadding(
|
||||
fun SectionItemViewLongClickable(
|
||||
click: () -> Unit,
|
||||
longClick: () -> Unit,
|
||||
minHeight: Dp = DEFAULT_MIN_SECTION_ITEM_HEIGHT + 8.dp,
|
||||
minHeight: Dp = DEFAULT_MIN_SECTION_ITEM_HEIGHT,
|
||||
disabled: Boolean = false,
|
||||
extraPadding: Boolean = false,
|
||||
padding: PaddingValues = if (extraPadding)
|
||||
PaddingValues(start = DEFAULT_PADDING * 1.7f, end = CARD_ITEM_PADDING, top = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL, bottom = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL)
|
||||
PaddingValues(start = DEFAULT_PADDING * 1.7f, end = DEFAULT_PADDING, top = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL, bottom = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL)
|
||||
else
|
||||
PaddingValues(horizontal = CARD_ITEM_PADDING, vertical = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL),
|
||||
PaddingValues(horizontal = DEFAULT_PADDING, vertical = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL),
|
||||
content: (@Composable RowScope.() -> Unit)
|
||||
) {
|
||||
val modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.sizeIn(minHeight = minHeight)
|
||||
.sectionItemDivider()
|
||||
Row(
|
||||
if (disabled) {
|
||||
modifier.padding(padding)
|
||||
@@ -241,15 +252,14 @@ fun SectionItemViewLongClickable(
|
||||
fun SectionItemViewSpaceBetween(
|
||||
click: (() -> Unit)? = null,
|
||||
onLongClick: (() -> Unit)? = null,
|
||||
minHeight: Dp = DEFAULT_MIN_SECTION_ITEM_HEIGHT + 8.dp,
|
||||
padding: PaddingValues = PaddingValues(horizontal = CARD_ITEM_PADDING),
|
||||
minHeight: Dp = DEFAULT_MIN_SECTION_ITEM_HEIGHT,
|
||||
padding: PaddingValues = PaddingValues(horizontal = DEFAULT_PADDING),
|
||||
disabled: Boolean = false,
|
||||
content: (@Composable RowScope.() -> Unit)
|
||||
) {
|
||||
val modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.sizeIn(minHeight = minHeight)
|
||||
.sectionItemDivider()
|
||||
Row(
|
||||
if (click == null || disabled) modifier.padding(padding).padding(vertical = DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL) else modifier
|
||||
.combinedClickable(onClick = click, onLongClick = onLongClick).padding(padding)
|
||||
@@ -297,7 +307,7 @@ fun SectionTextFooter(text: String, color: Color = MaterialTheme.colors.secondar
|
||||
fun SectionTextFooter(text: AnnotatedString, textAlign: TextAlign = TextAlign.Start, color: Color = MaterialTheme.colors.secondary) {
|
||||
Text(
|
||||
text,
|
||||
Modifier.padding(start = DEFAULT_PADDING + DEFAULT_PADDING_HALF, end = DEFAULT_PADDING + DEFAULT_PADDING_HALF, top = DEFAULT_PADDING_HALF).fillMaxWidth(0.9F),
|
||||
Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, top = DEFAULT_PADDING_HALF).fillMaxWidth(0.9F),
|
||||
color = color,
|
||||
lineHeight = 18.sp,
|
||||
fontSize = 14.sp,
|
||||
@@ -306,7 +316,7 @@ fun SectionTextFooter(text: AnnotatedString, textAlign: TextAlign = TextAlign.St
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SectionCustomFooter(padding: PaddingValues = PaddingValues(start = DEFAULT_PADDING + DEFAULT_PADDING_HALF, end = DEFAULT_PADDING + DEFAULT_PADDING_HALF, top = 5.dp), content: (@Composable () -> Unit)) {
|
||||
fun SectionCustomFooter(padding: PaddingValues = PaddingValues(start = DEFAULT_PADDING, end = DEFAULT_PADDING, top = 5.dp), content: (@Composable () -> Unit)) {
|
||||
Row(
|
||||
Modifier.padding(padding)
|
||||
) {
|
||||
@@ -314,20 +324,15 @@ fun SectionCustomFooter(padding: PaddingValues = PaddingValues(start = DEFAULT_P
|
||||
}
|
||||
}
|
||||
|
||||
// Explicit 2dp canvas-color divider for inserting between non-SectionItemView
|
||||
// composables inside a SectionView card (e.g., between a custom block and a
|
||||
// SectionItemView). Auto-divider on SectionItemView handles the row-to-row
|
||||
// case; this one covers manual placement around mixed content. No-op outside
|
||||
// a SectionView card.
|
||||
@Composable
|
||||
fun SectionDivider() {
|
||||
if (!LocalInSectionCard.current) return
|
||||
Box(Modifier.fillMaxWidth().height(2.dp).background(canvasColorForCurrentTheme()))
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SectionDividerSpaced(maxTopPadding: Boolean = false, maxBottomPadding: Boolean = true) {
|
||||
Spacer(Modifier.height(if (maxTopPadding || maxBottomPadding) DEFAULT_PADDING else DEFAULT_PADDING_HALF))
|
||||
Divider(
|
||||
Modifier.padding(
|
||||
start = DEFAULT_PADDING_HALF,
|
||||
top = if (maxTopPadding) DEFAULT_PADDING + 18.dp else DEFAULT_PADDING + 2.dp,
|
||||
end = DEFAULT_PADDING_HALF,
|
||||
bottom = if (maxBottomPadding) DEFAULT_PADDING + 18.dp else DEFAULT_PADDING + 2.dp)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -342,11 +347,11 @@ fun SectionBottomSpacer() {
|
||||
|
||||
@Composable
|
||||
fun TextIconSpaced(extraPadding: Boolean = false) {
|
||||
Spacer(Modifier.padding(horizontal = if (extraPadding) 17.dp else ICON_TEXT_SPACING))
|
||||
Spacer(Modifier.padding(horizontal = if (extraPadding) 17.dp else DEFAULT_PADDING_HALF))
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InfoRow(title: String, value: String, icon: Painter? = null, iconTint: Color? = null, textColor: Color = MaterialTheme.colors.onBackground, padding: PaddingValues = PaddingValues(horizontal = CARD_ITEM_PADDING)) {
|
||||
fun InfoRow(title: String, value: String, icon: Painter? = null, iconTint: Color? = null, textColor: Color = MaterialTheme.colors.onBackground, padding: PaddingValues = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
SectionItemViewSpaceBetween(padding = padding) {
|
||||
Row {
|
||||
val iconSize = with(LocalDensity.current) { 21.sp.toDp() }
|
||||
|
||||
+2
-10
@@ -329,7 +329,6 @@ fun ModalData.ChatWallpaperEditor(
|
||||
ThemeManager.currentColors(type, if (type?.sameType(themeModeOverride.value.type) == true) themeModeOverride.value else null, chatModel.currentUser.value?.uiThemes, appPrefs.themeOverrides.get())
|
||||
}
|
||||
|
||||
SectionView {
|
||||
WallpaperPresetSelector(
|
||||
selectedWallpaper = currentTheme.wallpaper.type,
|
||||
activeBackgroundColor = currentTheme.wallpaper.background,
|
||||
@@ -368,11 +367,9 @@ fun ModalData.ChatWallpaperEditor(
|
||||
editColor = editColor,
|
||||
onTypeChange = onTypeChange,
|
||||
)
|
||||
}
|
||||
|
||||
SectionSpacer()
|
||||
|
||||
SectionView {
|
||||
if (!globalThemeUsed.value) {
|
||||
ResetToGlobalThemeButton(remember { chatModel.currentUser }.value?.uiThemes?.preferredMode(isInDarkTheme()) == null) {
|
||||
themeModeOverride.value = ThemeManager.defaultActiveTheme(chatModel.currentUser.value?.uiThemes, appPrefs.themeOverrides.get())
|
||||
@@ -396,7 +393,6 @@ fun ModalData.ChatWallpaperEditor(
|
||||
save(themeModeOverride.value.mode, themeModeOverride.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KeyChangeEffect(theme.mode) {
|
||||
themeModeOverride.value = theme
|
||||
@@ -424,7 +420,6 @@ fun ModalData.ChatWallpaperEditor(
|
||||
)
|
||||
)
|
||||
}
|
||||
SectionView {
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.chat_theme_apply_to_mode),
|
||||
values,
|
||||
@@ -440,7 +435,6 @@ fun ModalData.ChatWallpaperEditor(
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
SectionDividerSpaced()
|
||||
|
||||
@@ -454,9 +448,7 @@ fun ModalData.ChatWallpaperEditor(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SectionView {
|
||||
AdvancedSettingsButton { showMore = true }
|
||||
}
|
||||
AdvancedSettingsButton { showMore = true }
|
||||
}
|
||||
|
||||
SectionBottomSpacer()
|
||||
@@ -465,7 +457,7 @@ fun ModalData.ChatWallpaperEditor(
|
||||
|
||||
@Composable
|
||||
private fun ImportExportThemeSection(perChat: ThemeModeOverride?, perUser: ThemeModeOverrides?, save: (ThemeModeOverride) -> Unit) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
val theme = remember { mutableStateOf(null as String?) }
|
||||
val exportThemeLauncher = rememberFileChooserLauncher(false) { to: URI? ->
|
||||
val themeValue = theme.value
|
||||
|
||||
+21
-21
@@ -182,7 +182,7 @@ private fun SectionByState(
|
||||
@Composable
|
||||
private fun MutableState<MigrationFromState>.ChatStopInProgressView() {
|
||||
Box {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_stopping_chat)) {}
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_stopping_chat), card = true) {}
|
||||
ProgressView()
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -192,7 +192,7 @@ private fun MutableState<MigrationFromState>.ChatStopInProgressView() {
|
||||
|
||||
@Composable
|
||||
private fun MutableState<MigrationFromState>.ChatStopFailedView(reason: String) {
|
||||
SectionView(stringResource(MR.strings.error_stopping_chat)) {
|
||||
SectionView(stringResource(MR.strings.error_stopping_chat), card = true) {
|
||||
Text(reason)
|
||||
SectionSpacer()
|
||||
SettingsActionItemWithContent(
|
||||
@@ -201,8 +201,8 @@ private fun MutableState<MigrationFromState>.ChatStopFailedView(reason: String)
|
||||
textColor = MaterialTheme.colors.error,
|
||||
click = ::stopChat
|
||||
){}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_from_device_chat_should_be_stopped))
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_from_device_chat_should_be_stopped))
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -226,7 +226,7 @@ private fun MutableState<MigrationFromState>.PassphraseConfirmationView() {
|
||||
ChatStoppedView()
|
||||
SectionSpacer()
|
||||
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_verify_database_passphrase)) {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_verify_database_passphrase), card = true) {
|
||||
PassphraseField(currentKey, placeholder = stringResource(MR.strings.current_passphrase), Modifier.padding(horizontal = DEFAULT_PADDING), isValid = ::validKey, requestFocus = true)
|
||||
|
||||
SettingsActionItemWithContent(
|
||||
@@ -243,8 +243,8 @@ private fun MutableState<MigrationFromState>.PassphraseConfirmationView() {
|
||||
}
|
||||
}
|
||||
) {}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_from_device_confirm_you_remember_passphrase))
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_from_device_confirm_you_remember_passphrase))
|
||||
}
|
||||
if (verifyingPassphrase.value) {
|
||||
ProgressView()
|
||||
@@ -254,21 +254,21 @@ private fun MutableState<MigrationFromState>.PassphraseConfirmationView() {
|
||||
|
||||
@Composable
|
||||
private fun MutableState<MigrationFromState>.UploadConfirmationView() {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_confirm_upload)) {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_confirm_upload), card = true) {
|
||||
SettingsActionItemWithContent(
|
||||
icon = painterResource(MR.images.ic_ios_share),
|
||||
text = stringResource(MR.strings.migrate_from_device_archive_and_upload),
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
click = { state = MigrationFromState.Archiving }
|
||||
){}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_from_device_all_data_will_be_uploaded))
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_from_device_all_data_will_be_uploaded))
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MutableState<MigrationFromState>.ArchivingView() {
|
||||
Box {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_archiving_database)) {}
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_archiving_database), card = true) {}
|
||||
ProgressView()
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -279,7 +279,7 @@ private fun MutableState<MigrationFromState>.ArchivingView() {
|
||||
@Composable
|
||||
private fun MutableState<MigrationFromState>.DatabaseInitView(tempDatabaseFile: File, totalBytes: Long, archivePath: String) {
|
||||
Box {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_database_init)) {}
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_database_init), card = true) {}
|
||||
ProgressView()
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -298,7 +298,7 @@ private fun MutableState<MigrationFromState>.UploadProgressView(
|
||||
archivePath: String,
|
||||
) {
|
||||
Box {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_uploading_archive)) {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_uploading_archive), card = true) {
|
||||
val ratio = uploadedBytes.toFloat() / max(totalBytes, 1)
|
||||
LargeProgressView(ratio, "${(ratio * 100).toInt()}%", stringResource(MR.strings.migrate_from_device_bytes_uploaded).format(formatBytes(uploadedBytes)))
|
||||
}
|
||||
@@ -310,7 +310,7 @@ private fun MutableState<MigrationFromState>.UploadProgressView(
|
||||
|
||||
@Composable
|
||||
private fun MutableState<MigrationFromState>.UploadFailedView(totalBytes: Long, archivePath: String, chatReceiver: MigrationFromChatReceiver?) {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_upload_failed)) {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_upload_failed), card = true) {
|
||||
SettingsActionItemWithContent(
|
||||
icon = painterResource(MR.images.ic_ios_share),
|
||||
text = stringResource(MR.strings.migrate_from_device_repeat_upload),
|
||||
@@ -319,8 +319,8 @@ private fun MutableState<MigrationFromState>.UploadFailedView(totalBytes: Long,
|
||||
state = MigrationFromState.DatabaseInit(totalBytes, archivePath)
|
||||
}
|
||||
) {}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_from_device_try_again))
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_from_device_try_again))
|
||||
LaunchedEffect(Unit) {
|
||||
chatReceiver?.stopAndCleanUp()
|
||||
}
|
||||
@@ -329,14 +329,14 @@ private fun MutableState<MigrationFromState>.UploadFailedView(totalBytes: Long,
|
||||
@Composable
|
||||
private fun LinkCreationView() {
|
||||
Box {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_creating_archive_link)) {}
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_creating_archive_link), card = true) {}
|
||||
ProgressView()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MutableState<MigrationFromState>.LinkShownView(fileId: Long, link: String, ctrl: ChatCtrl, chatReceiver: MigrationFromChatReceiver?) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
SettingsActionItemWithContent(
|
||||
icon = painterResource(MR.images.ic_close),
|
||||
text = stringResource(MR.strings.migrate_from_device_cancel_migration),
|
||||
@@ -361,15 +361,15 @@ private fun MutableState<MigrationFromState>.LinkShownView(fileId: Long, link: S
|
||||
)
|
||||
}
|
||||
) {}
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.migrate_from_device_archive_will_be_deleted))
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.migrate_from_device_choose_migrate_from_another_device))
|
||||
}
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.migrate_from_device_archive_will_be_deleted))
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.migrate_from_device_choose_migrate_from_another_device))
|
||||
SectionSpacer()
|
||||
SectionView(stringResource(MR.strings.show_QR_code)) {
|
||||
SectionView(stringResource(MR.strings.show_QR_code), card = true) {
|
||||
SimpleXLinkQRCode(link, onShare = {})
|
||||
}
|
||||
SectionSpacer()
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_or_share_this_file_link)) {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_or_share_this_file_link), card = true) {
|
||||
LinkTextView(link, true)
|
||||
}
|
||||
}
|
||||
@@ -377,7 +377,7 @@ private fun MutableState<MigrationFromState>.LinkShownView(fileId: Long, link: S
|
||||
@Composable
|
||||
private fun MutableState<MigrationFromState>.FinishedView(chatDeletion: Boolean) {
|
||||
Box {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_migration_complete)) {
|
||||
SectionView(stringResource(MR.strings.migrate_from_device_migration_complete), card = true) {
|
||||
SettingsActionItemWithContent(
|
||||
icon = painterResource(MR.images.ic_play_arrow_filled),
|
||||
text = stringResource(MR.strings.migrate_from_device_start_chat),
|
||||
@@ -410,9 +410,9 @@ private fun MutableState<MigrationFromState>.FinishedView(chatDeletion: Boolean)
|
||||
)
|
||||
}
|
||||
) {}
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.migrate_from_device_you_must_not_start_database_on_two_device))
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.migrate_from_device_using_on_two_device_breaks_encryption))
|
||||
}
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.migrate_from_device_you_must_not_start_database_on_two_device))
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.migrate_from_device_using_on_two_device_breaks_encryption))
|
||||
if (chatDeletion) {
|
||||
ProgressView()
|
||||
}
|
||||
|
||||
+18
-18
@@ -201,7 +201,7 @@ private fun MutableState<MigrationToState?>.PasteOrScanLinkView(close: () -> Uni
|
||||
val progressIndicator = remember { mutableStateOf(false) }
|
||||
Column {
|
||||
if (appPlatform.isAndroid) {
|
||||
SectionView(stringResource(MR.strings.scan_QR_code).replace('\n', ' ')) {
|
||||
SectionView(stringResource(MR.strings.scan_QR_code).replace('\n', ' '), card = true) {
|
||||
QRCodeScanner(showQRCodeScanner = remember { mutableStateOf(true) }) { text ->
|
||||
checkUserLink(text)
|
||||
}
|
||||
@@ -209,12 +209,12 @@ private fun MutableState<MigrationToState?>.PasteOrScanLinkView(close: () -> Uni
|
||||
SectionSpacer()
|
||||
}
|
||||
|
||||
SectionView(stringResource(if (appPlatform.isAndroid) MR.strings.or_paste_archive_link else MR.strings.paste_archive_link)) {
|
||||
SectionView(stringResource(if (appPlatform.isAndroid) MR.strings.or_paste_archive_link else MR.strings.paste_archive_link), card = true) {
|
||||
PasteLinkView()
|
||||
}
|
||||
SectionSpacer()
|
||||
|
||||
SectionView(stringResource(MR.strings.chat_archive)) {
|
||||
SectionView(stringResource(MR.strings.chat_archive), card = true) {
|
||||
ArchiveImportView(progressIndicator, close)
|
||||
}
|
||||
}
|
||||
@@ -280,7 +280,7 @@ private fun ModalData.OnionView(link: String, legacyLinkSocksProxy: String?, lin
|
||||
mutableStateOf(getNetCfg().withOnionHosts(onionHosts.value).copy(socksProxy = linkNetworkProxy?.toProxyString() ?: legacyLinkSocksProxy, sessionMode = sessionMode.value))
|
||||
}
|
||||
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_confirm_network_settings)) {
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_confirm_network_settings), card = true) {
|
||||
SettingsActionItemWithContent(
|
||||
icon = painterResource(MR.images.ic_check),
|
||||
text = stringResource(MR.strings.migrate_to_device_apply_onion),
|
||||
@@ -297,15 +297,15 @@ private fun ModalData.OnionView(link: String, legacyLinkSocksProxy: String?, lin
|
||||
}
|
||||
}
|
||||
){}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_to_device_confirm_network_settings_footer))
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_to_device_confirm_network_settings_footer))
|
||||
|
||||
SectionSpacer()
|
||||
|
||||
val networkProxyPref = SharedPreference(get = { networkProxy.value }, set = {
|
||||
networkProxy.value = it
|
||||
})
|
||||
SectionView(stringResource(MR.strings.network_settings_title)) {
|
||||
SectionView(stringResource(MR.strings.network_settings_title), card = true) {
|
||||
OnionRelatedLayout(
|
||||
appPreferences.developerTools.get(),
|
||||
networkUseSocksProxy,
|
||||
@@ -325,7 +325,7 @@ private fun ModalData.OnionView(link: String, legacyLinkSocksProxy: String?, lin
|
||||
@Composable
|
||||
private fun MutableState<MigrationToState?>.DatabaseInitView(link: String, tempDatabaseFile: File, netCfg: NetCfg, networkProxy: NetworkProxy?) {
|
||||
Box {
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_database_init)) {}
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_database_init), card = true) {}
|
||||
ProgressView()
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -345,7 +345,7 @@ private fun MutableState<MigrationToState?>.LinkDownloadingView(
|
||||
networkProxy: NetworkProxy?
|
||||
) {
|
||||
Box {
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_downloading_details)) {}
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_downloading_details), card = true) {}
|
||||
ProgressView()
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -356,7 +356,7 @@ private fun MutableState<MigrationToState?>.LinkDownloadingView(
|
||||
@Composable
|
||||
private fun DownloadProgressView(downloadedBytes: Long, totalBytes: Long) {
|
||||
Box {
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_downloading_archive)) {
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_downloading_archive), card = true) {
|
||||
val ratio = downloadedBytes.toFloat() / max(totalBytes, 1)
|
||||
LargeProgressView(ratio, "${(ratio * 100).toInt()}%", stringResource(MR.strings.migrate_to_device_bytes_downloaded).format(formatBytes(downloadedBytes)))
|
||||
}
|
||||
@@ -365,7 +365,7 @@ private fun DownloadProgressView(downloadedBytes: Long, totalBytes: Long) {
|
||||
|
||||
@Composable
|
||||
private fun MutableState<MigrationToState?>.DownloadFailedView(link: String, chatReceiver: MigrationToChatReceiver?, archivePath: String, netCfg: NetCfg, networkProxy: NetworkProxy?) {
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_download_failed)) {
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_download_failed), card = true) {
|
||||
SettingsActionItemWithContent(
|
||||
icon = painterResource(MR.images.ic_download),
|
||||
text = stringResource(MR.strings.migrate_to_device_repeat_download),
|
||||
@@ -374,8 +374,8 @@ private fun MutableState<MigrationToState?>.DownloadFailedView(link: String, cha
|
||||
state = MigrationToState.DatabaseInit(link, netCfg, networkProxy)
|
||||
}
|
||||
) {}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_to_device_try_again))
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_to_device_try_again))
|
||||
LaunchedEffect(Unit) {
|
||||
chatReceiver?.stopAndCleanUp()
|
||||
File(archivePath).delete()
|
||||
@@ -386,7 +386,7 @@ private fun MutableState<MigrationToState?>.DownloadFailedView(link: String, cha
|
||||
@Composable
|
||||
private fun MutableState<MigrationToState?>.ArchiveImportView(archivePath: String, netCfg: NetCfg, networkProxy: NetworkProxy?) {
|
||||
Box {
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_importing_archive)) {}
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_importing_archive).uppercase()) {}
|
||||
ProgressView()
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -396,7 +396,7 @@ private fun MutableState<MigrationToState?>.ArchiveImportView(archivePath: Strin
|
||||
|
||||
@Composable
|
||||
private fun MutableState<MigrationToState?>.ArchiveImportFailedView(archivePath: String, netCfg: NetCfg, networkProxy: NetworkProxy?) {
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_import_failed)) {
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_import_failed).uppercase()) {
|
||||
SettingsActionItemWithContent(
|
||||
icon = painterResource(MR.images.ic_download),
|
||||
text = stringResource(MR.strings.migrate_to_device_repeat_import),
|
||||
@@ -405,8 +405,8 @@ private fun MutableState<MigrationToState?>.ArchiveImportFailedView(archivePath:
|
||||
state = MigrationToState.ArchiveImport(archivePath, netCfg, networkProxy)
|
||||
}
|
||||
) {}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_to_device_try_again))
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.migrate_to_device_try_again))
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -417,7 +417,7 @@ private fun MutableState<MigrationToState?>.PassphraseEnteringView(currentKey: S
|
||||
|
||||
Box {
|
||||
val view = LocalMultiplatformView()
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_enter_passphrase)) {
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_enter_passphrase), card = true) {
|
||||
SavePassphraseSetting(
|
||||
useKeychain.value,
|
||||
false,
|
||||
@@ -489,7 +489,7 @@ private fun MutableState<MigrationToState?>.MigrationConfirmationView(status: DB
|
||||
}
|
||||
else -> Tuple4(generalGetString(MR.strings.error), null, generalGetString(MR.strings.unknown_error), null)
|
||||
}
|
||||
SectionView(header) {
|
||||
SectionView(header, card = true) {
|
||||
if (button != null && confirmation != null) {
|
||||
SettingsActionItemWithContent(
|
||||
icon = painterResource(MR.images.ic_download),
|
||||
@@ -500,14 +500,14 @@ private fun MutableState<MigrationToState?>.MigrationConfirmationView(status: DB
|
||||
}
|
||||
) {}
|
||||
}
|
||||
SectionTextFooter(footer)
|
||||
}
|
||||
SectionTextFooter(footer)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MigrationView(passphrase: String, confirmation: MigrationConfirmation, useKeychain: Boolean, netCfg: NetCfg, networkProxy: NetworkProxy?, close: () -> Unit) {
|
||||
Box {
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_migrating)) {}
|
||||
SectionView(stringResource(MR.strings.migrate_to_device_migrating), card = true) {}
|
||||
ProgressView()
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
|
||||
+2
-3
@@ -257,7 +257,7 @@ private fun ProfileStepView(
|
||||
sheetState = bottomSheetModalState,
|
||||
sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp)
|
||||
) {
|
||||
ModalView(close = close, background = MaterialTheme.colors.surface) {
|
||||
ModalView(close = close) {
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(generalGetString(MR.strings.create_channel_title), bottomPadding = DEFAULT_PADDING_HALF)
|
||||
Row(
|
||||
@@ -403,7 +403,6 @@ private fun ProgressStepView(
|
||||
|
||||
ModalView(
|
||||
close = { showCancelAlert() },
|
||||
background = MaterialTheme.colors.surface,
|
||||
showClose = false,
|
||||
) {
|
||||
ColumnWithScrollBar {
|
||||
@@ -568,7 +567,7 @@ private fun LinkStepView(
|
||||
}
|
||||
}
|
||||
}
|
||||
ModalView(close = close, background = MaterialTheme.colors.surface, showClose = false) {
|
||||
ModalView(close = close, showClose = false) {
|
||||
GroupLinkView(
|
||||
chatModel = chatModel,
|
||||
rhId = null,
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ fun AddGroupLayout(
|
||||
sheetState = bottomSheetModalState,
|
||||
sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp)
|
||||
) {
|
||||
ModalView(close = close, background = MaterialTheme.colors.surface) {
|
||||
ModalView(close = close) {
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(MR.strings.create_secret_group_title), hostDevice(rhId), bottomPadding = DEFAULT_PADDING_HALF)
|
||||
Row(
|
||||
|
||||
+4
-3
@@ -131,7 +131,8 @@ private fun ContactConnectionInfoLayout(
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
SectionViewWithButton(
|
||||
stringResource(MR.strings.one_time_link),
|
||||
titleButton = if (connLink.connShortLink == null) null else {{ ToggleShortLinkButton(showShortLink) }}
|
||||
titleButton = if (connLink.connShortLink == null) null else {{ ToggleShortLinkButton(showShortLink) }},
|
||||
card = true
|
||||
) {
|
||||
SimpleXCreatedLinkQRCode(connLink, short = showShortLink.value)
|
||||
incognitoEnabled()
|
||||
@@ -139,14 +140,14 @@ private fun ContactConnectionInfoLayout(
|
||||
OneTimeLinkLearnMoreButton(learnMore)
|
||||
}
|
||||
} else {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
incognitoEnabled()
|
||||
OneTimeLinkLearnMoreButton(learnMore)
|
||||
}
|
||||
}
|
||||
SectionTextFooter(sharedProfileInfo(chatModel, contactConnection.incognito))
|
||||
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
|
||||
|
||||
DeleteButton(deleteConnection)
|
||||
|
||||
|
||||
+30
-34
@@ -224,7 +224,7 @@ private fun ModalData.NewChatSheetLayout(
|
||||
}
|
||||
}
|
||||
if (deletedChats.isNotEmpty()) {
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SectionView {
|
||||
SectionItemView(
|
||||
click = {
|
||||
@@ -322,26 +322,23 @@ private fun ModalData.NewChatSheetLayout(
|
||||
item {
|
||||
DeletedChatsItem(actionButtonsOriginal.asReversed())
|
||||
}
|
||||
if (filteredContactChats.isNotEmpty()) {
|
||||
if (searchText.value.text.isEmpty()) {
|
||||
item {
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.contact_list_header_title), headerBottomPadding = DEFAULT_PADDING_HALF) {}
|
||||
item {
|
||||
if (filteredContactChats.isNotEmpty() && searchText.value.text.isEmpty()) {
|
||||
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false)
|
||||
SectionView(stringResource(MR.strings.contact_list_header_title).uppercase(), headerBottomPadding = DEFAULT_PADDING_HALF) {}
|
||||
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
|
||||
}
|
||||
}
|
||||
item {
|
||||
NoFilteredContactsItem()
|
||||
}
|
||||
itemsIndexed(filteredContactChats) { index, chat ->
|
||||
val nextChatSelected = remember(chat.id, filteredContactChats) {
|
||||
derivedStateOf {
|
||||
chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value
|
||||
}
|
||||
}
|
||||
itemsIndexed(filteredContactChats) { index, chat ->
|
||||
val nextChatSelected = remember(chat.id, filteredContactChats) {
|
||||
derivedStateOf {
|
||||
chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value
|
||||
}
|
||||
}
|
||||
ContactListNavLinkView(chat, nextChatSelected, showDeletedChatIcon = true)
|
||||
}
|
||||
if (searchText.value.text.isEmpty()) {
|
||||
item { Spacer(Modifier.height(DEFAULT_PADDING_HALF)) }
|
||||
}
|
||||
} else {
|
||||
item { NoFilteredContactsItem() }
|
||||
ContactListNavLinkView(chat, nextChatSelected, showDeletedChatIcon = true)
|
||||
}
|
||||
if (appPlatform.isAndroid) {
|
||||
item {
|
||||
@@ -410,23 +407,22 @@ private fun ModalData.NewChatSheetLayout(
|
||||
item {
|
||||
DeletedChatsItem(actionButtonsOriginal)
|
||||
}
|
||||
if (filteredContactChats.isNotEmpty()) {
|
||||
if (searchText.value.text.isEmpty()) {
|
||||
item {
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.contact_list_header_title), headerBottomPadding = DEFAULT_PADDING_HALF) {}
|
||||
item {
|
||||
if (filteredContactChats.isNotEmpty() && searchText.value.text.isEmpty()) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.contact_list_header_title).uppercase(), headerBottomPadding = DEFAULT_PADDING_HALF) {}
|
||||
}
|
||||
}
|
||||
item {
|
||||
NoFilteredContactsItem()
|
||||
}
|
||||
itemsIndexed(filteredContactChats) { index, chat ->
|
||||
val nextChatSelected = remember(chat.id, filteredContactChats) {
|
||||
derivedStateOf {
|
||||
chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value
|
||||
}
|
||||
}
|
||||
itemsIndexed(filteredContactChats) { index, chat ->
|
||||
val nextChatSelected = remember(chat.id, filteredContactChats) {
|
||||
derivedStateOf {
|
||||
chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value
|
||||
}
|
||||
}
|
||||
ContactListNavLinkView(chat, nextChatSelected, showDeletedChatIcon = true)
|
||||
}
|
||||
} else {
|
||||
item { NoFilteredContactsItem() }
|
||||
ContactListNavLinkView(chat, nextChatSelected, showDeletedChatIcon = true)
|
||||
}
|
||||
if (appPlatform.isAndroid) {
|
||||
item {
|
||||
|
||||
+5
-5
@@ -495,14 +495,14 @@ private fun InviteView(rhId: Long?, connLinkInvitation: CreatedConnLink, contact
|
||||
)
|
||||
SimpleXCreatedLinkQRCode(connLinkInvitation, short = showShortLink.value, onShare = { chatModel.markShowingInvitationUsed() })
|
||||
} else {
|
||||
SectionView(stringResource(MR.strings.share_this_1_time_link), headerBottomPadding = 5.dp) {
|
||||
SectionView(stringResource(MR.strings.share_this_1_time_link).uppercase(), headerBottomPadding = 5.dp) {
|
||||
LinkTextView(connLinkInvitation.simplexChatUri(short = showShortLink.value), true)
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
|
||||
SectionViewWithButton(
|
||||
stringResource(MR.strings.or_show_this_qr_code),
|
||||
stringResource(MR.strings.or_show_this_qr_code).uppercase(),
|
||||
titleButton = if (connLinkInvitation.connShortLink != null) {{ ToggleShortLinkButton(showShortLink) }} else null
|
||||
) {
|
||||
SimpleXCreatedLinkQRCode(connLinkInvitation, short = showShortLink.value, onShare = { chatModel.markShowingInvitationUsed() })
|
||||
@@ -519,7 +519,7 @@ private fun InviteView(rhId: Long?, connLinkInvitation: CreatedConnLink, contact
|
||||
val currentUser = remember { chatModel.currentUser }.value
|
||||
|
||||
if (currentUser != null) {
|
||||
SectionView(stringResource(MR.strings.new_chat_share_profile), headerBottomPadding = 5.dp) {
|
||||
SectionView(stringResource(MR.strings.new_chat_share_profile).uppercase(), headerBottomPadding = 5.dp) {
|
||||
SectionItemView(
|
||||
padding = PaddingValues(
|
||||
top = 0.dp,
|
||||
@@ -643,14 +643,14 @@ private fun ConnectView(rhId: Long?, showQRCodeScanner: MutableState<Boolean>, p
|
||||
)
|
||||
}
|
||||
|
||||
SectionView(stringResource(MR.strings.paste_the_link_you_received), headerBottomPadding = 5.dp) {
|
||||
SectionView(stringResource(MR.strings.paste_the_link_you_received).uppercase(), headerBottomPadding = 5.dp) {
|
||||
PasteLinkView(rhId, pastedLink, showQRCodeScanner, close)
|
||||
}
|
||||
|
||||
if (appPlatform.isAndroid) {
|
||||
Spacer(Modifier.height(10.dp))
|
||||
|
||||
SectionView(stringResource(MR.strings.or_scan_qr_code), headerBottomPadding = 5.dp) {
|
||||
SectionView(stringResource(MR.strings.or_scan_qr_code).uppercase(), headerBottomPadding = 5.dp) {
|
||||
QRCodeScanner(showQRCodeScanner) { text ->
|
||||
val linkVerified = verifyOnly(text)
|
||||
if (!linkVerified) {
|
||||
|
||||
+1
-1
@@ -373,7 +373,7 @@ private fun ChooseServerOperatorsInfoView() {
|
||||
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(title = stringResource(MR.strings.onboarding_network_about_operators)) {
|
||||
SectionView(title = stringResource(MR.strings.onboarding_network_about_operators), card = true) {
|
||||
chatModel.conditions.value.serverOperators.forEach { op ->
|
||||
ServerOperatorRow(op)
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import dev.icerock.moko.resources.StringResource
|
||||
|
||||
@Composable
|
||||
fun HowItWorks(user: User?, onboardingStage: SharedPreference<OnboardingStage>? = null) {
|
||||
Column(Modifier.fillMaxSize().background(MaterialTheme.colors.surface).padding(horizontal = if (appPlatform.isDesktop) DEFAULT_PADDING * 2 else DEFAULT_PADDING)) {
|
||||
Column(Modifier.fillMaxSize().padding(horizontal = if (appPlatform.isDesktop) DEFAULT_PADDING * 2 else DEFAULT_PADDING)) {
|
||||
Spacer(Modifier.statusBarsPadding().padding(top = AppBarHeight * fontSizeSqrtMultiplier))
|
||||
val paraPadding = PaddingValues(bottom = if (appPlatform.isDesktop) 10.dp else 12.dp)
|
||||
Column(Modifier.weight(1f).padding(bottom = DEFAULT_PADDING).verticalScroll(rememberScrollState())) {
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ private fun LinkAMobileLayout(
|
||||
Modifier.weight(0.3f),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
SectionView(generalGetString(MR.strings.this_device_name)) {
|
||||
SectionView(generalGetString(MR.strings.this_device_name), card = true) {
|
||||
DeviceNameField(deviceName.value ?: "") { updateDeviceName(it) }
|
||||
SectionTextFooter(generalGetString(MR.strings.this_device_name_shared_with_mobile))
|
||||
PreferenceToggle(stringResource(MR.strings.multicast_discoverable_via_local_network), checked = remember { ChatModel.controller.appPrefs.offerRemoteMulticast.state }.value) {
|
||||
|
||||
+1
-2
@@ -106,8 +106,7 @@ fun SimpleXInfoLayout(
|
||||
onboardingStage: SharedPreference<OnboardingStage>?
|
||||
) {
|
||||
val topBar = onboardingStage == null && !appPrefs.oneHandUI.state.value
|
||||
val baseModifier = Modifier.fillMaxSize().systemBarsPadding().padding(horizontal = DEFAULT_ONBOARDING_HORIZONTAL_PADDING)
|
||||
val modifier = if (onboardingStage == null) baseModifier.background(MaterialTheme.colors.surface) else baseModifier
|
||||
val modifier = Modifier.fillMaxSize().systemBarsPadding().padding(horizontal = DEFAULT_ONBOARDING_HORIZONTAL_PADDING)
|
||||
Column(if (topBar) modifier.padding(top = AppBarHeight * fontSizeSqrtMultiplier) else modifier, horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Box(Modifier.padding(top = DEFAULT_PADDING * 2).widthIn(max = if (appPlatform.isAndroid) 185.dp else 160.dp), contentAlignment = Alignment.Center) {
|
||||
SimpleXLogo()
|
||||
|
||||
+1
-1
@@ -138,7 +138,7 @@ fun ModalData.WhatsNewView(updatedConditions: Boolean = false, viaSettings: Bool
|
||||
|
||||
val v = versionDescriptions[currentVersion.value]
|
||||
|
||||
ModalView(close = close, background = MaterialTheme.colors.surface) {
|
||||
ModalView(close = close) {
|
||||
ColumnWithScrollBar(
|
||||
Modifier
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
|
||||
+18
-18
@@ -128,7 +128,7 @@ private fun ConnectDesktopLayout(deviceName: String, close: () -> Unit) {
|
||||
@Composable
|
||||
private fun ConnectDesktop(deviceName: String, remoteCtrls: SnapshotStateList<RemoteCtrlInfo>, sessionAddress: MutableState<String>) {
|
||||
AppBarTitle(stringResource(MR.strings.connect_to_desktop))
|
||||
SectionView(stringResource(MR.strings.this_device_name)) {
|
||||
SectionView(stringResource(MR.strings.this_device_name), card = true) {
|
||||
DevicesView(deviceName, remoteCtrls) {
|
||||
if (it != "") {
|
||||
setDeviceName(it)
|
||||
@@ -147,7 +147,7 @@ private fun ConnectDesktop(deviceName: String, remoteCtrls: SnapshotStateList<Re
|
||||
@Composable
|
||||
private fun ConnectingDesktop(session: RemoteCtrlSession, rc: RemoteCtrlInfo?) {
|
||||
AppBarTitle(stringResource(MR.strings.connecting_to_desktop))
|
||||
SectionView(stringResource(MR.strings.connecting_to_desktop), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
SectionView(stringResource(MR.strings.connecting_to_desktop), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING), card = true) {
|
||||
CtrlDeviceNameText(session, rc)
|
||||
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
|
||||
CtrlDeviceVersionText(session)
|
||||
@@ -155,14 +155,14 @@ private fun ConnectingDesktop(session: RemoteCtrlSession, rc: RemoteCtrlInfo?) {
|
||||
|
||||
if (session.sessionCode != null) {
|
||||
SectionSpacer()
|
||||
SectionView(stringResource(MR.strings.session_code)) {
|
||||
SectionView(stringResource(MR.strings.session_code), card = true) {
|
||||
SessionCodeText(session.sessionCode!!)
|
||||
}
|
||||
}
|
||||
|
||||
SectionSpacer()
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
DisconnectButton(onClick = ::disconnectDesktop)
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ private fun ProgressIndicator() {
|
||||
@Composable
|
||||
private fun SearchingDesktop(deviceName: String, remoteCtrls: SnapshotStateList<RemoteCtrlInfo>) {
|
||||
AppBarTitle(stringResource(MR.strings.connecting_to_desktop))
|
||||
SectionView(stringResource(MR.strings.this_device_name)) {
|
||||
SectionView(stringResource(MR.strings.this_device_name), card = true) {
|
||||
DevicesView(deviceName, remoteCtrls) {
|
||||
if (it != "") {
|
||||
setDeviceName(it)
|
||||
@@ -197,7 +197,7 @@ private fun SearchingDesktop(deviceName: String, remoteCtrls: SnapshotStateList<
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.found_desktop), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
SectionView(stringResource(MR.strings.found_desktop), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING), card = true) {
|
||||
Text(stringResource(MR.strings.waiting_for_desktop), fontStyle = FontStyle.Italic)
|
||||
}
|
||||
SectionSpacer()
|
||||
@@ -215,7 +215,7 @@ private fun FoundDesktop(
|
||||
sessionAddress: MutableState<String>,
|
||||
) {
|
||||
AppBarTitle(stringResource(MR.strings.found_desktop))
|
||||
SectionView(stringResource(MR.strings.this_device_name)) {
|
||||
SectionView(stringResource(MR.strings.this_device_name), card = true) {
|
||||
DevicesView(deviceName, remoteCtrls) {
|
||||
if (it != "") {
|
||||
setDeviceName(it)
|
||||
@@ -224,7 +224,7 @@ private fun FoundDesktop(
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.found_desktop), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
SectionView(stringResource(MR.strings.found_desktop), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING), card = true) {
|
||||
CtrlDeviceNameText(session, rc)
|
||||
CtrlDeviceVersionText(session)
|
||||
if (!compatible) {
|
||||
@@ -256,7 +256,7 @@ private fun FoundDesktop(
|
||||
@Composable
|
||||
private fun VerifySession(session: RemoteCtrlSession, rc: RemoteCtrlInfo?, sessCode: String, remoteCtrls: SnapshotStateList<RemoteCtrlInfo>) {
|
||||
AppBarTitle(stringResource(MR.strings.verify_connection))
|
||||
SectionView(stringResource(MR.strings.connected_to_desktop), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
SectionView(stringResource(MR.strings.connected_to_desktop), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING), card = true) {
|
||||
CtrlDeviceNameText(session, rc)
|
||||
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
|
||||
CtrlDeviceVersionText(session)
|
||||
@@ -264,7 +264,7 @@ private fun VerifySession(session: RemoteCtrlSession, rc: RemoteCtrlInfo?, sessC
|
||||
|
||||
SectionSpacer()
|
||||
|
||||
SectionView(stringResource(MR.strings.verify_code_with_desktop)) {
|
||||
SectionView(stringResource(MR.strings.verify_code_with_desktop), card = true) {
|
||||
SessionCodeText(sessCode)
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ private fun VerifySession(session: RemoteCtrlSession, rc: RemoteCtrlInfo?, sessC
|
||||
Text(generalGetString(MR.strings.confirm_verb))
|
||||
}
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
DisconnectButton(onClick = ::disconnectDesktop)
|
||||
}
|
||||
}
|
||||
@@ -311,7 +311,7 @@ private fun CtrlDeviceVersionText(session: RemoteCtrlSession) {
|
||||
@Composable
|
||||
private fun ActiveSession(session: RemoteCtrlSession, rc: RemoteCtrlInfo, close: () -> Unit) {
|
||||
AppBarTitle(stringResource(MR.strings.connected_to_desktop))
|
||||
SectionView(stringResource(MR.strings.connected_desktop), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
SectionView(stringResource(MR.strings.connected_desktop), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING), card = true) {
|
||||
Text(rc.deviceViewName)
|
||||
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
|
||||
CtrlDeviceVersionText(session)
|
||||
@@ -319,14 +319,14 @@ private fun ActiveSession(session: RemoteCtrlSession, rc: RemoteCtrlInfo, close:
|
||||
|
||||
if (session.sessionCode != null) {
|
||||
SectionSpacer()
|
||||
SectionView(stringResource(MR.strings.session_code)) {
|
||||
SectionView(stringResource(MR.strings.session_code), card = true) {
|
||||
SessionCodeText(session.sessionCode!!)
|
||||
}
|
||||
}
|
||||
|
||||
SectionSpacer()
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
DisconnectButton { disconnectDesktop(close) }
|
||||
}
|
||||
}
|
||||
@@ -355,7 +355,7 @@ private fun DevicesView(deviceName: String, remoteCtrls: SnapshotStateList<Remot
|
||||
|
||||
@Composable
|
||||
private fun ScanDesktopAddressView(sessionAddress: MutableState<String>) {
|
||||
SectionView(stringResource(MR.strings.scan_qr_code_from_desktop)) {
|
||||
SectionView(stringResource(MR.strings.scan_qr_code_from_desktop), card = true) {
|
||||
QRCodeScanner { text ->
|
||||
sessionAddress.value = text
|
||||
connectDesktopAddress(sessionAddress, text)
|
||||
@@ -366,7 +366,7 @@ private fun ScanDesktopAddressView(sessionAddress: MutableState<String>) {
|
||||
@Composable
|
||||
private fun DesktopAddressView(sessionAddress: MutableState<String>) {
|
||||
val clipboard = LocalClipboardManager.current
|
||||
SectionView(stringResource(MR.strings.desktop_address)) {
|
||||
SectionView(stringResource(MR.strings.desktop_address), card = true) {
|
||||
if (sessionAddress.value.isEmpty()) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_content_paste),
|
||||
@@ -410,7 +410,7 @@ private fun DesktopAddressView(sessionAddress: MutableState<String>) {
|
||||
private fun LinkedDesktopsView(remoteCtrls: SnapshotStateList<RemoteCtrlInfo>) {
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(MR.strings.linked_desktops))
|
||||
SectionView(stringResource(MR.strings.desktop_devices)) {
|
||||
SectionView(stringResource(MR.strings.desktop_devices), card = true) {
|
||||
remoteCtrls.forEach { rc ->
|
||||
val showMenu = rememberSaveable { mutableStateOf(false) }
|
||||
SectionItemViewLongClickable(click = {}, longClick = { showMenu.value = true }) {
|
||||
@@ -427,7 +427,7 @@ private fun LinkedDesktopsView(remoteCtrls: SnapshotStateList<RemoteCtrlInfo>) {
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(stringResource(MR.strings.linked_desktop_options)) {
|
||||
SectionView(stringResource(MR.strings.linked_desktop_options), card = true) {
|
||||
PreferenceToggle(stringResource(MR.strings.verify_connections), checked = remember { controller.appPrefs.confirmRemoteSessions.state }.value) {
|
||||
controller.appPrefs.confirmRemoteSessions.set(it)
|
||||
}
|
||||
|
||||
+9
-8
@@ -92,15 +92,15 @@ fun ConnectMobileLayout(
|
||||
) {
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(if (remember { chatModel.remoteHosts }.isEmpty()) MR.strings.link_a_mobile else MR.strings.linked_mobiles))
|
||||
SectionView(generalGetString(MR.strings.this_device_name)) {
|
||||
SectionView(generalGetString(MR.strings.this_device_name), card = true) {
|
||||
DeviceNameField(deviceName.value ?: "") { updateDeviceName(it) }
|
||||
SectionTextFooter(generalGetString(MR.strings.this_device_name_shared_with_mobile))
|
||||
PreferenceToggle(stringResource(MR.strings.multicast_discoverable_via_local_network), checked = remember { controller.appPrefs.offerRemoteMulticast.state }.value) {
|
||||
controller.appPrefs.offerRemoteMulticast.set(it)
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
SectionTextFooter(generalGetString(MR.strings.this_device_name_shared_with_mobile))
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.devices)) {
|
||||
SectionView(stringResource(MR.strings.devices), card = true) {
|
||||
if (chatModel.localUserCreated.value == true) {
|
||||
SettingsActionItemWithContent(text = stringResource(MR.strings.this_device), icon = painterResource(MR.images.ic_desktop), click = connectDesktop) {
|
||||
if (connectedHost.value == null) {
|
||||
@@ -189,7 +189,7 @@ private fun ConnectMobileViewLayout(
|
||||
if (title != null) {
|
||||
AppBarTitle(title)
|
||||
}
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
if (invitation != null && sessionCode == null && port != null) {
|
||||
Box {
|
||||
QRCode(invitation)
|
||||
@@ -211,10 +211,11 @@ private fun ConnectMobileViewLayout(
|
||||
Text(generalGetString(MR.strings.share_link), color = MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
}
|
||||
if (deviceName != null || sessionCode != null) {
|
||||
SectionView(stringResource(MR.strings.connected_mobile)) {
|
||||
SectionView(stringResource(MR.strings.connected_mobile), card = true) {
|
||||
SelectionContainer {
|
||||
Text(
|
||||
deviceName ?: stringResource(MR.strings.new_mobile_device),
|
||||
@@ -227,7 +228,7 @@ private fun ConnectMobileViewLayout(
|
||||
}
|
||||
|
||||
if (sessionCode != null) {
|
||||
SectionView(stringResource(MR.strings.verify_code_on_mobile)) {
|
||||
SectionView(stringResource(MR.strings.verify_code_on_mobile), card = true) {
|
||||
SelectionContainer {
|
||||
Text(
|
||||
sessionCode.substring(0, 23),
|
||||
|
||||
+58
-63
@@ -1,9 +1,6 @@
|
||||
package chat.simplex.common.views.usersettings
|
||||
|
||||
import CARD_ITEM_PADDING
|
||||
import CARD_PADDING
|
||||
import SectionBottomSpacer
|
||||
import SectionDivider
|
||||
import SectionDividerSpaced
|
||||
import SectionItemView
|
||||
import SectionItemViewSpaceBetween
|
||||
@@ -61,9 +58,9 @@ expect fun AppearanceView(m: ChatModel)
|
||||
object AppearanceScope {
|
||||
@Composable
|
||||
fun ProfileImageSection() {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_profile_images), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_profile_images), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING), card = true) {
|
||||
val image = remember { chatModel.currentUser }.value?.image
|
||||
Row(Modifier.padding(vertical = 10.dp), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) {
|
||||
Row(Modifier.padding(top = 10.dp), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) {
|
||||
val size = 60
|
||||
Box(Modifier.offset(x = -(size / 12).dp)) {
|
||||
if (!image.isNullOrEmpty()) {
|
||||
@@ -94,7 +91,7 @@ object AppearanceScope {
|
||||
@Composable
|
||||
fun AppToolbarsSection() {
|
||||
BoxWithConstraints {
|
||||
SectionView(stringResource(MR.strings.appearance_app_toolbars)) {
|
||||
SectionView(stringResource(MR.strings.appearance_app_toolbars), card = true) {
|
||||
SectionItemViewWithoutMinPadding {
|
||||
Box(Modifier.weight(1f)) {
|
||||
Text(
|
||||
@@ -115,7 +112,7 @@ object AppearanceScope {
|
||||
val diff = it % 0.025f
|
||||
appPrefs.inAppBarsAlpha.set(1f - (String.format(Locale.US, "%.3f", it + (if (diff >= 0.0125f) -diff + 0.025f else -diff)).toFloatOrNull() ?: 1f))
|
||||
},
|
||||
Modifier.widthIn(max = (this@BoxWithConstraints.maxWidth - (CARD_PADDING + CARD_ITEM_PADDING) * 2) * 0.618f),
|
||||
Modifier.widthIn(max = (this@BoxWithConstraints.maxWidth - DEFAULT_PADDING * 2) * 0.618f),
|
||||
valueRange = 0f..0.5f,
|
||||
steps = 21,
|
||||
colors = SliderDefaults.colors(
|
||||
@@ -161,7 +158,7 @@ object AppearanceScope {
|
||||
val diff = it % 0.05f
|
||||
saveBlur(((String.format(Locale.US, "%.2f", it + (if (diff >= 0.025f) -diff + 0.05f else -diff)).toFloatOrNull() ?: 1f) * 100).toInt())
|
||||
},
|
||||
Modifier.widthIn(max = (this@BoxWithConstraints.maxWidth - (CARD_PADDING + CARD_ITEM_PADDING) * 2) * 0.618f),
|
||||
Modifier.widthIn(max = (this@BoxWithConstraints.maxWidth - DEFAULT_PADDING * 2) * 0.618f),
|
||||
valueRange = 0f..1f,
|
||||
steps = 21,
|
||||
colors = SliderDefaults.colors(
|
||||
@@ -178,7 +175,7 @@ object AppearanceScope {
|
||||
@Composable
|
||||
fun MessageShapeSection() {
|
||||
BoxWithConstraints {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_message_shape)) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_message_shape), card = true) {
|
||||
SectionItemViewWithoutMinPadding {
|
||||
Text(stringResource(MR.strings.settings_message_shape_corner), Modifier.weight(1f))
|
||||
Spacer(Modifier.width(10.dp))
|
||||
@@ -189,7 +186,7 @@ object AppearanceScope {
|
||||
appPreferences.chatItemRoundness.set(it + (if (diff >= 0.025f) -diff + 0.05f else -diff))
|
||||
saveThemeToDatabase(null)
|
||||
},
|
||||
Modifier.widthIn(max = (this@BoxWithConstraints.maxWidth - (CARD_PADDING + CARD_ITEM_PADDING) * 2) * 0.618f),
|
||||
Modifier.widthIn(max = (this@BoxWithConstraints.maxWidth - DEFAULT_PADDING * 2) * 0.618f),
|
||||
valueRange = 0f..1f,
|
||||
steps = 20,
|
||||
colors = SliderDefaults.colors(
|
||||
@@ -208,8 +205,8 @@ object AppearanceScope {
|
||||
@Composable
|
||||
fun FontScaleSection() {
|
||||
val localFontScale = remember { mutableStateOf(appPrefs.fontScale.get()) }
|
||||
SectionView(stringResource(MR.strings.appearance_font_size), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Row(Modifier.padding(vertical = 10.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
SectionView(stringResource(MR.strings.appearance_font_size), contentPadding = PaddingValues(horizontal = DEFAULT_PADDING), card = true) {
|
||||
Row(Modifier.padding(top = 10.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Box(Modifier.size(50.dp)
|
||||
.background(MaterialTheme.colors.surface, RoundedCornerShape(percent = 22))
|
||||
.clip(RoundedCornerShape(percent = 22))
|
||||
@@ -523,9 +520,10 @@ object AppearanceScope {
|
||||
}
|
||||
}
|
||||
|
||||
SectionView(stringResource(MR.strings.settings_section_title_themes)) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_themes), card = true) {
|
||||
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
|
||||
ThemeDestinationPicker(themeUserDestination)
|
||||
Spacer(Modifier.height(DEFAULT_PADDING_HALF))
|
||||
|
||||
val importWallpaperLauncher = rememberFileChooserLauncher(true) { to: URI? ->
|
||||
if (to != null) onImport(to)
|
||||
@@ -539,7 +537,6 @@ object AppearanceScope {
|
||||
},
|
||||
onChooseType = { onChooseType(it, importWallpaperLauncher) },
|
||||
)
|
||||
SectionDivider()
|
||||
val type = MaterialTheme.wallpaper.type
|
||||
if (type is WallpaperType.Image && (themeUserDestination.value == null || perUserTheme.value.wallpaper?.imageFile != null)) {
|
||||
SectionItemView(disabled = chatModel.remoteHostId != null && themeUserDestination.value != null, click = {
|
||||
@@ -558,6 +555,7 @@ object AppearanceScope {
|
||||
color = if (chatModel.remoteHostId != null && themeUserDestination.value != null) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
||||
)
|
||||
}
|
||||
SectionSpacer()
|
||||
}
|
||||
|
||||
val state: State<DefaultThemeMode?> = remember(appPrefs.currentTheme.get()) {
|
||||
@@ -586,23 +584,23 @@ object AppearanceScope {
|
||||
}
|
||||
saveThemeToDatabase(null)
|
||||
}
|
||||
SectionItemView(click = {
|
||||
val user = themeUserDestination.value
|
||||
if (user == null) {
|
||||
ModalManager.start.showModal {
|
||||
val importWallpaperLauncher = rememberFileChooserLauncher(true) { to: URI? ->
|
||||
if (to != null) onImport(to)
|
||||
}
|
||||
CustomizeThemeView { onChooseType(it, importWallpaperLauncher) }
|
||||
}
|
||||
} else {
|
||||
ModalManager.start.showModalCloseable { close ->
|
||||
UserWallpaperEditorModal(chatModel.remoteHostId(), user.first, close)
|
||||
}
|
||||
SectionItemView(click = {
|
||||
val user = themeUserDestination.value
|
||||
if (user == null) {
|
||||
ModalManager.start.showModal {
|
||||
val importWallpaperLauncher = rememberFileChooserLauncher(true) { to: URI? ->
|
||||
if (to != null) onImport(to)
|
||||
}
|
||||
CustomizeThemeView { onChooseType(it, importWallpaperLauncher) }
|
||||
}
|
||||
} else {
|
||||
ModalManager.start.showModalCloseable { close ->
|
||||
UserWallpaperEditorModal(chatModel.remoteHostId(), user.first, close)
|
||||
}
|
||||
}) {
|
||||
Text(stringResource(MR.strings.customize_theme_title))
|
||||
}
|
||||
}) {
|
||||
Text(stringResource(MR.strings.customize_theme_title))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,35 +626,33 @@ object AppearanceScope {
|
||||
)
|
||||
}
|
||||
|
||||
SectionView {
|
||||
WallpaperPresetSelector(
|
||||
selectedWallpaper = wallpaperType,
|
||||
baseTheme = currentTheme.base,
|
||||
currentColors = { type ->
|
||||
ThemeManager.currentColors(type, null, null, appPrefs.themeOverrides.get())
|
||||
},
|
||||
onChooseType = onChooseType
|
||||
)
|
||||
WallpaperPresetSelector(
|
||||
selectedWallpaper = wallpaperType,
|
||||
baseTheme = currentTheme.base,
|
||||
currentColors = { type ->
|
||||
ThemeManager.currentColors(type, null, null, appPrefs.themeOverrides.get())
|
||||
},
|
||||
onChooseType = onChooseType
|
||||
)
|
||||
|
||||
val type = MaterialTheme.wallpaper.type
|
||||
if (type is WallpaperType.Image) {
|
||||
SectionItemView(disabled = chatModel.remoteHostId != null, click = {
|
||||
val defaultActiveTheme = ThemeManager.defaultActiveTheme(appPrefs.themeOverrides.get())
|
||||
ThemeManager.saveAndApplyWallpaper(baseTheme, null)
|
||||
ThemeManager.removeTheme(defaultActiveTheme?.themeId)
|
||||
removeWallpaperFile(type.filename)
|
||||
saveThemeToDatabase(null)
|
||||
}) {
|
||||
Text(
|
||||
stringResource(MR.strings.theme_remove_image),
|
||||
color = if (chatModel.remoteHostId == null) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
|
||||
)
|
||||
}
|
||||
val type = MaterialTheme.wallpaper.type
|
||||
if (type is WallpaperType.Image) {
|
||||
SectionItemView(disabled = chatModel.remoteHostId != null, click = {
|
||||
val defaultActiveTheme = ThemeManager.defaultActiveTheme(appPrefs.themeOverrides.get())
|
||||
ThemeManager.saveAndApplyWallpaper(baseTheme, null)
|
||||
ThemeManager.removeTheme(defaultActiveTheme?.themeId)
|
||||
removeWallpaperFile(type.filename)
|
||||
saveThemeToDatabase(null)
|
||||
}) {
|
||||
Text(
|
||||
stringResource(MR.strings.theme_remove_image),
|
||||
color = if (chatModel.remoteHostId == null) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
|
||||
)
|
||||
}
|
||||
SectionSpacer()
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(stringResource(MR.strings.settings_section_title_chat_colors)) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_chat_colors), card = true) {
|
||||
WallpaperSetupView(
|
||||
wallpaperType,
|
||||
baseTheme,
|
||||
@@ -685,18 +681,16 @@ object AppearanceScope {
|
||||
val currentOverrides = remember(currentTheme) { ThemeManager.defaultActiveTheme(appPrefs.themeOverrides.get()) }
|
||||
val canResetColors = currentTheme.base.hasChangedAnyColor(currentOverrides)
|
||||
if (canResetColors) {
|
||||
SectionView {
|
||||
SectionItemView({
|
||||
ThemeManager.resetAllThemeColors()
|
||||
saveThemeToDatabase(null)
|
||||
}) {
|
||||
Text(generalGetString(MR.strings.reset_color), color = colors.primary)
|
||||
}
|
||||
SectionItemView({
|
||||
ThemeManager.resetAllThemeColors()
|
||||
saveThemeToDatabase(null)
|
||||
}) {
|
||||
Text(generalGetString(MR.strings.reset_color), color = colors.primary)
|
||||
}
|
||||
SectionSpacer()
|
||||
}
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
val theme = remember { mutableStateOf(null as String?) }
|
||||
val exportThemeLauncher = rememberFileChooserLauncher(false) { to: URI? ->
|
||||
val themeValue = theme.value
|
||||
@@ -759,7 +753,7 @@ object AppearanceScope {
|
||||
onLongClick = onLongClick
|
||||
)
|
||||
.onRightClick(onLongClick)
|
||||
.size(28.dp),
|
||||
.size(44.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Icon(painterResource(if (themeMode == DefaultThemeMode.LIGHT) MR.images.ic_light_mode else MR.images.ic_bedtime_moon), stringResource(MR.strings.color_mode_light), tint = MaterialTheme.colors.secondary)
|
||||
@@ -949,7 +943,7 @@ object AppearanceScope {
|
||||
|
||||
@Composable
|
||||
fun CustomizeThemeColorsSection(currentTheme: ThemeManager.ActiveTheme, editColor: (ThemeColor) -> Unit) {
|
||||
SectionView(stringResource(MR.strings.theme_colors_section_title)) {
|
||||
SectionView(stringResource(MR.strings.theme_colors_section_title), card = true) {
|
||||
SectionItemViewSpaceBetween({ editColor(ThemeColor.PRIMARY) }) {
|
||||
val title = generalGetString(MR.strings.color_primary)
|
||||
Text(title)
|
||||
@@ -1241,6 +1235,7 @@ fun WallpaperSetupView(
|
||||
Text(title)
|
||||
Icon(painterResource(MR.images.ic_circle_filled), title, tint = wallpaperTintColor)
|
||||
}
|
||||
SectionSpacer()
|
||||
}
|
||||
|
||||
SectionItemViewSpaceBetween({ editColor(ThemeColor.SENT_MESSAGE) }) {
|
||||
|
||||
+10
-10
@@ -24,19 +24,19 @@ fun DeveloperView(withAuth: (title: String, desc: String, block: () -> Unit) ->
|
||||
val developerTools = m.controller.appPrefs.developerTools
|
||||
val devTools = remember { developerTools.state }
|
||||
val unchangedHints = mutableStateOf(unchangedHintPreferences())
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
InstallTerminalAppItem(uriHandler)
|
||||
ChatConsoleItem { withAuth(generalGetString(MR.strings.auth_open_chat_console), generalGetString(MR.strings.auth_log_in_using_credential)) { ModalManager.start.showModalCloseable { TerminalView(false) } } }
|
||||
ResetHintsItem(unchangedHints)
|
||||
SettingsPreferenceItem(painterResource(MR.images.ic_code), stringResource(MR.strings.show_developer_options), developerTools)
|
||||
SectionTextFooter(
|
||||
generalGetString(if (devTools.value) MR.strings.show_dev_options else MR.strings.hide_dev_options) + " " +
|
||||
generalGetString(MR.strings.developer_options)
|
||||
)
|
||||
}
|
||||
SectionTextFooter(
|
||||
generalGetString(if (devTools.value) MR.strings.show_dev_options else MR.strings.hide_dev_options) + " " +
|
||||
generalGetString(MR.strings.developer_options)
|
||||
)
|
||||
if (devTools.value) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.developer_options_section)) {
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
SectionView(stringResource(MR.strings.developer_options_section), card = true) {
|
||||
SettingsActionItemWithContent(painterResource(MR.images.ic_breaking_news), stringResource(MR.strings.debug_logs)) {
|
||||
DefaultSwitch(
|
||||
checked = remember { appPrefs.logLevel.state }.value <= LogLevel.DEBUG,
|
||||
@@ -59,15 +59,15 @@ fun DeveloperView(withAuth: (title: String, desc: String, block: () -> Unit) ->
|
||||
SettingsPreferenceItem(painterResource(MR.images.ic_avg_pace), stringResource(MR.strings.show_slow_api_calls), appPreferences.showSlowApiCalls)
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.deprecated_options_section)) {
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
SectionView(stringResource(MR.strings.deprecated_options_section), card = true) {
|
||||
val simplexLinkMode = chatModel.controller.appPrefs.simplexLinkMode
|
||||
SimpleXLinkOptions(chatModel.simplexLinkMode, onSelected = {
|
||||
simplexLinkMode.set(it)
|
||||
chatModel.simplexLinkMode.value = it
|
||||
})
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+24
-27
@@ -6,7 +6,6 @@ import SectionItemViewWithoutMinPadding
|
||||
import SectionSpacer
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
@@ -57,32 +56,30 @@ private fun HiddenProfileLayout(
|
||||
user: User,
|
||||
saveProfilePassword: (String) -> Unit
|
||||
) {
|
||||
Box(Modifier.fillMaxSize().background(MaterialTheme.colors.surface)) {
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(MR.strings.hide_profile))
|
||||
SectionView(contentPadding = PaddingValues(start = 8.dp, end = DEFAULT_PADDING)) {
|
||||
UserProfileRow(user)
|
||||
}
|
||||
SectionSpacer()
|
||||
|
||||
val hidePassword = rememberSaveable { mutableStateOf("") }
|
||||
val confirmHidePassword = rememberSaveable { mutableStateOf("") }
|
||||
val passwordValid by remember { derivedStateOf { hidePassword.value == hidePassword.value.trim() } }
|
||||
val confirmValid by remember { derivedStateOf { confirmHidePassword.value == "" || hidePassword.value == confirmHidePassword.value } }
|
||||
val saveDisabled by remember { derivedStateOf { hidePassword.value == "" || !passwordValid || confirmHidePassword.value == "" || !confirmValid } }
|
||||
SectionView(stringResource(MR.strings.hidden_profile_password)) {
|
||||
SectionItemViewWithoutMinPadding {
|
||||
PassphraseField(hidePassword, generalGetString(MR.strings.password_to_show), isValid = { passwordValid }, showStrength = true)
|
||||
}
|
||||
SectionItemViewWithoutMinPadding {
|
||||
PassphraseField(confirmHidePassword, stringResource(MR.strings.confirm_password), isValid = { confirmValid }, dependsOn = hidePassword)
|
||||
}
|
||||
SectionItemViewSpaceBetween({ saveProfilePassword(hidePassword.value) }, disabled = saveDisabled, minHeight = TextFieldDefaults.MinHeight) {
|
||||
Text(generalGetString(MR.strings.save_profile_password), color = if (saveDisabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.to_reveal_profile_enter_password))
|
||||
SectionBottomSpacer()
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(MR.strings.hide_profile))
|
||||
SectionView(contentPadding = PaddingValues(start = 8.dp, end = DEFAULT_PADDING)) {
|
||||
UserProfileRow(user)
|
||||
}
|
||||
SectionSpacer()
|
||||
|
||||
val hidePassword = rememberSaveable { mutableStateOf("") }
|
||||
val confirmHidePassword = rememberSaveable { mutableStateOf("") }
|
||||
val passwordValid by remember { derivedStateOf { hidePassword.value == hidePassword.value.trim() } }
|
||||
val confirmValid by remember { derivedStateOf { confirmHidePassword.value == "" || hidePassword.value == confirmHidePassword.value } }
|
||||
val saveDisabled by remember { derivedStateOf { hidePassword.value == "" || !passwordValid || confirmHidePassword.value == "" || !confirmValid } }
|
||||
SectionView(stringResource(MR.strings.hidden_profile_password).uppercase()) {
|
||||
SectionItemViewWithoutMinPadding {
|
||||
PassphraseField(hidePassword, generalGetString(MR.strings.password_to_show), isValid = { passwordValid }, showStrength = true)
|
||||
}
|
||||
SectionItemViewWithoutMinPadding {
|
||||
PassphraseField(confirmHidePassword, stringResource(MR.strings.confirm_password), isValid = { confirmValid }, dependsOn = hidePassword)
|
||||
}
|
||||
SectionItemViewSpaceBetween({ saveProfilePassword(hidePassword.value) }, disabled = saveDisabled, minHeight = TextFieldDefaults.MinHeight) {
|
||||
Text(generalGetString(MR.strings.save_profile_password), color = if (saveDisabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.to_reveal_profile_enter_password))
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -55,7 +55,7 @@ fun NotificationsSettingsLayout(
|
||||
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(MR.strings.notifications))
|
||||
SectionView(null) {
|
||||
SectionView(null, card = true) {
|
||||
if (appPlatform == AppPlatform.ANDROID) {
|
||||
SettingsActionItemWithContent(null, stringResource(MR.strings.settings_notifications_mode_title), { showPage(CurrentPage.NOTIFICATIONS_MODE) }) {
|
||||
Text(
|
||||
@@ -74,9 +74,9 @@ fun NotificationsSettingsLayout(
|
||||
color = MaterialTheme.colors.secondary
|
||||
)
|
||||
}
|
||||
}
|
||||
if (platform.androidIsXiaomiDevice() && (notificationsMode.value == NotificationsMode.PERIODIC || notificationsMode.value == NotificationsMode.SERVICE)) {
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.xiaomi_ignore_battery_optimization))
|
||||
if (platform.androidIsXiaomiDevice() && (notificationsMode.value == NotificationsMode.PERIODIC || notificationsMode.value == NotificationsMode.SERVICE)) {
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.xiaomi_ignore_battery_optimization))
|
||||
}
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
|
||||
+8
-8
@@ -81,27 +81,27 @@ private fun PreferencesLayout(
|
||||
onTTLUpdated = onTTLUpdated
|
||||
)
|
||||
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
val allowFullDeletion = remember(preferences) { mutableStateOf(preferences.fullDelete.allow) }
|
||||
FeatureSection(ChatFeature.FullDelete, allowFullDeletion) {
|
||||
applyPrefs(preferences.copy(fullDelete = SimpleChatPreference(allow = it)))
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
val allowReactions = remember(preferences) { mutableStateOf(preferences.reactions.allow) }
|
||||
FeatureSection(ChatFeature.Reactions, allowReactions) {
|
||||
applyPrefs(preferences.copy(reactions = SimpleChatPreference(allow = it)))
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
val allowVoice = remember(preferences) { mutableStateOf(preferences.voice.allow) }
|
||||
FeatureSection(ChatFeature.Voice, allowVoice) {
|
||||
applyPrefs(preferences.copy(voice = SimpleChatPreference(allow = it)))
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(true, maxBottomPadding = false)
|
||||
val allowCalls = remember(preferences) { mutableStateOf(preferences.calls.allow) }
|
||||
FeatureSection(ChatFeature.Calls, allowCalls) {
|
||||
applyPrefs(preferences.copy(calls = SimpleChatPreference(allow = it)))
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
|
||||
ResetSaveButtons(
|
||||
reset = reset,
|
||||
save = savePrefs,
|
||||
@@ -113,7 +113,7 @@ private fun PreferencesLayout(
|
||||
|
||||
@Composable
|
||||
private fun FeatureSection(feature: ChatFeature, allowFeature: State<FeatureAllowed>, onSelected: (FeatureAllowed) -> Unit) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
ExposedDropDownSettingRow(
|
||||
feature.text,
|
||||
FeatureAllowed.values().map { it to it.text },
|
||||
@@ -133,7 +133,7 @@ private fun TimedMessagesFeatureSection(
|
||||
onTTLUpdated: (Int?) -> Unit
|
||||
) {
|
||||
val ttl = rememberSaveable(preferences) { mutableStateOf(preferences.timedMessages.ttl) }
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
PreferenceToggleWithIcon(
|
||||
ChatFeature.TimedMessages.text,
|
||||
ChatFeature.TimedMessages.icon,
|
||||
@@ -163,7 +163,7 @@ private fun TimedMessagesFeatureSection(
|
||||
|
||||
@Composable
|
||||
private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Boolean) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
SectionItemView(reset, disabled = disabled) {
|
||||
Text(stringResource(MR.strings.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
}
|
||||
|
||||
+8
-8
@@ -60,7 +60,7 @@ fun PrivacySettingsView(
|
||||
PrivacyDeviceSection(showSettingsModal, setPerformLA)
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(stringResource(MR.strings.settings_section_title_chats)) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_chats), card = true) {
|
||||
SettingsPreferenceItem(
|
||||
painterResource(MR.images.ic_travel_explore),
|
||||
stringResource(MR.strings.send_link_previews),
|
||||
@@ -93,7 +93,7 @@ fun PrivacySettingsView(
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(stringResource(MR.strings.settings_section_title_files)) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_files), card = true) {
|
||||
SettingsPreferenceItem(painterResource(MR.images.ic_lock), stringResource(MR.strings.encrypt_local_files), chatModel.controller.appPrefs.privacyEncryptLocalFiles, onChange = { enable ->
|
||||
withBGApi { chatModel.controller.apiSetEncryptLocalFiles(enable) }
|
||||
})
|
||||
@@ -171,7 +171,7 @@ fun PrivacySettingsView(
|
||||
}
|
||||
|
||||
if (!chatModel.desktopNoUserNoRemote) {
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
ContacRequestsFromGroupsSection(
|
||||
currentUser = currentUser,
|
||||
setAutoAcceptGrpDirectInvs = { enable ->
|
||||
@@ -179,7 +179,7 @@ fun PrivacySettingsView(
|
||||
}
|
||||
)
|
||||
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
DeliveryReceiptsSection(
|
||||
currentUser = currentUser,
|
||||
setOrAskSendReceiptsContacts = { enable ->
|
||||
@@ -277,7 +277,7 @@ private fun ContacRequestsFromGroupsSection(
|
||||
currentUser: User,
|
||||
setAutoAcceptGrpDirectInvs: (Boolean) -> Unit
|
||||
) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_contact_requests_from_groups)) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_contact_requests_from_groups), card = true) {
|
||||
SettingsActionItemWithContent(painterResource(MR.images.ic_check), stringResource(MR.strings.auto_accept_contact)) {
|
||||
DefaultSwitch(
|
||||
checked = currentUser.autoAcceptMemberContacts,
|
||||
@@ -306,7 +306,7 @@ private fun DeliveryReceiptsSection(
|
||||
setOrAskSendReceiptsContacts: (Boolean) -> Unit,
|
||||
setOrAskSendReceiptsGroups: (Boolean) -> Unit,
|
||||
) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_delivery_receipts)) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_delivery_receipts), card = true) {
|
||||
SettingsActionItemWithContent(painterResource(MR.images.ic_person), stringResource(MR.strings.receipts_section_contacts)) {
|
||||
DefaultSwitch(
|
||||
checked = currentUser.sendRcptsContacts,
|
||||
@@ -562,7 +562,7 @@ fun SimplexLockView(
|
||||
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(MR.strings.chat_lock))
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
EnableLock(remember { appPrefs.performLA.state }) { performLAToggle ->
|
||||
showAuthScreen.value = performLAToggle
|
||||
chatModel.controller.appPrefs.laNoticeShown.set(true)
|
||||
@@ -619,7 +619,7 @@ fun SimplexLockView(
|
||||
}
|
||||
if (performLA.value && laMode.value == LAMode.PASSCODE) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.self_destruct_passcode)) {
|
||||
SectionView(stringResource(MR.strings.self_destruct_passcode), card = true) {
|
||||
val openInfo = {
|
||||
ModalManager.start.showModal {
|
||||
SelfDestructInfoView()
|
||||
|
||||
+8
-10
@@ -2,7 +2,6 @@ package chat.simplex.common.views.usersettings
|
||||
|
||||
import SectionBottomSpacer
|
||||
import SectionItemViewSpaceBetween
|
||||
import SectionView
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
@@ -102,21 +101,20 @@ fun RTCServersLayout(
|
||||
) {
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(MR.strings.your_ICE_servers))
|
||||
SectionView {
|
||||
SectionItemViewSpaceBetween {
|
||||
Text(stringResource(MR.strings.configure_ICE_servers), Modifier.padding(end = 24.dp))
|
||||
DefaultSwitch(
|
||||
checked = isUserRTCServers,
|
||||
onCheckedChange = isUserRTCServersOnOff,
|
||||
)
|
||||
}
|
||||
}
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
SectionItemViewSpaceBetween(padding = PaddingValues()) {
|
||||
Text(stringResource(MR.strings.configure_ICE_servers), Modifier.padding(end = 24.dp))
|
||||
DefaultSwitch(
|
||||
checked = isUserRTCServers,
|
||||
onCheckedChange = isUserRTCServersOnOff,
|
||||
)
|
||||
}
|
||||
|
||||
if (!isUserRTCServers) {
|
||||
Text(stringResource(MR.strings.using_simplex_chat_servers), lineHeight = 22.sp)
|
||||
} else {
|
||||
|
||||
+6
-7
@@ -1,6 +1,5 @@
|
||||
package chat.simplex.common.views.usersettings
|
||||
|
||||
import CARD_ITEM_PADDING
|
||||
import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionItemView
|
||||
@@ -101,7 +100,7 @@ fun SettingsLayout(
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(MR.strings.your_settings))
|
||||
|
||||
SectionView(stringResource(MR.strings.settings_section_title_settings)) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_settings), card = true) {
|
||||
SettingsActionItem(painterResource(if (notificationsMode.value == NotificationsMode.OFF) MR.images.ic_bolt_off else MR.images.ic_bolt), stringResource(MR.strings.notifications), showSettingsModal { NotificationsSettingsView(it) }, disabled = stopped)
|
||||
SettingsActionItem(painterResource(MR.images.ic_wifi_tethering), stringResource(MR.strings.network_and_servers), showCustomModal { _, close -> NetworkAndServersView(close) }, disabled = stopped)
|
||||
SettingsActionItem(painterResource(MR.images.ic_videocam), stringResource(MR.strings.settings_audio_video_calls), showSettingsModal { CallSettingsView(it, showModal) }, disabled = stopped)
|
||||
@@ -110,14 +109,14 @@ fun SettingsLayout(
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(stringResource(MR.strings.settings_section_title_chat_database)) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_chat_database), card = true) {
|
||||
DatabaseItem(encrypted, passphraseSaved, showSettingsModal { DatabaseView() }, stopped)
|
||||
SettingsActionItem(painterResource(MR.images.ic_ios_share), stringResource(MR.strings.migrate_from_device_to_another_device), { withAuth(generalGetString(MR.strings.auth_open_migration_to_another_device), generalGetString(MR.strings.auth_log_in_using_credential)) { ModalManager.fullscreen.showCustomModal { close -> MigrateFromDeviceView(close) } } }, disabled = stopped)
|
||||
}
|
||||
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(stringResource(MR.strings.settings_section_title_help)) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_help), card = true) {
|
||||
SettingsActionItem(painterResource(MR.images.ic_help), stringResource(MR.strings.how_to_use_simplex_chat), showModal { HelpView(userDisplayName ?: "") }, disabled = stopped)
|
||||
SettingsActionItem(painterResource(MR.images.ic_add), stringResource(MR.strings.whats_new), showCustomModal { _, close -> WhatsNewView(viaSettings = true, close = close) }, disabled = stopped)
|
||||
SettingsActionItem(painterResource(MR.images.ic_info), stringResource(MR.strings.about_simplex_chat), showModal { SimpleXInfo(it, onboarding = false) })
|
||||
@@ -128,7 +127,7 @@ fun SettingsLayout(
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(stringResource(MR.strings.settings_section_title_support)) {
|
||||
SectionView(stringResource(MR.strings.settings_section_title_support), card = true) {
|
||||
if (!BuildConfigCommon.ANDROID_BUNDLE) {
|
||||
ContributeItem(uriHandler)
|
||||
}
|
||||
@@ -349,9 +348,9 @@ fun SettingsActionItemWithContent(icon: Painter?, text: String? = null, click: (
|
||||
click,
|
||||
extraPadding = extraPadding,
|
||||
padding = if (extraPadding && icon != null)
|
||||
PaddingValues(start = DEFAULT_PADDING * 1.7f, end = CARD_ITEM_PADDING)
|
||||
PaddingValues(start = DEFAULT_PADDING * 1.7f, end = DEFAULT_PADDING)
|
||||
else
|
||||
PaddingValues(horizontal = CARD_ITEM_PADDING),
|
||||
PaddingValues(horizontal = DEFAULT_PADDING),
|
||||
disabled = disabled
|
||||
) {
|
||||
if (icon != null) {
|
||||
|
||||
+15
-20
@@ -301,17 +301,17 @@ private fun UserAddressLayout(
|
||||
) {
|
||||
if (userAddress == null) {
|
||||
if (!onboarding) {
|
||||
SectionView(generalGetString(MR.strings.for_social_media)) {
|
||||
SectionView(generalGetString(MR.strings.for_social_media), card = true) {
|
||||
CreateAddressButton(createAddress)
|
||||
}
|
||||
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.or_to_share_privately)) {
|
||||
SectionView(generalGetString(MR.strings.or_to_share_privately), card = true) {
|
||||
CreateOneTimeLinkButton()
|
||||
}
|
||||
|
||||
SectionDividerSpaced()
|
||||
SectionView {
|
||||
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
|
||||
SectionView(card = true) {
|
||||
LearnMoreButton(learnMore)
|
||||
}
|
||||
}
|
||||
@@ -336,7 +336,7 @@ private fun UserAddressLayout(
|
||||
val savedAddressSettingsState = remember { mutableStateOf(addressSettingsState.value) }
|
||||
|
||||
SectionViewWithButton(
|
||||
stringResource(MR.strings.for_social_media),
|
||||
stringResource(MR.strings.for_social_media).uppercase(),
|
||||
titleButton = if (userAddress.connLinkContact.connShortLink != null) {{ ToggleShortLinkButton(showShortLink) }} else null
|
||||
) {
|
||||
SimpleXCreatedLinkQRCode(userAddress.connLinkContact, short = showShortLink.value)
|
||||
@@ -359,20 +359,20 @@ private fun UserAddressLayout(
|
||||
}
|
||||
}
|
||||
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.or_to_share_privately)) {
|
||||
SectionDividerSpaced(maxTopPadding = addressSettingsState.value.businessAddress)
|
||||
SectionView(generalGetString(MR.strings.or_to_share_privately), card = true) {
|
||||
CreateOneTimeLinkButton()
|
||||
}
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
LearnMoreButton(learnMore)
|
||||
}
|
||||
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
DeleteAddressButton(deleteAddress)
|
||||
SectionTextFooter(stringResource(MR.strings.your_contacts_will_remain_connected))
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.your_contacts_will_remain_connected))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -503,7 +503,7 @@ private fun ModalData.UserAddressSettings(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
ShareWithContactsButton(shareViaProfile, setProfileAddress)
|
||||
AutoAcceptToggle(addressSettingsState) { saveAddressSettings(addressSettingsState.value, savedAddressSettingsState) }
|
||||
if (addressSettingsState.value.autoAccept && !chatModel.addressShortLinkDataSet() && !addressSettingsState.value.businessAddress) {
|
||||
@@ -512,18 +512,13 @@ private fun ModalData.UserAddressSettings(
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(
|
||||
stringResource(MR.strings.address_welcome_message),
|
||||
contentPadding = PaddingValues(vertical = DEFAULT_PADDING_HALF),
|
||||
) {
|
||||
SectionView(stringResource(MR.strings.address_welcome_message), card = true) {
|
||||
AutoReplyEditor(addressSettingsState)
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
|
||||
|
||||
SectionView {
|
||||
saveAddressSettingsButton(addressSettingsState.value == savedAddressSettingsState.value) {
|
||||
saveAddressSettings(addressSettingsState.value, savedAddressSettingsState)
|
||||
}
|
||||
saveAddressSettingsButton(addressSettingsState.value == savedAddressSettingsState.value) {
|
||||
saveAddressSettings(addressSettingsState.value, savedAddressSettingsState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ fun UserProfileLayout(
|
||||
showUnsavedChangesAlert({ saveProfile(displayName.value, fullName.value, shortDescr.value, profileImage.value) }, close)
|
||||
}
|
||||
}
|
||||
ModalView(close = closeWithAlert, background = MaterialTheme.colors.surface) {
|
||||
ModalView(close = closeWithAlert) {
|
||||
ColumnWithScrollBar(
|
||||
Modifier
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
|
||||
+22
-22
@@ -1,14 +1,12 @@
|
||||
package chat.simplex.common.views.usersettings
|
||||
|
||||
import SectionBottomSpacer
|
||||
import SectionDivider
|
||||
import SectionItemView
|
||||
import SectionItemViewSpaceBetween
|
||||
import SectionItemViewWithoutMinPadding
|
||||
import SectionSpacer
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
@@ -164,16 +162,18 @@ private fun UserProfilesLayout(
|
||||
unmuteUser: (User) -> Unit,
|
||||
showHiddenProfile: (User) -> Unit,
|
||||
) {
|
||||
Box(Modifier.fillMaxSize().background(MaterialTheme.colors.surface)) {
|
||||
ColumnWithScrollBar {
|
||||
if (profileHidden.value) {
|
||||
ColumnWithScrollBar {
|
||||
if (profileHidden.value) {
|
||||
SectionView {
|
||||
SettingsActionItem(painterResource(MR.images.ic_lock_open_right), stringResource(MR.strings.enter_password_to_show), click = {
|
||||
profileHidden.value = false
|
||||
})
|
||||
SectionSpacer()
|
||||
}
|
||||
AppBarTitle(stringResource(MR.strings.your_chat_profiles), hostDevice(remember { chatModel.remoteHostId() }))
|
||||
SectionSpacer()
|
||||
}
|
||||
AppBarTitle(stringResource(MR.strings.your_chat_profiles), hostDevice(remember { chatModel.remoteHostId() }))
|
||||
|
||||
SectionView {
|
||||
for (user in filteredUsers) {
|
||||
UserView(user, visibleUsersCount, activateUser, removeUser, unhideUser, muteUser, unmuteUser, showHiddenProfile)
|
||||
Divider(Modifier.padding(horizontal = 8.dp))
|
||||
@@ -185,22 +185,22 @@ private fun UserProfilesLayout(
|
||||
Text(stringResource(MR.strings.users_add), color = MaterialTheme.colors.primary)
|
||||
}
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.tap_to_activate_profile))
|
||||
LaunchedEffect(Unit) {
|
||||
if (showHiddenProfilesNotice.state.value && users.size > 1) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.make_profile_private),
|
||||
text = generalGetString(MR.strings.you_can_hide_or_mute_user_profile),
|
||||
confirmText = generalGetString(MR.strings.ok),
|
||||
dismissText = generalGetString(MR.strings.dont_show_again),
|
||||
onDismiss = {
|
||||
showHiddenProfilesNotice.set(false)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.tap_to_activate_profile))
|
||||
LaunchedEffect(Unit) {
|
||||
if (showHiddenProfilesNotice.state.value && users.size > 1) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.make_profile_private),
|
||||
text = generalGetString(MR.strings.you_can_hide_or_mute_user_profile),
|
||||
confirmText = generalGetString(MR.strings.ok),
|
||||
dismissText = generalGetString(MR.strings.dont_show_again),
|
||||
onDismiss = {
|
||||
showHiddenProfilesNotice.set(false)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-4
@@ -1,9 +1,6 @@
|
||||
package chat.simplex.common.views.usersettings
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -19,7 +16,7 @@ import chat.simplex.res.MR
|
||||
@Composable
|
||||
fun VersionInfoView(info: CoreVersionInfo) {
|
||||
ColumnWithScrollBar(
|
||||
Modifier.fillMaxSize().background(MaterialTheme.colors.surface).padding(horizontal = DEFAULT_PADDING),
|
||||
Modifier.padding(horizontal = DEFAULT_PADDING),
|
||||
) {
|
||||
AppBarTitle(stringResource(MR.strings.app_version_title), withPadding = false)
|
||||
if (appPlatform.isAndroid) {
|
||||
|
||||
+7
-7
@@ -228,19 +228,19 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (@Composable ModalData.() -
|
||||
AppBarTitle(stringResource(MR.strings.network_settings_title))
|
||||
|
||||
if (currentRemoteHost == null) {
|
||||
SectionView(generalGetString(MR.strings.settings_section_title_private_message_routing)) {
|
||||
SectionView(generalGetString(MR.strings.settings_section_title_private_message_routing), card = true) {
|
||||
SMPProxyModePicker(smpProxyMode, showModal, updateSMPProxyMode)
|
||||
SMPProxyFallbackPicker(smpProxyFallback, showModal, updateSMPProxyFallback, enabled = remember { derivedStateOf { smpProxyMode.value != SMPProxyMode.Never } })
|
||||
SettingsPreferenceItem(painterResource(MR.images.ic_arrow_forward), stringResource(MR.strings.private_routing_show_message_status), chatModel.controller.appPrefs.showSentViaProxy)
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.private_routing_explanation))
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
|
||||
SectionView(stringResource(MR.strings.network_session_mode_transport_isolation)) {
|
||||
SectionView(stringResource(MR.strings.network_session_mode_transport_isolation), card = true) {
|
||||
SessionModePicker(sessionMode, showModal, updateSessionMode)
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.network_smp_web_port_section_title)) {
|
||||
SectionView(stringResource(MR.strings.network_smp_web_port_section_title), card = true) {
|
||||
ExposedDropDownSettingRow(
|
||||
stringResource(MR.strings.network_smp_web_port_toggle),
|
||||
SMPWebPortServers.entries.map { it to stringResource(it.text) },
|
||||
@@ -251,9 +251,9 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (@Composable ModalData.() -
|
||||
if (smpWebPortServers.value == SMPWebPortServers.Preset) stringResource(MR.strings.network_smp_web_port_preset_footer)
|
||||
else String.format(stringResource(MR.strings.network_smp_web_port_footer), if (smpWebPortServers.value == SMPWebPortServers.All) "443" else "5223")
|
||||
)
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
|
||||
SectionView(stringResource(MR.strings.network_option_tcp_connection)) {
|
||||
SectionView(stringResource(MR.strings.network_option_tcp_connection), card = true) {
|
||||
SectionItemView {
|
||||
TimeoutSettingRow(
|
||||
stringResource(MR.strings.network_option_tcp_connection_timeout), networkTCPConnectTimeoutInteractive,
|
||||
@@ -332,7 +332,7 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (@Composable ModalData.() -
|
||||
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
SectionItemView(reset, disabled = resetDisabled) {
|
||||
Text(stringResource(MR.strings.network_options_reset_to_defaults), color = if (resetDisabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
|
||||
}
|
||||
|
||||
+8
-8
@@ -182,7 +182,7 @@ private fun ChatRelayLayout(
|
||||
|
||||
@Composable
|
||||
private fun PresetRelay(relay: MutableState<UserChatRelay>, testing: MutableState<Boolean>) {
|
||||
SectionView(stringResource(MR.strings.preset_relay_address)) {
|
||||
SectionView(stringResource(MR.strings.preset_relay_address).uppercase()) {
|
||||
SelectionContainer {
|
||||
Text(
|
||||
relay.value.address,
|
||||
@@ -192,7 +192,7 @@ private fun PresetRelay(relay: MutableState<UserChatRelay>, testing: MutableStat
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.preset_relay_name)) {
|
||||
SectionView(stringResource(MR.strings.preset_relay_name).uppercase()) {
|
||||
SectionItemView {
|
||||
Text(relay.value.displayName)
|
||||
}
|
||||
@@ -229,7 +229,7 @@ private fun CustomRelay(
|
||||
}
|
||||
|
||||
SectionView(
|
||||
stringResource(MR.strings.your_relay_address),
|
||||
stringResource(MR.strings.your_relay_address).uppercase(),
|
||||
icon = painterResource(MR.images.ic_error),
|
||||
iconTint = if (!validAddress.value) MaterialTheme.colors.error else Color.Transparent,
|
||||
) {
|
||||
@@ -238,13 +238,13 @@ private fun CustomRelay(
|
||||
Modifier.height(144.dp)
|
||||
)
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
|
||||
Column {
|
||||
val iconSize = with(LocalDensity.current) { 21.sp.toDp() }
|
||||
Row(Modifier.padding(start = DEFAULT_PADDING, bottom = 5.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
stringResource(MR.strings.your_relay_name),
|
||||
stringResource(MR.strings.your_relay_name).uppercase(),
|
||||
color = MaterialTheme.colors.secondary, style = MaterialTheme.typography.body2, fontSize = 12.sp
|
||||
)
|
||||
IconButton(
|
||||
@@ -270,7 +270,7 @@ private fun CustomRelay(
|
||||
if (relay.value.tested != true) {
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.test_relay_to_retrieve_name))
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
|
||||
UseRelaySection(relay, validAddress.value, testing)
|
||||
|
||||
@@ -291,7 +291,7 @@ private fun UseRelaySection(
|
||||
testing: MutableState<Boolean>
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
SectionView(stringResource(MR.strings.use_relay)) {
|
||||
SectionView(stringResource(MR.strings.use_relay).uppercase()) {
|
||||
SectionItemViewSpaceBetween(
|
||||
click = {
|
||||
testing.value = true
|
||||
@@ -377,7 +377,7 @@ fun ModalData.NewChatRelayView(
|
||||
|
||||
ModalView(close = {
|
||||
addChatRelay(relayToEdit.value, userServers, serverErrors, serverWarnings, rhId, close)
|
||||
}, background = MaterialTheme.colors.surface) {
|
||||
}) {
|
||||
NewChatRelayLayout(relayToEdit)
|
||||
}
|
||||
}
|
||||
|
||||
+71
-67
@@ -22,7 +22,6 @@ import androidx.compose.ui.text.*
|
||||
import androidx.compose.ui.text.input.*
|
||||
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.shape.CircleShape
|
||||
import androidx.compose.ui.draw.clip
|
||||
@@ -211,13 +210,13 @@ fun ModalData.NetworkAndServersView(closeNetworkAndServers: () -> Unit) {
|
||||
AppBarTitle(stringResource(MR.strings.network_and_servers))
|
||||
// TODO: Review this and socks.
|
||||
if (!chatModel.desktopNoUserNoRemote) {
|
||||
SectionView(generalGetString(MR.strings.network_preset_servers_title)) {
|
||||
SectionView(generalGetString(MR.strings.network_preset_servers_title), card = true) {
|
||||
userServers.value.forEachIndexed { index, srv ->
|
||||
srv.operator?.let { ServerOperatorRow(index, it, currUserServers, userServers, serverErrors, serverWarnings, currentRemoteHost?.remoteHostId) }
|
||||
}
|
||||
if (conditionsAction != null && anyOperatorEnabled.value) {
|
||||
ConditionsButton(conditionsAction, rhId = currentRemoteHost?.remoteHostId)
|
||||
}
|
||||
}
|
||||
if (conditionsAction != null && anyOperatorEnabled.value) {
|
||||
ConditionsButton(conditionsAction, rhId = currentRemoteHost?.remoteHostId)
|
||||
}
|
||||
val footerText = if (conditionsAction is UsageConditionsAction.Review && conditionsAction.deadline != null && anyOperatorEnabled.value) {
|
||||
String.format(generalGetString(MR.strings.operator_conditions_will_be_accepted_on), localDate(conditionsAction.deadline))
|
||||
@@ -229,7 +228,7 @@ fun ModalData.NetworkAndServersView(closeNetworkAndServers: () -> Unit) {
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
|
||||
SectionView(generalGetString(MR.strings.settings_section_title_messages)) {
|
||||
SectionView(generalGetString(MR.strings.settings_section_title_messages), card = true) {
|
||||
val nullOperatorIndex = userServers.value.indexOfFirst { it.operator == null }
|
||||
|
||||
if (nullOperatorIndex != -1) {
|
||||
@@ -263,25 +262,21 @@ fun ModalData.NetworkAndServersView(closeNetworkAndServers: () -> Unit) {
|
||||
UseSocksProxySwitch(networkUseSocksProxy, toggleSocksProxy)
|
||||
SettingsActionItem(painterResource(MR.images.ic_settings_ethernet), stringResource(MR.strings.network_socks_proxy_settings), { showCustomModal { SocksProxySettings(networkUseSocksProxy.value, appPrefs.networkProxy, onionHosts, sessionMode = appPrefs.networkSessionMode.get(), false, it) } })
|
||||
SettingsActionItem(painterResource(MR.images.ic_cable), stringResource(MR.strings.network_settings), { ModalManager.start.showCustomModal { AdvancedNetworkSettingsView(showModal, it) } })
|
||||
}
|
||||
}
|
||||
if (currentRemoteHost == null) {
|
||||
if (networkUseSocksProxy.value) {
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.socks_proxy_setting_limitations))
|
||||
SectionDividerSpaced()
|
||||
} else {
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
if (networkUseSocksProxy.value) {
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.socks_proxy_setting_limitations))
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
} else {
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
val saveDisabled = !serversCanBeSaved(currUserServers.value, userServers.value, serverErrors.value)
|
||||
|
||||
SectionView {
|
||||
SectionItemView(
|
||||
{ scope.launch { saveServers(rhId = currentRemoteHost?.remoteHostId, currUserServers, userServers) } },
|
||||
disabled = saveDisabled,
|
||||
) {
|
||||
Text(stringResource(MR.strings.smp_servers_save), color = if (!saveDisabled) MaterialTheme.colors.onBackground else MaterialTheme.colors.secondary)
|
||||
}
|
||||
SectionItemView(
|
||||
{ scope.launch { saveServers(rhId = currentRemoteHost?.remoteHostId, currUserServers, userServers) } },
|
||||
disabled = saveDisabled,
|
||||
) {
|
||||
Text(stringResource(MR.strings.smp_servers_save), color = if (!saveDisabled) MaterialTheme.colors.onBackground else MaterialTheme.colors.secondary)
|
||||
}
|
||||
val serversErr = globalServersError(serverErrors.value)
|
||||
if (serversErr != null) {
|
||||
@@ -302,13 +297,13 @@ fun ModalData.NetworkAndServersView(closeNetworkAndServers: () -> Unit) {
|
||||
|
||||
SectionDividerSpaced()
|
||||
|
||||
SectionView(generalGetString(MR.strings.settings_section_title_calls)) {
|
||||
SectionView(generalGetString(MR.strings.settings_section_title_calls), card = true) {
|
||||
SettingsActionItem(painterResource(MR.images.ic_electrical_services), stringResource(MR.strings.webrtc_ice_servers), { ModalManager.start.showModal { RTCServersView(m) } })
|
||||
}
|
||||
|
||||
if (appPlatform.isAndroid) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.settings_section_title_network_connection)) {
|
||||
SectionView(generalGetString(MR.strings.settings_section_title_network_connection), card = true) {
|
||||
val info = remember { chatModel.networkInfo }.value
|
||||
SettingsActionItemWithContent(icon = null, info.networkType.text) {
|
||||
Icon(painterResource(MR.images.ic_circle_filled), stringResource(MR.strings.icon_descr_server_status_connected), tint = if (info.online) Color.Green else MaterialTheme.colors.error)
|
||||
@@ -340,10 +335,23 @@ fun UseSocksProxySwitch(
|
||||
networkUseSocksProxy: MutableState<Boolean>,
|
||||
toggleSocksProxy: (Boolean) -> Unit,
|
||||
) {
|
||||
SettingsActionItemWithContent(
|
||||
icon = painterResource(MR.images.ic_settings_ethernet),
|
||||
text = stringResource(MR.strings.network_socks_toggle_use_socks_proxy),
|
||||
Row(
|
||||
Modifier.fillMaxWidth().padding(end = DEFAULT_PADDING),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Row(
|
||||
Modifier.weight(1f).padding(horizontal = DEFAULT_PADDING),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
painterResource(MR.images.ic_settings_ethernet),
|
||||
stringResource(MR.strings.network_socks_toggle_use_socks_proxy),
|
||||
tint = MaterialTheme.colors.secondary
|
||||
)
|
||||
TextIconSpaced(false)
|
||||
Text(generalGetString(MR.strings.network_socks_toggle_use_socks_proxy))
|
||||
}
|
||||
DefaultSwitch(
|
||||
checked = networkUseSocksProxy.value,
|
||||
onCheckedChange = toggleSocksProxy,
|
||||
@@ -461,7 +469,7 @@ fun SocksProxySettings(
|
||||
) {
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(generalGetString(MR.strings.network_socks_proxy_settings))
|
||||
SectionView(stringResource(MR.strings.network_socks_proxy)) {
|
||||
SectionView(stringResource(MR.strings.network_socks_proxy), card = true) {
|
||||
Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
|
||||
DefaultConfigurableTextField(
|
||||
hostUnsaved,
|
||||
@@ -484,13 +492,12 @@ fun SocksProxySettings(
|
||||
UseOnionHosts(onionHosts, rememberUpdatedState(networkUseSocksProxy && proxyAuthRandomUnsaved.value)) {
|
||||
onionHosts.value = it
|
||||
}
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.disable_onion_hosts_when_not_supported))
|
||||
}
|
||||
UseOnionHostsDescription(onionHosts)
|
||||
SectionTextFooter(annotatedStringResource(MR.strings.disable_onion_hosts_when_not_supported))
|
||||
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
|
||||
SectionView(stringResource(MR.strings.network_proxy_auth)) {
|
||||
SectionView(stringResource(MR.strings.network_proxy_auth), card = true) {
|
||||
PreferenceToggle(
|
||||
stringResource(MR.strings.network_proxy_random_credentials),
|
||||
checked = proxyAuthRandomUnsaved.value,
|
||||
@@ -516,12 +523,12 @@ fun SocksProxySettings(
|
||||
)
|
||||
}
|
||||
}
|
||||
SectionTextFooter(proxyAuthFooter(usernameUnsaved.value.text, passwordUnsaved.value.text, proxyAuthModeUnsaved.value, sessionMode))
|
||||
}
|
||||
SectionTextFooter(proxyAuthFooter(usernameUnsaved.value.text, passwordUnsaved.value.text, proxyAuthModeUnsaved.value, sessionMode))
|
||||
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxBottomPadding = false, maxTopPadding = true)
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
SectionItemView({
|
||||
hostUnsaved.value = hostUnsaved.value.copy("localhost", TextRange(9))
|
||||
portUnsaved.value = portUnsaved.value.copy("9050", TextRange(4))
|
||||
@@ -560,8 +567,13 @@ private fun showUnsavedSocksHostPortAlert(confirmText: String, save: () -> Unit,
|
||||
)
|
||||
}
|
||||
|
||||
private val onionHostsValues: List<ValueTitleDesc<OnionHosts>>
|
||||
@Composable get() = remember {
|
||||
@Composable
|
||||
fun UseOnionHosts(
|
||||
onionHosts: MutableState<OnionHosts>,
|
||||
enabled: State<Boolean>,
|
||||
useOnion: (OnionHosts) -> Unit,
|
||||
) {
|
||||
val values = remember {
|
||||
OnionHosts.values().map {
|
||||
when (it) {
|
||||
OnionHosts.NEVER -> ValueTitleDesc(OnionHosts.NEVER, generalGetString(MR.strings.network_use_onion_hosts_no), AnnotatedString(generalGetString(MR.strings.network_use_onion_hosts_no_desc)))
|
||||
@@ -571,39 +583,31 @@ private val onionHostsValues: List<ValueTitleDesc<OnionHosts>>
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UseOnionHosts(
|
||||
onionHosts: MutableState<OnionHosts>,
|
||||
enabled: State<Boolean>,
|
||||
useOnion: (OnionHosts) -> Unit,
|
||||
) {
|
||||
if (enabled.value) {
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.network_use_onion_hosts),
|
||||
onionHostsValues.map { it.value to it.title },
|
||||
onionHosts,
|
||||
icon = painterResource(MR.images.ic_security),
|
||||
enabled = enabled,
|
||||
onSelected = useOnion
|
||||
)
|
||||
} else {
|
||||
// In reality, when socks proxy is disabled, this option acts like NEVER regardless of what was chosen before
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.network_use_onion_hosts),
|
||||
listOf(OnionHosts.NEVER to generalGetString(MR.strings.network_use_onion_hosts_no)),
|
||||
remember { mutableStateOf(OnionHosts.NEVER) },
|
||||
icon = painterResource(MR.images.ic_security),
|
||||
enabled = enabled,
|
||||
onSelected = {}
|
||||
)
|
||||
Column {
|
||||
if (enabled.value) {
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.network_use_onion_hosts),
|
||||
values.map { it.value to it.title },
|
||||
onionHosts,
|
||||
icon = painterResource(MR.images.ic_security),
|
||||
enabled = enabled,
|
||||
onSelected = useOnion
|
||||
)
|
||||
} else {
|
||||
// In reality, when socks proxy is disabled, this option acts like NEVER regardless of what was chosen before
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.network_use_onion_hosts),
|
||||
listOf(OnionHosts.NEVER to generalGetString(MR.strings.network_use_onion_hosts_no)),
|
||||
remember { mutableStateOf(OnionHosts.NEVER) },
|
||||
icon = painterResource(MR.images.ic_security),
|
||||
enabled = enabled,
|
||||
onSelected = {}
|
||||
)
|
||||
}
|
||||
SectionTextFooter(values.firstOrNull { it.value == onionHosts.value }?.description ?: AnnotatedString(""))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UseOnionHostsDescription(onionHosts: MutableState<OnionHosts>) {
|
||||
SectionTextFooter(onionHostsValues.firstOrNull { it.value == onionHosts.value }?.description ?: AnnotatedString(""))
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SessionModePicker(
|
||||
sessionMode: MutableState<TransportSessionMode>,
|
||||
@@ -778,7 +782,7 @@ fun UsageConditionsView(
|
||||
}
|
||||
}
|
||||
|
||||
ColumnWithScrollBar(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.surface).padding(horizontal = DEFAULT_PADDING)) {
|
||||
ColumnWithScrollBar(modifier = Modifier.fillMaxSize().padding(horizontal = DEFAULT_PADDING)) {
|
||||
when (val conditionsAction = chatModel.conditions.value.conditionsAction) {
|
||||
is UsageConditionsAction.Review -> {
|
||||
AppBarTitle(stringResource(MR.strings.operator_updated_conditions), enableAlphaChanges = false, withPadding = false, bottomPadding = DEFAULT_PADDING)
|
||||
|
||||
+1
-2
@@ -2,7 +2,6 @@ package chat.simplex.common.views.usersettings.networkAndServers
|
||||
|
||||
import SectionBottomSpacer
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.runtime.*
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import chat.simplex.common.model.*
|
||||
@@ -34,7 +33,7 @@ fun ModalData.NewServerView(
|
||||
rhId,
|
||||
close = close
|
||||
)
|
||||
}, background = MaterialTheme.colors.surface) {
|
||||
}) {
|
||||
Box {
|
||||
NewServerLayout(
|
||||
newServer,
|
||||
|
||||
+13
-13
@@ -181,7 +181,7 @@ fun OperatorViewLayout(
|
||||
val duplicateHosts = findDuplicateHosts(serverErrors.value)
|
||||
|
||||
Column {
|
||||
SectionView(generalGetString(MR.strings.operator)) {
|
||||
SectionView(generalGetString(MR.strings.operator), card = true) {
|
||||
SectionItemView({ ModalManager.start.showModalCloseable { _ -> OperatorInfoView(operator) } }) {
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
@@ -238,7 +238,7 @@ fun OperatorViewLayout(
|
||||
if (userServers.value[operatorIndex].chatRelays.any { !it.deleted }) {
|
||||
val duplicateRelayAddresses = findDuplicateRelayAddresses(serverErrors.value)
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.chat_relays)) {
|
||||
SectionView(generalGetString(MR.strings.chat_relays), card = true) {
|
||||
userServers.value[operatorIndex].chatRelays.forEachIndexed { index, relay ->
|
||||
if (!relay.deleted) {
|
||||
ChatRelayViewLink(relay, duplicateRelayAddresses) {
|
||||
@@ -252,7 +252,7 @@ fun OperatorViewLayout(
|
||||
|
||||
if (userServers.value[operatorIndex].smpServers.any { !it.deleted }) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.operator_use_for_messages)) {
|
||||
SectionView(generalGetString(MR.strings.operator_use_for_messages), card = true) {
|
||||
SectionItemView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Text(
|
||||
stringResource(MR.strings.operator_use_for_messages_receiving),
|
||||
@@ -306,7 +306,7 @@ fun OperatorViewLayout(
|
||||
// Preset servers can't be deleted
|
||||
if (userServers.value[operatorIndex].smpServers.any { it.preset }) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.message_servers)) {
|
||||
SectionView(generalGetString(MR.strings.message_servers), card = true) {
|
||||
userServers.value[operatorIndex].smpServers.forEachIndexed { i, server ->
|
||||
if (!server.preset) return@forEachIndexed
|
||||
SectionItemView({ navigateToProtocolView(i, server, ServerProtocol.SMP) }) {
|
||||
@@ -340,7 +340,7 @@ fun OperatorViewLayout(
|
||||
|
||||
if (userServers.value[operatorIndex].smpServers.any { !it.preset && !it.deleted }) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.operator_added_message_servers)) {
|
||||
SectionView(generalGetString(MR.strings.operator_added_message_servers), card = true) {
|
||||
userServers.value[operatorIndex].smpServers.forEachIndexed { i, server ->
|
||||
if (server.deleted || server.preset) return@forEachIndexed
|
||||
SectionItemView({ navigateToProtocolView(i, server, ServerProtocol.SMP) }) {
|
||||
@@ -356,7 +356,7 @@ fun OperatorViewLayout(
|
||||
|
||||
if (userServers.value[operatorIndex].xftpServers.any { !it.deleted }) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.operator_use_for_files)) {
|
||||
SectionView(generalGetString(MR.strings.operator_use_for_files), card = true) {
|
||||
SectionItemView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Text(
|
||||
stringResource(MR.strings.operator_use_for_sending),
|
||||
@@ -389,7 +389,7 @@ fun OperatorViewLayout(
|
||||
// Preset servers can't be deleted
|
||||
if (userServers.value[operatorIndex].xftpServers.any { it.preset }) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.media_and_file_servers)) {
|
||||
SectionView(generalGetString(MR.strings.media_and_file_servers), card = true) {
|
||||
userServers.value[operatorIndex].xftpServers.forEachIndexed { i, server ->
|
||||
if (!server.preset) return@forEachIndexed
|
||||
SectionItemView({ navigateToProtocolView(i, server, ServerProtocol.XFTP) }) {
|
||||
@@ -423,7 +423,7 @@ fun OperatorViewLayout(
|
||||
|
||||
if (userServers.value[operatorIndex].xftpServers.any { !it.preset && !it.deleted}) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.operator_added_xftp_servers)) {
|
||||
SectionView(generalGetString(MR.strings.operator_added_xftp_servers), card = true) {
|
||||
userServers.value[operatorIndex].xftpServers.forEachIndexed { i, server ->
|
||||
if (server.deleted || server.preset) return@forEachIndexed
|
||||
SectionItemView({ navigateToProtocolView(i, server, ServerProtocol.XFTP) }) {
|
||||
@@ -438,7 +438,7 @@ fun OperatorViewLayout(
|
||||
}
|
||||
|
||||
SectionDividerSpaced()
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
TestServersButton(
|
||||
testing = testing,
|
||||
smpServers = userServers.value[operatorIndex].smpServers,
|
||||
@@ -479,7 +479,7 @@ fun OperatorInfoView(serverOperator: ServerOperator) {
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(MR.strings.operator_info_title))
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
SectionItemView {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
Image(painterResource(serverOperator.largeLogo), null, Modifier.height(48.dp))
|
||||
@@ -493,7 +493,7 @@ fun OperatorInfoView(serverOperator: ServerOperator) {
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
|
||||
val uriHandler = LocalUriHandler.current
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
SectionItemView {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
serverOperator.info.description.forEach { d ->
|
||||
@@ -508,7 +508,7 @@ fun OperatorInfoView(serverOperator: ServerOperator) {
|
||||
val selfhost = serverOperator.info.selfhost
|
||||
if (selfhost != null) {
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
SectionItemView {
|
||||
val (text, link) = selfhost
|
||||
Text(text, color = MaterialTheme.colors.primary, modifier = Modifier.clickable { uriHandler.openExternalLink(link) })
|
||||
@@ -645,7 +645,7 @@ private fun SingleOperatorUsageConditionsView(
|
||||
)
|
||||
}
|
||||
|
||||
ColumnWithScrollBar(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.surface).padding(horizontal = DEFAULT_PADDING)) {
|
||||
ColumnWithScrollBar(modifier = Modifier.fillMaxSize().padding(horizontal = DEFAULT_PADDING)) {
|
||||
AppBarTitle(String.format(stringResource(MR.strings.use_servers_of_operator_x), operator.tradeName), enableAlphaChanges = false, withPadding = false)
|
||||
if (operator.conditionsAcceptance is ConditionsAcceptance.Accepted) {
|
||||
// In current UI implementation this branch doesn't get shown - as conditions can't be opened from inside operator once accepted
|
||||
|
||||
+5
-5
@@ -140,7 +140,7 @@ private fun PresetServer(
|
||||
testing: Boolean,
|
||||
testServer: () -> Unit
|
||||
) {
|
||||
SectionView(stringResource(MR.strings.smp_servers_preset_address)) {
|
||||
SectionView(stringResource(MR.strings.smp_servers_preset_address), card = true) {
|
||||
SelectionContainer {
|
||||
Text(
|
||||
server.value.server,
|
||||
@@ -175,7 +175,7 @@ fun CustomServer(
|
||||
stringResource(MR.strings.smp_servers_your_server_address),
|
||||
icon = painterResource(MR.images.ic_error),
|
||||
iconTint = if (!valid.value) MaterialTheme.colors.error else Color.Transparent,
|
||||
padding = PaddingValues(vertical = DEFAULT_PADDING_HALF),
|
||||
card = true,
|
||||
) {
|
||||
val testedPreviously = remember { mutableMapOf<String, Boolean?>() }
|
||||
TextEditor(
|
||||
@@ -191,13 +191,13 @@ fun CustomServer(
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
|
||||
UseServerSection(server, valid.value, testing, testServer, onDelete)
|
||||
|
||||
if (valid.value) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(stringResource(MR.strings.smp_servers_add_to_another_device)) {
|
||||
SectionView(stringResource(MR.strings.smp_servers_add_to_another_device), card = true) {
|
||||
QRCode(serverAddress.value, small = true)
|
||||
}
|
||||
}
|
||||
@@ -211,7 +211,7 @@ private fun UseServerSection(
|
||||
testServer: () -> Unit,
|
||||
onDelete: (() -> Unit)? = null,
|
||||
) {
|
||||
SectionView(stringResource(MR.strings.smp_servers_use_server)) {
|
||||
SectionView(stringResource(MR.strings.smp_servers_use_server), card = true) {
|
||||
SectionItemViewSpaceBetween(testServer, disabled = !valid || testing) {
|
||||
Text(stringResource(MR.strings.smp_servers_test_server), color = if (valid && !testing) MaterialTheme.colors.onBackground else MaterialTheme.colors.secondary)
|
||||
ShowTestStatus(server.value)
|
||||
|
||||
+7
-7
@@ -86,7 +86,7 @@ fun YourServersViewLayout(
|
||||
Column {
|
||||
if (userServers.value[operatorIndex].chatRelays.any { !it.deleted }) {
|
||||
val duplicateRelayAddresses = findDuplicateRelayAddresses(serverErrors.value)
|
||||
SectionView(generalGetString(MR.strings.chat_relays)) {
|
||||
SectionView(generalGetString(MR.strings.chat_relays), card = true) {
|
||||
userServers.value[operatorIndex].chatRelays.forEachIndexed { i, relay ->
|
||||
if (relay.deleted) return@forEachIndexed
|
||||
ChatRelayViewLink(relay, duplicateRelayAddresses) {
|
||||
@@ -99,7 +99,7 @@ fun YourServersViewLayout(
|
||||
|
||||
if (userServers.value[operatorIndex].smpServers.any { !it.deleted }) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.message_servers)) {
|
||||
SectionView(generalGetString(MR.strings.message_servers), card = true) {
|
||||
userServers.value[operatorIndex].smpServers.forEachIndexed { i, server ->
|
||||
if (server.deleted) return@forEachIndexed
|
||||
SectionItemView({ navigateToProtocolView(i, server, ServerProtocol.SMP) }) {
|
||||
@@ -133,7 +133,7 @@ fun YourServersViewLayout(
|
||||
|
||||
if (userServers.value[operatorIndex].xftpServers.any { !it.deleted }) {
|
||||
SectionDividerSpaced()
|
||||
SectionView(generalGetString(MR.strings.media_and_file_servers)) {
|
||||
SectionView(generalGetString(MR.strings.media_and_file_servers), card = true) {
|
||||
userServers.value[operatorIndex].xftpServers.forEachIndexed { i, server ->
|
||||
if (server.deleted) return@forEachIndexed
|
||||
SectionItemView({ navigateToProtocolView(i, server, ServerProtocol.XFTP) }) {
|
||||
@@ -170,10 +170,10 @@ fun YourServersViewLayout(
|
||||
userServers.value[operatorIndex].xftpServers.any { !it.deleted } ||
|
||||
userServers.value[operatorIndex].chatRelays.any { !it.deleted }
|
||||
) {
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false)
|
||||
}
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_add),
|
||||
stringResource(MR.strings.smp_servers_add),
|
||||
@@ -195,9 +195,9 @@ fun YourServersViewLayout(
|
||||
ServersWarningFooter(serversWarn)
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false)
|
||||
|
||||
SectionView {
|
||||
SectionView(card = true) {
|
||||
TestServersButton(
|
||||
testing = testing,
|
||||
smpServers = userServers.value[operatorIndex].smpServers,
|
||||
|
||||
Reference in New Issue
Block a user