Merge branch 'master' into master-ios

This commit is contained in:
spaced4ndy
2023-06-28 16:13:45 +04:00
40 changed files with 415 additions and 110 deletions

View File

@@ -695,6 +695,13 @@ sealed class ChatInfo: SomeChat, NamedChat {
private val invalidChatName = generalGetString(R.string.invalid_chat)
}
}
val chatSettings
get() = when(this) {
is Direct -> contact.chatSettings
is Group -> groupInfo.chatSettings
else -> null
}
}
@Serializable
@@ -783,7 +790,7 @@ data class Contact(
profile = LocalProfile.sampleData,
activeConn = Connection.sampleData,
contactUsed = true,
chatSettings = ChatSettings(true),
chatSettings = ChatSettings(true, false),
userPreferences = ChatPreferences.sampleData,
mergedPreferences = ContactUserPreferences.sampleData,
createdAt = Clock.System.now(),
@@ -931,7 +938,7 @@ data class GroupInfo (
fullGroupPreferences = FullGroupPreferences.sampleData,
membership = GroupMember.sampleData,
hostConnCustomUserProfileId = null,
chatSettings = ChatSettings(true),
chatSettings = ChatSettings(true, false),
createdAt = Clock.System.now(),
updatedAt = Clock.System.now()
)

View File

@@ -106,6 +106,7 @@ class AppPreferences(val context: Context) {
)
val privacyFullBackup = mkBoolPreference(SHARED_PREFS_PRIVACY_FULL_BACKUP, false)
val experimentalCalls = mkBoolPreference(SHARED_PREFS_EXPERIMENTAL_CALLS, false)
val showUnreadAndFavorites = mkBoolPreference(SHARED_PREFS_SHOW_UNREAD_AND_FAVORITES, false)
val chatArchiveName = mkStrPreference(SHARED_PREFS_CHAT_ARCHIVE_NAME, null)
val chatArchiveTime = mkDatePreference(SHARED_PREFS_CHAT_ARCHIVE_TIME, null)
val chatLastStart = mkDatePreference(SHARED_PREFS_CHAT_LAST_START, null)
@@ -249,6 +250,7 @@ class AppPreferences(val context: Context) {
private const val SHARED_PREFS_PRIVACY_SIMPLEX_LINK_MODE = "PrivacySimplexLinkMode"
internal const val SHARED_PREFS_PRIVACY_FULL_BACKUP = "FullBackup"
private const val SHARED_PREFS_EXPERIMENTAL_CALLS = "ExperimentalCalls"
private const val SHARED_PREFS_SHOW_UNREAD_AND_FAVORITES = "ShowUnreadAndFavorites"
private const val SHARED_PREFS_CHAT_ARCHIVE_NAME = "ChatArchiveName"
private const val SHARED_PREFS_CHAT_ARCHIVE_TIME = "ChatArchiveTime"
private const val SHARED_PREFS_APP_LANGUAGE = "AppLanguage"
@@ -2519,8 +2521,13 @@ data class KeepAliveOpts(
@Serializable
data class ChatSettings(
val enableNtfs: Boolean
)
val enableNtfs: Boolean,
val favorite: Boolean
) {
companion object {
val defaults: ChatSettings = ChatSettings(enableNtfs = true, favorite = false)
}
}
@Serializable
data class FullChatPreferences(
@@ -2930,7 +2937,8 @@ enum class GroupFeature: Feature {
@SerialName("directMessages") DirectMessages,
@SerialName("fullDelete") FullDelete,
@SerialName("reactions") Reactions,
@SerialName("voice") Voice;
@SerialName("voice") Voice,
@SerialName("files") Files;
override val hasParam: Boolean get() = when(this) {
TimedMessages -> true
@@ -2944,6 +2952,7 @@ enum class GroupFeature: Feature {
FullDelete -> generalGetString(R.string.full_deletion)
Reactions -> generalGetString(R.string.message_reactions)
Voice -> generalGetString(R.string.voice_messages)
Files -> generalGetString(R.string.files_and_media)
}
val icon: Painter
@@ -2953,6 +2962,7 @@ enum class GroupFeature: Feature {
FullDelete -> painterResource(R.drawable.ic_delete_forever)
Reactions -> painterResource(R.drawable.ic_add_reaction)
Voice -> painterResource(R.drawable.ic_keyboard_voice)
Files -> painterResource(R.drawable.ic_draft)
}
@Composable
@@ -2962,6 +2972,7 @@ enum class GroupFeature: Feature {
FullDelete -> painterResource(R.drawable.ic_delete_forever_filled)
Reactions -> painterResource(R.drawable.ic_add_reaction_filled)
Voice -> painterResource(R.drawable.ic_keyboard_voice_filled)
Files -> painterResource(R.drawable.ic_draft_filled)
}
fun enableDescription(enabled: GroupFeatureEnabled, canEdit: Boolean): String =
@@ -2987,6 +2998,10 @@ enum class GroupFeature: Feature {
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_send_voice)
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_sending_voice)
}
Files -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_send_files)
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_sending_files)
}
}
} else {
when(this) {
@@ -3010,6 +3025,10 @@ enum class GroupFeature: Feature {
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_voice)
GroupFeatureEnabled.OFF -> generalGetString(R.string.voice_messages_are_prohibited)
}
Files -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_files)
GroupFeatureEnabled.OFF -> generalGetString(R.string.files_are_prohibited_in_group)
}
}
}
}
@@ -3122,7 +3141,8 @@ data class FullGroupPreferences(
val directMessages: GroupPreference,
val fullDelete: GroupPreference,
val reactions: GroupPreference,
val voice: GroupPreference
val voice: GroupPreference,
val files: GroupPreference,
) {
fun toGroupPreferences(): GroupPreferences =
GroupPreferences(
@@ -3130,7 +3150,8 @@ data class FullGroupPreferences(
directMessages = directMessages,
fullDelete = fullDelete,
reactions = reactions,
voice = voice
voice = voice,
files = files,
)
companion object {
@@ -3139,7 +3160,8 @@ data class FullGroupPreferences(
directMessages = GroupPreference(GroupFeatureEnabled.OFF),
fullDelete = GroupPreference(GroupFeatureEnabled.OFF),
reactions = GroupPreference(GroupFeatureEnabled.ON),
voice = GroupPreference(GroupFeatureEnabled.ON)
voice = GroupPreference(GroupFeatureEnabled.ON),
files = GroupPreference(GroupFeatureEnabled.ON),
)
}
}
@@ -3150,7 +3172,8 @@ data class GroupPreferences(
val directMessages: GroupPreference?,
val fullDelete: GroupPreference?,
val reactions: GroupPreference?,
val voice: GroupPreference?
val voice: GroupPreference?,
val files: GroupPreference?,
) {
companion object {
val sampleData = GroupPreferences(
@@ -3158,7 +3181,8 @@ data class GroupPreferences(
directMessages = GroupPreference(GroupFeatureEnabled.OFF),
fullDelete = GroupPreference(GroupFeatureEnabled.OFF),
reactions = GroupPreference(GroupFeatureEnabled.ON),
voice = GroupPreference(GroupFeatureEnabled.ON)
voice = GroupPreference(GroupFeatureEnabled.ON),
files = GroupPreference(GroupFeatureEnabled.ON),
)
}
}

View File

@@ -305,7 +305,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: () -> Unit) {
)
}
},
changeNtfsState = { enabled, currentValue -> changeNtfsStatePerChat(enabled, currentValue, chat, chatModel) },
changeNtfsState = { enabled, currentValue -> toggleNotifications(chat, enabled, chatModel, currentValue) },
onSearchValueChanged = { value ->
if (searchText.value == value) return@ChatLayout
val c = chatModel.getChat(chat.chatInfo.id) ?: return@ChatLayout

View File

@@ -16,6 +16,7 @@ import android.webkit.MimeTypeMap
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContract
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.*
@@ -713,11 +714,22 @@ fun ComposeView(
modifier = Modifier.padding(end = 8.dp),
verticalAlignment = Alignment.Bottom,
) {
IconButton(showChooseAttachment, enabled = !composeState.value.attachmentDisabled && rememberUpdatedState(chat.userCanSend).value) {
val isGroupAndProhibitedFiles = chat.chatInfo is ChatInfo.Group && !chat.chatInfo.groupInfo.fullGroupPreferences.files.on
val attachmentClicked = if (isGroupAndProhibitedFiles) {
{
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.files_and_media_prohibited),
text = generalGetString(R.string.only_owners_can_enable_files_and_media)
)
}
} else {
showChooseAttachment
}
IconButton(attachmentClicked, enabled = !composeState.value.attachmentDisabled && rememberUpdatedState(chat.userCanSend).value) {
Icon(
painterResource(R.drawable.ic_attach_file_filled_500),
contentDescription = stringResource(R.string.attach),
tint = if (!composeState.value.attachmentDisabled && userCanSend.value) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
tint = if (!composeState.value.attachmentDisabled && userCanSend.value && !isGroupAndProhibitedFiles) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
modifier = Modifier
.size(28.dp)
.clip(CircleShape)

View File

@@ -11,12 +11,16 @@ import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -34,15 +38,17 @@ fun AddGroupMembersView(groupInfo: GroupInfo, creatingGroup: Boolean = false, ch
val selectedContacts = remember { mutableStateListOf<Long>() }
val selectedRole = remember { mutableStateOf(GroupMemberRole.Member) }
var allowModifyMembers by remember { mutableStateOf(true) }
val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) }
BackHandler(onBack = close)
AddGroupMembersLayout(
chatModel.incognito.value,
groupInfo = groupInfo,
creatingGroup = creatingGroup,
contactsToAdd = getContactsToAdd(chatModel),
contactsToAdd = getContactsToAdd(chatModel, searchText.value.text),
selectedContacts = selectedContacts,
selectedRole = selectedRole,
allowModifyMembers = allowModifyMembers,
searchText,
openPreferences = {
ModalManager.shared.showCustomModal { close ->
GroupPreferencesView(chatModel, groupInfo.id, close)
@@ -69,7 +75,8 @@ fun AddGroupMembersView(groupInfo: GroupInfo, creatingGroup: Boolean = false, ch
)
}
fun getContactsToAdd(chatModel: ChatModel): List<Contact> {
fun getContactsToAdd(chatModel: ChatModel, search: String): List<Contact> {
val s = search.trim().lowercase()
val memberContactIds = chatModel.groupMembers
.filter { it.memberCurrent }
.mapNotNull { it.memberContactId }
@@ -78,7 +85,7 @@ fun getContactsToAdd(chatModel: ChatModel): List<Contact> {
.map { it.chatInfo }
.filterIsInstance<ChatInfo.Direct>()
.map { it.contact }
.filter { it.contactId !in memberContactIds }
.filter { it.contactId !in memberContactIds && it.chatViewName.lowercase().contains(s) }
.sortedBy { it.displayName.lowercase() }
.toList()
}
@@ -92,6 +99,7 @@ fun AddGroupMembersLayout(
selectedContacts: List<Long>,
selectedRole: MutableState<GroupMemberRole>,
allowModifyMembers: Boolean,
searchText: MutableState<TextFieldValue>,
openPreferences: () -> Unit,
inviteMembers: () -> Unit,
clearSelection: () -> Unit,
@@ -125,7 +133,7 @@ fun AddGroupMembersLayout(
}
SectionSpacer()
if (contactsToAdd.isEmpty()) {
if (contactsToAdd.isEmpty() && searchText.value.text.isEmpty()) {
Row(
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
@@ -154,8 +162,10 @@ fun AddGroupMembersLayout(
InviteSectionFooter(selectedContactsCount = selectedContacts.size, allowModifyMembers, clearSelection)
}
SectionDividerSpaced(maxTopPadding = true)
SectionView(stringResource(R.string.select_contacts)) {
SectionItemView(padding = PaddingValues(start = DEFAULT_PADDING, end = DEFAULT_PADDING_HALF)) {
SearchRowView(searchText, selectedContacts.size)
}
ContactList(contacts = contactsToAdd, selectedContacts, groupInfo, allowModifyMembers, addContact, removeContact)
}
}
@@ -163,6 +173,25 @@ fun AddGroupMembersLayout(
}
}
@Composable
private fun SearchRowView(
searchText: MutableState<TextFieldValue> = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue()) },
selectedContactsSize: Int
) {
Box(Modifier.width(36.dp), contentAlignment = Alignment.Center) {
Icon(painterResource(R.drawable.ic_search), stringResource(android.R.string.search_go), tint = MaterialTheme.colors.secondary)
}
Spacer(Modifier.width(DEFAULT_SPACE_AFTER_ICON))
SearchTextField(Modifier.fillMaxWidth(), searchText = searchText, alwaysVisible = true) {
searchText.value = searchText.value.copy(it)
}
val view = LocalView.current
LaunchedEffect(selectedContactsSize) {
searchText.value = searchText.value.copy("")
hideKeyboard(view)
}
}
@Composable
private fun RoleSelectionRow(groupInfo: GroupInfo, selectedRole: MutableState<GroupMemberRole>, enabled: Boolean) {
Row(
@@ -325,6 +354,7 @@ fun PreviewAddGroupMembersLayout() {
selectedContacts = remember { mutableStateListOf() },
selectedRole = remember { mutableStateOf(GroupMemberRole.Admin) },
allowModifyMembers = true,
searchText = remember { mutableStateOf(TextFieldValue("")) },
openPreferences = {},
inviteMembers = {},
clearSelection = {},

View File

@@ -13,12 +13,14 @@ import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -196,10 +198,17 @@ fun GroupChatInfoLayout(
val tint = if (chat.chatInfo.incognito) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
AddMembersButton(tint, onAddMembersClick)
}
val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue()) }
val filteredMembers = derivedStateOf { members.filter { it.chatViewName.lowercase().contains(searchText.value.text.trim()) } }
if (members.size > 8) {
SectionItemView(padding = PaddingValues(start = 14.dp, end = DEFAULT_PADDING_HALF)) {
SearchRowView(searchText)
}
}
SectionItemView(minHeight = 54.dp) {
MemberRow(groupInfo.membership, user = true)
}
MembersList(members, showMemberInfo)
MembersList(filteredMembers.value, showMemberInfo)
}
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
SectionView {
@@ -393,6 +402,19 @@ private fun DeleteGroupButton(onClick: () -> Unit) {
)
}
@Composable
private fun SearchRowView(
searchText: MutableState<TextFieldValue> = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue()) }
) {
Box(Modifier.width(36.dp), contentAlignment = Alignment.Center) {
Icon(painterResource(R.drawable.ic_search), stringResource(android.R.string.search_go), tint = MaterialTheme.colors.secondary)
}
Spacer(Modifier.width(14.dp))
SearchTextField(Modifier.fillMaxWidth(), searchText = searchText, alwaysVisible = true) {
searchText.value = searchText.value.copy(it)
}
}
@Preview
@Composable
fun PreviewGroupChatInfoLayout() {

View File

@@ -103,6 +103,12 @@ private fun GroupPreferencesLayout(
FeatureSection(GroupFeature.Voice, allowVoice, groupInfo, preferences, onTTLUpdated) {
applyPrefs(preferences.copy(voice = GroupPreference(enable = it)))
}
// TODO uncomment in 5.3
// SectionDividerSpaced(true, maxBottomPadding = false)
// val allowFiles = remember(preferences) { mutableStateOf(preferences.files.enable) }
// FeatureSection(GroupFeature.Files, allowFiles, groupInfo, preferences, onTTLUpdated) {
// applyPrefs(preferences.copy(files = GroupPreference(enable = it)))
// }
if (groupInfo.canEdit) {
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
ResetSaveButtons(

View File

@@ -145,6 +145,7 @@ fun ContactMenuItems(chat: Chat, chatModel: ChatModel, showMenu: MutableState<Bo
} else {
MarkUnreadChatAction(chat, chatModel, showMenu)
}
ToggleFavoritesChatAction(chat, chatModel, chat.chatInfo.chatSettings?.favorite == true, showMenu)
ToggleNotificationsChatAction(chat, chatModel, chat.chatInfo.ntfsEnabled, showMenu)
ClearChatAction(chat, chatModel, showMenu)
DeleteContactAction(chat, chatModel, showMenu)
@@ -173,6 +174,7 @@ fun GroupMenuItems(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, showM
} else {
MarkUnreadChatAction(chat, chatModel, showMenu)
}
ToggleFavoritesChatAction(chat, chatModel, chat.chatInfo.chatSettings?.favorite == true, showMenu)
ToggleNotificationsChatAction(chat, chatModel, chat.chatInfo.ntfsEnabled, showMenu)
ClearChatAction(chat, chatModel, showMenu)
if (groupInfo.membership.memberCurrent) {
@@ -210,13 +212,25 @@ fun MarkUnreadChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableStat
)
}
@Composable
fun ToggleFavoritesChatAction(chat: Chat, chatModel: ChatModel, favorite: Boolean, showMenu: MutableState<Boolean>) {
ItemAction(
if (favorite) stringResource(R.string.unfavorite_chat) else stringResource(R.string.favorite_chat),
if (favorite) painterResource(R.drawable.ic_star_off) else painterResource(R.drawable.ic_star),
onClick = {
toggleChatFavorite(chat, !favorite, chatModel)
showMenu.value = false
}
)
}
@Composable
fun ToggleNotificationsChatAction(chat: Chat, chatModel: ChatModel, ntfsEnabled: Boolean, showMenu: MutableState<Boolean>) {
ItemAction(
if (ntfsEnabled) stringResource(R.string.mute_chat) else stringResource(R.string.unmute_chat),
if (ntfsEnabled) painterResource(R.drawable.ic_notifications_off) else painterResource(R.drawable.ic_notifications),
onClick = {
changeNtfsStatePerChat(!ntfsEnabled, mutableStateOf(ntfsEnabled), chat, chatModel)
toggleNotifications(chat, !ntfsEnabled, chatModel)
showMenu.value = false
}
)
@@ -535,13 +549,23 @@ fun groupInvitationAcceptedAlert() {
)
}
fun changeNtfsStatePerChat(enabled: Boolean, currentState: MutableState<Boolean>, chat: Chat, chatModel: ChatModel) {
fun toggleNotifications(chat: Chat, enableNtfs: Boolean, chatModel: ChatModel, currentState: MutableState<Boolean>? = null) {
val chatSettings = (chat.chatInfo.chatSettings ?: ChatSettings.defaults).copy(enableNtfs = enableNtfs)
updateChatSettings(chat, chatSettings, chatModel, currentState)
}
fun toggleChatFavorite(chat: Chat, favorite: Boolean, chatModel: ChatModel) {
val chatSettings = (chat.chatInfo.chatSettings ?: ChatSettings.defaults).copy(favorite = favorite)
updateChatSettings(chat, chatSettings, chatModel)
}
fun updateChatSettings(chat: Chat, chatSettings: ChatSettings, chatModel: ChatModel, currentState: MutableState<Boolean>? = null) {
val newChatInfo = when(chat.chatInfo) {
is ChatInfo.Direct -> with (chat.chatInfo) {
ChatInfo.Direct(contact.copy(chatSettings = contact.chatSettings.copy(enableNtfs = enabled)))
ChatInfo.Direct(contact.copy(chatSettings = chatSettings))
}
is ChatInfo.Group -> with(chat.chatInfo) {
ChatInfo.Group(groupInfo.copy(chatSettings = groupInfo.chatSettings.copy(enableNtfs = enabled)))
ChatInfo.Group(groupInfo.copy(chatSettings = chatSettings))
}
else -> null
}
@@ -557,10 +581,13 @@ fun changeNtfsStatePerChat(enabled: Boolean, currentState: MutableState<Boolean>
}
if (res && newChatInfo != null) {
chatModel.updateChatInfo(newChatInfo)
if (!enabled) {
if (!chatSettings.enableNtfs) {
chatModel.controller.ntfManager.cancelNotificationsForChat(chat.id)
}
currentState.value = enabled
val current = currentState?.value
if (current != null) {
currentState.value = !current
}
}
}
}

View File

@@ -18,6 +18,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.capitalize
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.intl.Locale
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.*
import androidx.fragment.app.FragmentActivity
import chat.simplex.app.*
@@ -222,11 +223,6 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user
},
title = {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
stringResource(R.string.your_chats),
color = MaterialTheme.colors.onBackground,
fontWeight = FontWeight.SemiBold,
)
if (chatModel.incognito.value) {
Icon(
painterResource(R.drawable.ic_theater_comedy_filled),
@@ -235,6 +231,14 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user
modifier = Modifier.padding(10.dp).size(26.dp)
)
}
Text(
stringResource(R.string.your_chats),
color = MaterialTheme.colors.onBackground,
fontWeight = FontWeight.SemiBold,
)
if (chatModel.chats.size > 0) {
ToggleFilterButton()
}
}
},
onTitleClick = null,
@@ -275,6 +279,24 @@ private fun BoxScope.unreadBadge(text: String? = "") {
)
}
@Composable
private fun ToggleFilterButton() {
val pref = remember { SimplexApp.context.chatModel.controller.appPrefs.showUnreadAndFavorites }
IconButton(onClick = { pref.set(!pref.get()) }) {
Icon(
painterResource(R.drawable.ic_filter_list),
null,
tint = if (pref.state.value) MaterialTheme.colors.background else MaterialTheme.colors.primary,
modifier = Modifier
.padding(3.dp)
.background(color = if (pref.state.value) MaterialTheme.colors.primary else MaterialTheme.colors.background, shape = RoundedCornerShape(50))
.border(width = 1.dp, color = MaterialTheme.colors.primary, shape = RoundedCornerShape(50))
.padding(3.dp)
.size(16.dp)
)
}
}
@Composable
private fun ProgressIndicator() {
CircularProgressIndicator(
@@ -290,14 +312,12 @@ private var lazyListState = 0 to 0
@Composable
private fun ChatList(chatModel: ChatModel, search: String) {
val filter: (Chat) -> Boolean = { chat: Chat ->
chat.chatInfo.chatViewName.lowercase().contains(search.lowercase())
}
val listState = rememberLazyListState(lazyListState.first, lazyListState.second)
DisposableEffect(Unit) {
onDispose { lazyListState = listState.firstVisibleItemIndex to listState.firstVisibleItemScrollOffset }
}
val chats by remember(search) { derivedStateOf { if (search.isEmpty()) chatModel.chats else chatModel.chats.filter(filter) } }
val showUnreadAndFavorites = remember { chatModel.controller.appPrefs.showUnreadAndFavorites.state }.value
val chats by remember(search, showUnreadAndFavorites) { derivedStateOf { filteredChats(showUnreadAndFavorites, search) } }
LazyColumn(
modifier = Modifier.fillMaxWidth(),
listState
@@ -306,4 +326,44 @@ private fun ChatList(chatModel: ChatModel, search: String) {
ChatListNavLinkView(chat, chatModel)
}
}
if (chats.isEmpty() && !chatModel.chats.isEmpty()) {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(generalGetString(R.string.no_filtered_chats), color = MaterialTheme.colors.secondary)
}
}
}
private fun filteredChats(showUnreadAndFavorites: Boolean, searchText: String): List<Chat> {
val chatModel = SimplexApp.context.chatModel
val s = searchText.trim().lowercase()
return if (s.isEmpty() && !showUnreadAndFavorites)
chatModel.chats
else {
chatModel.chats.filter { chat ->
when (val cInfo = chat.chatInfo) {
is ChatInfo.Direct -> if (s.isEmpty()) {
filtered(chat)
} else {
(viewNameContains(cInfo, s) ||
cInfo.contact.profile.displayName.lowercase().contains(s) ||
cInfo.contact.fullName.lowercase().contains(s))
}
is ChatInfo.Group -> if (s.isEmpty()) {
(filtered(chat) || cInfo.groupInfo.membership.memberStatus == GroupMemberStatus.MemInvited)
} else {
viewNameContains(cInfo, s)
}
is ChatInfo.ContactRequest -> s.isEmpty() || viewNameContains(cInfo, s)
is ChatInfo.ContactConnection -> s.isNotEmpty() && cInfo.contactConnection.localAlias.lowercase().contains(s)
is ChatInfo.InvalidJSON -> false
}
}
}
}
private fun filtered(chat: Chat): Boolean =
(chat.chatInfo.chatSettings?.favorite ?: false) || chat.chatStats.unreadCount > 0 || chat.chatStats.unreadChat
private fun viewNameContains(cInfo: ChatInfo, s: String): Boolean =
cInfo.chatViewName.lowercase().contains(s.lowercase())

View File

@@ -245,6 +245,21 @@ fun ChatPreviewView(
.size(17.dp)
)
}
} else if (chat.chatInfo.chatSettings?.favorite == true) {
Box(
Modifier.padding(top = 24.dp),
contentAlignment = Alignment.Center
) {
Icon(
painterResource(R.drawable.ic_star_filled),
contentDescription = generalGetString(R.string.favorite_chat),
tint = MaterialTheme.colors.secondary,
modifier = Modifier
.padding(horizontal = 3.dp)
.padding(vertical = 1.dp)
.size(17.dp)
)
}
}
if (cInfo is ChatInfo.Direct) {
Box(

View File

@@ -33,7 +33,7 @@ fun DefaultTopAppBar(
if (!showSearch) {
title?.invoke()
} else {
SearchTextField(Modifier.fillMaxWidth(), stringResource(android.R.string.search_go), alwaysVisible = false, onSearchValueChanged)
SearchTextField(Modifier.fillMaxWidth(), alwaysVisible = false, onValueChange = onSearchValueChanged)
}
},
backgroundColor = if (isInDarkTheme()) ToolbarDark else ToolbarLight,

View File

@@ -1,5 +1,6 @@
package chat.simplex.app.views.helpers
import android.R
import android.util.Log
import androidx.activity.compose.BackHandler
import androidx.compose.animation.*
@@ -8,8 +9,13 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.capitalize
import androidx.compose.ui.text.intl.Locale
import chat.simplex.app.TAG
import chat.simplex.app.ui.theme.isInDarkTheme
import chat.simplex.app.ui.theme.themedBackground

View File

@@ -29,8 +29,13 @@ import kotlinx.coroutines.delay
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun SearchTextField(modifier: Modifier, placeholder: String, alwaysVisible: Boolean, onValueChange: (String) -> Unit) {
var searchText by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) }
fun SearchTextField(
modifier: Modifier,
alwaysVisible: Boolean,
searchText: MutableState<TextFieldValue> = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) },
placeholder: String = stringResource(android.R.string.search_go),
onValueChange: (String) -> Unit
) {
val focusRequester = remember { FocusRequester() }
val focusManager = LocalFocusManager.current
val keyboard = LocalSoftwareKeyboardController.current
@@ -45,7 +50,7 @@ fun SearchTextField(modifier: Modifier, placeholder: String, alwaysVisible: Bool
DisposableEffect(Unit) {
onDispose {
if (searchText.text.isNotEmpty()) onValueChange("")
if (searchText.value.text.isNotEmpty()) onValueChange("")
}
}
@@ -59,7 +64,7 @@ fun SearchTextField(modifier: Modifier, placeholder: String, alwaysVisible: Bool
val shape = MaterialTheme.shapes.small.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize)
val interactionSource = remember { MutableInteractionSource() }
BasicTextField(
value = searchText,
value = searchText.value,
modifier = modifier
.background(colors.backgroundColor(enabled).value, shape)
.indicatorLine(enabled, false, interactionSource, colors)
@@ -69,7 +74,7 @@ fun SearchTextField(modifier: Modifier, placeholder: String, alwaysVisible: Bool
minHeight = TextFieldDefaults.MinHeight
),
onValueChange = {
searchText = it
searchText.value = it
onValueChange(it.text)
},
cursorBrush = SolidColor(colors.cursorColor(false).value),
@@ -84,18 +89,18 @@ fun SearchTextField(modifier: Modifier, placeholder: String, alwaysVisible: Bool
interactionSource = interactionSource,
decorationBox = @Composable { innerTextField ->
TextFieldDefaults.TextFieldDecorationBox(
value = searchText.text,
value = searchText.value.text,
innerTextField = innerTextField,
placeholder = {
Text(placeholder)
},
trailingIcon = if (searchText.text.isNotEmpty()) {{
trailingIcon = if (searchText.value.text.isNotEmpty()) {{
IconButton({
if (alwaysVisible) {
keyboard?.hide()
focusManager.clearFocus()
}
searchText = TextFieldValue("");
searchText.value = TextFieldValue("");
onValueChange("")
}) {
Icon(painterResource(R.drawable.ic_close), stringResource(R.string.icon_descr_close_button), tint = MaterialTheme.colors.primary,)

View File

@@ -62,7 +62,7 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean, FragmentActivity)
ModalView(
{ close() },
endButtons = {
SearchTextField(Modifier.fillMaxWidth(), stringResource(android.R.string.search_go), alwaysVisible = true) { search.value = it }
SearchTextField(Modifier.fillMaxWidth(), alwaysVisible = true) { search.value = it }
},
content = { modalView(chatModel, search) })
}

View File

@@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="960"
android:viewportWidth="960" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M430.5,707.5q-12.25,0 -20.63,-8.18 -8.38,-8.18 -8.38,-20.5 0,-12.32 8.38,-20.58T430.5,650h99q12.25,0 20.63,8.43 8.38,8.43 8.38,20.75 0,12.32 -8.38,20.33t-20.63,8h-99ZM152.5,300q-12.25,0 -20.63,-8.18 -8.38,-8.18 -8.38,-20.5 0,-12.32 8.38,-20.58t20.63,-8.25h655q12.25,0 20.63,8.43 8.38,8.43 8.38,20.75 0,12.32 -8.38,20.33t-20.63,8h-655ZM271.5,504q-12.25,0 -20.63,-8.43 -8.38,-8.43 -8.38,-20.75 0,-11.82 8.38,-20.08t20.63,-8.25h417q11.75,0 20.13,8.43 8.38,8.43 8.38,20.25 0,12.32 -8.38,20.58T688.5,504h-417Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M480,729.5 L293.5,842q-8,5 -16.75,4.5T261.5,841q-6.5,-5 -10,-12.5t-1,-17.5l49,-212.5L135,455q-7.5,-6.5 -9.25,-14.5t0.25,-16q2,-8 9,-13.25t16.5,-6.25L369,386l84.5,-200.5q3.5,-8.5 11,-13T480,168q8,0 15.5,4.5t11.5,13L591.5,386 809,405q9,1 16,6.25t9,13.25q2,8 0.25,16T825,455L660.5,598.5 710,811q2,10 -1.5,17.5t-10,12.5q-6.5,5 -15.25,5.5T667,842L480,729.5Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector android:height="24dp" android:viewportHeight="960"
android:viewportWidth="960" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<group>
<clip-path android:pathData="m124.92,168.01v678.55h710.16v-678.55zM398.32,304.53c2.09,2.21 4.19,4.36 6.29,6.56 4.15,4.34 8.26,8.76 12.34,13.16 4.31,4.63 8.58,9.28 12.85,13.95 3.91,4.31 7.83,8.63 11.76,12.93 3.61,4.02 7.24,8.02 10.86,12.03l1.72,1.88 -5.43,4.92c2.66,2.71 5.31,5.44 7.97,8.16L437.5,396.84c3.42,3.27 6.86,6.52 10.27,9.8l2.93,2.85 -14.45,15 -2.93,-2.81c-6,-5.77 -12,-11.58 -18.05,-17.3 -5.52,-5.18 -11.09,-10.28 -16.76,-15.31 -5.86,-5.27 -11.73,-10.56 -17.5,-15.94 -3.88,-3.66 -7.77,-7.34 -11.45,-11.21 -1.01,-1.05 -2,-2.11 -3.05,-3.13l7.5,-7.89c-1.27,-1.33 -2.53,-2.67 -3.83,-3.98 -1.76,-1.8 -3.55,-3.6 -5.31,-5.39L372.07,335c-0.69,-0.73 -1.39,-1.45 -2.07,-2.19zM622.85,527.89c0.98,1.11 1.94,2.25 2.93,3.36 2.92,3.29 5.93,6.49 8.91,9.73 3.89,4.24 7.78,8.47 11.68,12.7 3.7,4.02 7.4,8.03 11.13,12.03 3.37,3.66 6.82,7.32 10.23,10.94 3.28,3.41 6.54,6.81 9.8,10.23 3.57,3.78 7.15,7.57 10.7,11.37 2.84,3.02 5.68,6 8.52,9.02l-12.77,12.03c1.03,1.1 2.06,2.19 3.09,3.28l-3.95,3.71c0.52,0.7 1.04,1.4 1.13,1.52 2.1,2.62 4.28,5.17 6.45,7.73l-1.56,1.29c1.82,2.14 3.71,4.2 5.59,6.29 0.87,0.95 1.78,1.87 2.66,2.81l4.18,-3.36c3.86,4.81 7.71,9.63 11.6,14.41 3.65,4.49 7.31,8.94 11.13,13.28 3.45,4.01 6.9,8.04 10.27,12.11 2.75,3.32 5.52,6.62 8.2,10 3.03,3.94 6.03,7.92 7.73,12.66 -28.44,22.74 -22.95,32.05 -37.19,16.8 -3.88,-4.21 -7.78,-8.42 -11.68,-12.62 -5.85,-6.31 -11.68,-12.6 -17.58,-18.87 -6.38,-6.81 -12.79,-13.6 -19.1,-20.47 -3.99,-4.44 -8.09,-8.87 -11.45,-13.83l0.47,-0.27c-4.95,-4.81 -9.89,-9.64 -14.84,-14.45 -3.9,-3.83 -7.85,-7.63 -11.6,-11.6l5.66,-5.16c-0.58,-0.57 -1.17,-1.15 -1.76,-1.72 -6.97,-6.69 -14,-13.33 -21.13,-19.84l-0.66,0.66c-2.91,-2.91 -5.78,-5.84 -8.67,-8.75 -1.04,-0.87 -2.01,-1.83 -3.09,-2.66l0.2,-0.27c-2.67,-2.7 -5.36,-5.37 -8.01,-8.09 -6.04,-6.23 -11.98,-12.56 -17.73,-19.06 -2,-2.24 -4.01,-4.52 -6.05,-6.72l29.22,-27.3c2.27,2.44 4.5,4.93 6.72,7.42 0.94,1.06 1.92,2.09 2.89,3.13z"/>
<path android:fillColor="#FF000000" android:pathData="m321,757.5 l159,-95 159,96 -42.5,-180 140,-121.5L552,440.5l-72,-170L408.5,440 224,456l140,121 -43,180.5ZM480,729.5L293.5,842q-8,5 -16.75,4.5T261.5,841q-6.5,-5 -10,-12.5t-1,-17.5l49,-212.5L135,455q-7.5,-6.5 -9.25,-14.5t0.25,-16q2,-8 9,-13.25t16.5,-6.25L369,386l84.5,-200.5q3.5,-8.5 11,-13T480,168q8,0 15.5,4.5t11.5,13L591.5,386 809,405q9,1 16,6.25t9,13.25q2,8 0.25,16T825,455L660.5,598.5 710,811q2,10 -1.5,17.5t-10,12.5q-6.5,5 -15.25,5.5T667,842L480,729.5ZM480,524.5Z"/>
</group>
<path android:fillColor="#FF000000"
android:pathData="M639.94,703.24 L132.69,196.96c-5.82,-5.5 -8.73,-11.88 -8.73,-19.16 0,-7.27 2.83,-13.82 8.49,-19.64 5.66,-5.82 12.12,-8.73 19.4,-8.73 7.27,0 13.82,2.75 19.64,8.24l657.97,658.94c5.56,5.56 8.26,12.05 8.09,19.47 -0.16,7.43 -2.83,13.9 -8,19.41 -5.81,5.5 -12.36,8.24 -19.63,8.24 -7.28,0 -13.67,-2.76 -19.19,-8.27L640.02,704.39c0,0 -0.66,-1.96 -0.09,-1.15z" android:strokeWidth="0.969876"/>
</vector>

View File

@@ -951,7 +951,7 @@
<string name="you_will_be_connected_when_your_contacts_device_is_online">Budete připojeni, jakmile bude zařízení vašeho kontaktu online, vyčkejte prosím nebo se podívejte později!</string>
<string name="your_chat_profile_will_be_sent_to_your_contact">Váš chat profil bude odeslán
\nvašemu kontaktu</string>
<string name="your_chats">Vaše konverzace</string>
<string name="your_chats">Konverzace</string>
<string name="paste_connection_link_below_to_connect">Do níže uvedeného pole vložte odkaz, který jste obdrželi pro spojení s kontaktem.</string>
<string name="share_invitation_link">Sdílet jednorázovou pozvánku</string>
<string name="status_e2e_encrypted">koncově šifrované</string>

View File

@@ -170,7 +170,7 @@
<string name="personal_welcome">Willkommen <xliff:g>%1$s</xliff:g>!</string>
<string name="welcome">Willkommen!</string>
<string name="this_text_is_available_in_settings">Dieser Text ist in den Einstellungen verfügbar.</string>
<string name="your_chats">Meine Chats</string>
<string name="your_chats">Chats</string>
<string name="contact_connection_pending">verbinde …</string>
<string name="group_preview_you_are_invited">Sie sind zu der Gruppe eingeladen</string>
<string name="group_preview_join_as">Beitreten als %s</string>

View File

@@ -118,7 +118,7 @@
<string name="allow_verb">Autoriser</string>
<string name="delete_message__question">Supprimer le message\?</string>
<string name="for_me_only">Supprimer pour moi</string>
<string name="your_chats">Vos chats</string>
<string name="your_chats">Chats</string>
<string name="notification_preview_mode_message">Texte du message</string>
<string name="notification_preview_mode_hidden">Caché</string>
<string name="la_notice_to_protect_your_information_turn_on_simplex_lock_you_will_be_prompted_to_complete_authentication_before_this_feature_is_enabled">Pour protéger vos informations, activez la fonction SimpleX Lock.

View File

@@ -145,7 +145,7 @@
<string name="personal_welcome">Benvenuto/a <xliff:g>%1$s</xliff:g>!</string>
<string name="welcome">Benvenuto/a!</string>
<string name="this_text_is_available_in_settings">Questo testo è disponibile nelle impostazioni</string>
<string name="your_chats">Le tue chat</string>
<string name="your_chats">Сhat</string>
<string name="group_preview_you_are_invited">sei stato invitato in un gruppo</string>
<string name="group_preview_join_as">entra come %s</string>
<string name="group_connection_pending">in connessione…</string>

View File

@@ -1220,7 +1220,7 @@
<string name="group_main_profile_sent">פרופיל הצ׳אט שלך יישלח לחברי הקבוצה</string>
<string name="database_is_not_encrypted">מסד הנתונים שלך אינו מוצפן יש להגדיר סיסמה כדי להגן עליו.</string>
<string name="v4_3_irreversible_message_deletion_desc">אנשי הקשר שלך יכולים לאפשר מחיקת הודעות מלאה.</string>
<string name="your_chats">הצ׳אטים שלך</string>
<string name="your_chats">הצ׳אטים</string>
<string name="contact_sent_large_file">איש הקשר שלך שלח קובץ גדול יותר מהגודל המרבי הנתמך כעת (<xliff:g id="maxFileSize">%1$s</xliff:g>).</string>
<string name="alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry">איש הקשר שלך צריך להיות מקוון כדי שהחיבור יושלם.
\nניתן לבטל חיבור זה ולהסיר את איש הקשר (ולנסות מאוחר יותר עם קישור חדש).</string>

View File

@@ -704,7 +704,7 @@
<string name="images_limit_title">画像数の上限を超えてます!</string>
<string name="welcome">ようこそ!</string>
<string name="group_preview_you_are_invited">グループ招待が届きました</string>
<string name="your_chats">あなたのチャット</string>
<string name="your_chats">チャット</string>
<string name="text_field_set_contact_placeholder">連絡先を設定…</string>
<string name="waiting_for_file">ファイル待ち</string>
<string name="switch_receiving_address_question">受信アドレスを変えますか?</string>

View File

@@ -347,7 +347,7 @@
<string name="you_will_stop_receiving_messages_from_this_group_chat_history_will_be_preserved">Jūs nustosite gauti žinutes iš šios grupės. Pokalbio istorija bus išsaugota.</string>
<string name="group_info_member_you">jūs: <xliff:g id="group_info_you">%1$s</xliff:g></string>
<string name="personal_welcome">Sveiki, <xliff:g>%1$s</xliff:g>!</string>
<string name="your_chats">Jūsų pokalbiai</string>
<string name="your_chats">Pokalbiai</string>
<string name="wrong_passphrase">Neteisinga duomenų bazės slaptafrazė</string>
<string name="icon_descr_video_snd_complete">Vaizdo įrašas išsiųstas</string>
<string name="voice_message">Balso žinutė</string>

View File

@@ -662,7 +662,7 @@
<string name="welcome">Welkom!</string>
<string name="group_preview_you_are_invited">je bent uitgenodigd voor de groep</string>
<string name="you_have_no_chats">Je hebt geen gesprekken</string>
<string name="your_chats">Jouw gesprekken</string>
<string name="your_chats">Gesprekken</string>
<string name="share_file">Deel bestand…</string>
<string name="share_image">Afbeelding delen…</string>
<string name="icon_descr_waiting_for_image">Wachten op afbeelding</string>

View File

@@ -156,7 +156,7 @@
<string name="personal_welcome">Witaj <xliff:g>%1$s</xliff:g>!</string>
<string name="group_preview_you_are_invited">jesteś zaproszony do grupy</string>
<string name="you_have_no_chats">Nie masz czatów</string>
<string name="your_chats">Twoje czaty</string>
<string name="your_chats">Czaty</string>
<string name="icon_descr_asked_to_receive">Poproszony o odbiór obrazu</string>
<string name="icon_descr_video_asked_to_receive">Poproszony o odbiór filmu</string>
<string name="image_decoding_exception_title">Błąd dekodowania</string>

View File

@@ -573,7 +573,7 @@
<string name="notifications_mode_off">Executa quando o aplicativo está aberto</string>
<string name="icon_descr_sent_msg_status_sent">enviado</string>
<string name="icon_descr_sent_msg_status_send_failed">o envio falhou</string>
<string name="your_chats">Seus chats</string>
<string name="your_chats">Chats</string>
<string name="your_profile_will_be_sent">Seu perfil de chat será enviado para seu contato</string>
<string name="paste_button">Colar</string>
<string name="one_time_link">Link de convite de uso único</string>

View File

@@ -172,7 +172,7 @@
<string name="personal_welcome">Здравствуйте <xliff:g>%1$s</xliff:g>!</string>
<string name="welcome">Здравствуйте!</string>
<string name="this_text_is_available_in_settings">Этот текст можно найти в Настройках</string>
<string name="your_chats">Ваши чаты</string>
<string name="your_chats">Чаты</string>
<string name="contact_connection_pending">соединяется…</string>
<string name="group_preview_you_are_invited">Вы приглашены в группу</string>
<string name="group_preview_join_as">вступить как %s</string>

View File

@@ -1103,7 +1103,7 @@
<string name="personal_welcome">ยินดีต้อนรับ <xliff:g>%1$s</xliff:g>!</string>
<string name="group_preview_you_are_invited">คุณได้รับเชิญให้เข้าร่วมกลุ่ม</string>
<string name="you_have_no_chats">คุณไม่มีการแชท</string>
<string name="your_chats">แชทของคุณ</string>
<string name="your_chats">แชท</string>
<string name="you_are_observer">คุณเป็นผู้สังเกตการณ์</string>
<string name="image_decoding_exception_desc">ไม่สามารถถอดรหัสภาพได้ โปรดลองใช้ภาพอื่นหรือติดต่อผู้พัฒนาแอป</string>
<string name="observer_cant_send_message_title">คุณไม่สามารถส่งข้อความได้!</string>

View File

@@ -331,7 +331,7 @@
<string name="auth_stop_chat">Зупинити чат</string>
<string name="auth_open_chat_console">Відкрийте консоль чату</string>
<string name="moderate_message_will_be_marked_warning">Повідомлення буде позначено як модероване для всіх учасників.</string>
<string name="your_chats">Ваші чати</string>
<string name="your_chats">Чати</string>
<string name="contact_connection_pending">підключення…</string>
<string name="group_connection_pending">підключення…</string>
<string name="tap_to_start_new_chat">Натисніть, щоб почати новий чат</string>

View File

@@ -495,7 +495,7 @@
<string name="notification_preview_mode_contact_desc">只显示联系人</string>
<string name="la_notice_to_protect_your_information_turn_on_simplex_lock_you_will_be_prompted_to_complete_authentication_before_this_feature_is_enabled">为保护您的信息,请打开 SimpleX 锁定。
\n在启用此功能之前系统将提示您完成身份验证。</string>
<string name="your_chats">您的聊天</string>
<string name="your_chats">聊天</string>
<string name="share_file">分享文件……</string>
<string name="share_image">分享媒体……</string>
<string name="share_message">分享消息……</string>

View File

@@ -253,7 +253,7 @@
<string name="personal_welcome">Welcome <xliff:g>%1$s</xliff:g>!</string>
<string name="welcome">Welcome!</string>
<string name="this_text_is_available_in_settings">This text is available in settings</string>
<string name="your_chats">Your chats</string>
<string name="your_chats">Chats</string>
<string name="contact_connection_pending">connecting…</string>
<string name="group_preview_you_are_invited">you are invited to group</string>
<string name="group_preview_join_as">join as %s</string>
@@ -261,6 +261,7 @@
<string name="tap_to_start_new_chat">Tap to start a new chat</string>
<string name="chat_with_developers">Chat with the developers</string>
<string name="you_have_no_chats">You have no chats</string>
<string name="no_filtered_chats">No filtered chats</string>
<!-- ShareListView.kt -->
<string name="share_message">Share message…</string>
@@ -281,6 +282,8 @@
<string name="you_are_observer">you are observer</string>
<string name="observer_cant_send_message_title">You can\'t send messages!</string>
<string name="observer_cant_send_message_desc">Please contact group admin.</string>
<string name="files_and_media_prohibited">Files and media prohibited!</string>
<string name="only_owners_can_enable_files_and_media">Only group owners can enable files and media.</string>
<!-- Images - chat.simplex.app.views.chat.item.CIImageView.kt -->
<string name="image_descr">Image</string>
@@ -422,6 +425,9 @@
<!-- Actions - ChatListNavLinkView.kt -->
<string name="mute_chat">Mute</string>
<string name="unmute_chat">Unmute</string>
<string name="favorite_chat">Favorite</string>
<string name="unfavorite_chat">Unfavorite</string>
<!-- Pending contact connection alert dialogues -->
<string name="you_invited_your_contact">You invited your contact</string>
@@ -1290,6 +1296,7 @@
<string name="full_deletion">Delete for everyone</string>
<string name="message_reactions">Message reactions</string>
<string name="voice_messages">Voice messages</string>
<string name="files_and_media">Files and media</string>
<string name="audio_video_calls">Audio/video calls</string>
<string name="available_in_v51">\nAvailable in v5.1</string>
<string name="feature_enabled">enabled</string>
@@ -1344,6 +1351,8 @@
<string name="prohibit_sending_voice">Prohibit sending voice messages.</string>
<string name="allow_message_reactions">Allow message reactions.</string>
<string name="prohibit_message_reactions_group">Prohibit messages reactions.</string>
<string name="allow_to_send_files">Allow to send files and media.</string>
<string name="prohibit_sending_files">Prohibit sending files and media.</string>
<string name="group_members_can_send_disappearing">Group members can send disappearing messages.</string>
<string name="disappearing_messages_are_prohibited">Disappearing messages are prohibited in this group.</string>
<string name="group_members_can_send_dms">Group members can send direct messages.</string>
@@ -1354,6 +1363,8 @@
<string name="voice_messages_are_prohibited">Voice messages are prohibited in this group.</string>
<string name="group_members_can_add_message_reactions">Group members can add message reactions.</string>
<string name="message_reactions_are_prohibited">Message reactions are prohibited in this group.</string>
<string name="group_members_can_send_files">Group members can send files and media.</string>
<string name="files_are_prohibited_in_group">Files and media are prohibited in this group.</string>
<string name="delete_after">Delete after</string>
<string name="ttl_sec">%d sec</string>
<string name="ttl_s">%ds</string>

View File

@@ -264,7 +264,7 @@ struct ComposeView: View {
default: previewView()
}
HStack (alignment: .bottom) {
Button {
let b = Button {
showChooseSource = true
} label: {
Image(systemName: "paperclip")
@@ -274,6 +274,17 @@ struct ComposeView: View {
.frame(width: 25, height: 25)
.padding(.bottom, 12)
.padding(.leading, 12)
if case let .group(g) = chat.chatInfo,
!g.fullGroupPreferences.files.on {
b.disabled(true).onTapGesture {
AlertManager.shared.showAlertMsg(
title: "Files and media prohibited!",
message: "Only group owners can enable files and media."
)
}
} else {
b
}
ZStack(alignment: .leading) {
SendMessageView(
composeState: $composeState,

View File

@@ -27,6 +27,8 @@ struct GroupPreferencesView: View {
featureSection(.directMessages, $preferences.directMessages.enable)
featureSection(.reactions, $preferences.reactions.enable)
featureSection(.voice, $preferences.voice.enable)
// TODO uncomment in 5.3
// featureSection(.files, $preferences.files.enable)
if groupInfo.canEdit {
Section {

View File

@@ -117,18 +117,24 @@ struct ChatListView: View {
}
}
private var chatList: some View {
List {
ForEach(filteredChats(), id: \.viewId) { chat in
ChatListNavLink(chat: chat)
.padding(.trailing, -16)
.disabled(chatModel.chatRunning != true)
@ViewBuilder private var chatList: some View {
let cs = filteredChats()
ZStack {
List {
ForEach(cs, id: \.viewId) { chat in
ChatListNavLink(chat: chat)
.padding(.trailing, -16)
.disabled(chatModel.chatRunning != true)
}
}
}
.onChange(of: chatModel.chatId) { _ in
if chatModel.chatId == nil, let chatId = chatModel.chatToTop {
chatModel.chatToTop = nil
chatModel.popChat(chatId)
.onChange(of: chatModel.chatId) { _ in
if chatModel.chatId == nil, let chatId = chatModel.chatToTop {
chatModel.chatToTop = nil
chatModel.popChat(chatId)
}
}
if cs.isEmpty && !chatModel.chats.isEmpty {
Text("No filtered chats").foregroundColor(.secondary)
}
}
}
@@ -195,18 +201,34 @@ struct ChatListView: View {
return s == "" && !showUnreadAndFavorites
? chatModel.chats
: chatModel.chats.filter { chat in
let contains = s == ""
? ((chat.chatInfo.chatSettings?.favorite ?? false) || chat.chatStats.unreadCount > 0 || chat.chatStats.unreadChat)
: chat.chatInfo.chatViewName.localizedLowercase.contains(s)
switch chat.chatInfo {
let cInfo = chat.chatInfo
switch cInfo {
case let .direct(contact):
return contains
|| contact.profile.displayName.localizedLowercase.contains(s)
|| contact.fullName.localizedLowercase.contains(s)
case .contactConnection: return false
default: return contains
return s == ""
? filtered(chat)
: (viewNameContains(cInfo, s) ||
contact.profile.displayName.localizedLowercase.contains(s) ||
contact.fullName.localizedLowercase.contains(s))
case let .group(gInfo):
return s == ""
? (filtered(chat) || gInfo.membership.memberStatus == .memInvited)
: viewNameContains(cInfo, s)
case .contactRequest:
return s == "" || viewNameContains(cInfo, s)
case let .contactConnection(conn):
return s != "" && conn.localAlias.localizedLowercase.contains(s)
case .invalidJSON:
return false
}
}
func filtered(_ chat: Chat) -> Bool {
(chat.chatInfo.chatSettings?.favorite ?? false) || chat.chatStats.unreadCount > 0 || chat.chatStats.unreadChat
}
func viewNameContains(_ cInfo: ChatInfo, _ s: String) -> Bool {
cInfo.chatViewName.localizedLowercase.contains(s)
}
}
}

View File

@@ -115,6 +115,11 @@
5CC2C0FC2809BF11000C35E3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CC2C0FA2809BF11000C35E3 /* Localizable.strings */; };
5CC2C0FF2809BF11000C35E3 /* SimpleX--iOS--InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CC2C0FD2809BF11000C35E3 /* SimpleX--iOS--InfoPlist.strings */; };
5CC868F329EB540C0017BBFD /* CIRcvDecryptionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC868F229EB540C0017BBFD /* CIRcvDecryptionError.swift */; };
5CCAA6D52A4B38F700BAF93B /* libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6D02A4B38F600BAF93B /* libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ.a */; };
5CCAA6D62A4B38F700BAF93B /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6D12A4B38F600BAF93B /* libgmp.a */; };
5CCAA6D72A4B38F700BAF93B /* libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6D22A4B38F600BAF93B /* libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ-ghc8.10.7.a */; };
5CCAA6D82A4B38F700BAF93B /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6D32A4B38F600BAF93B /* libgmpxx.a */; };
5CCAA6D92A4B38F700BAF93B /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6D42A4B38F600BAF93B /* libffi.a */; };
5CCB939C297EFCB100399E78 /* NavStackCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCB939B297EFCB100399E78 /* NavStackCompat.swift */; };
5CCD403427A5F6DF00368C90 /* AddContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403327A5F6DF00368C90 /* AddContactView.swift */; };
5CCD403727A5F9A200368C90 /* ScanToConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */; };
@@ -147,11 +152,6 @@
5CFE0922282EEAF60002594B /* ZoomableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */; };
6407BA83295DA85D0082BA18 /* CIInvalidJSONView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */; };
6432857C2925443C00FBE5C8 /* GroupPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */; };
643EE9682A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 643EE9632A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a */; };
643EE9692A372E8700678085 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 643EE9642A372E8700678085 /* libffi.a */; };
643EE96A2A372E8700678085 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 643EE9652A372E8700678085 /* libgmpxx.a */; };
643EE96B2A372E8700678085 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 643EE9662A372E8700678085 /* libgmp.a */; };
643EE96C2A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 643EE9672A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt-ghc8.10.7.a */; };
6440CA00288857A10062C672 /* CIEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6440C9FF288857A10062C672 /* CIEventView.swift */; };
6440CA03288AECA70062C672 /* AddGroupMembersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6440CA02288AECA70062C672 /* AddGroupMembersView.swift */; };
6442E0BA287F169300CEC0F9 /* AddGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6442E0B9287F169300CEC0F9 /* AddGroupView.swift */; };
@@ -392,6 +392,11 @@
5CC2C0FB2809BF11000C35E3 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
5CC2C0FE2809BF11000C35E3 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = "ru.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
5CC868F229EB540C0017BBFD /* CIRcvDecryptionError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIRcvDecryptionError.swift; sourceTree = "<group>"; };
5CCAA6D02A4B38F600BAF93B /* libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ.a"; sourceTree = "<group>"; };
5CCAA6D12A4B38F600BAF93B /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5CCAA6D22A4B38F600BAF93B /* libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ-ghc8.10.7.a"; sourceTree = "<group>"; };
5CCAA6D32A4B38F600BAF93B /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5CCAA6D42A4B38F600BAF93B /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5CCB939B297EFCB100399E78 /* NavStackCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavStackCompat.swift; sourceTree = "<group>"; };
5CCD403327A5F6DF00368C90 /* AddContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContactView.swift; sourceTree = "<group>"; };
5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanToConnectView.swift; sourceTree = "<group>"; };
@@ -422,11 +427,6 @@
5CFE0920282EEAF60002594B /* ZoomableScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ZoomableScrollView.swift; path = Shared/Views/ZoomableScrollView.swift; sourceTree = SOURCE_ROOT; };
6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIInvalidJSONView.swift; sourceTree = "<group>"; };
6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupPreferencesView.swift; sourceTree = "<group>"; };
643EE9632A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a"; sourceTree = "<group>"; };
643EE9642A372E8700678085 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
643EE9652A372E8700678085 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
643EE9662A372E8700678085 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
643EE9672A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt-ghc8.10.7.a"; sourceTree = "<group>"; };
6440C9FF288857A10062C672 /* CIEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIEventView.swift; sourceTree = "<group>"; };
6440CA02288AECA70062C672 /* AddGroupMembersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddGroupMembersView.swift; sourceTree = "<group>"; };
6442E0B9287F169300CEC0F9 /* AddGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddGroupView.swift; sourceTree = "<group>"; };
@@ -497,13 +497,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5CCAA6D82A4B38F700BAF93B /* libgmpxx.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
643EE96A2A372E8700678085 /* libgmpxx.a in Frameworks */,
5CCAA6D72A4B38F700BAF93B /* libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ-ghc8.10.7.a in Frameworks */,
5CCAA6D52A4B38F700BAF93B /* libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ.a in Frameworks */,
5CCAA6D92A4B38F700BAF93B /* libffi.a in Frameworks */,
5CCAA6D62A4B38F700BAF93B /* libgmp.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
643EE9682A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a in Frameworks */,
643EE96B2A372E8700678085 /* libgmp.a in Frameworks */,
643EE9692A372E8700678085 /* libffi.a in Frameworks */,
643EE96C2A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt-ghc8.10.7.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -564,11 +564,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
643EE9642A372E8700678085 /* libffi.a */,
643EE9662A372E8700678085 /* libgmp.a */,
643EE9652A372E8700678085 /* libgmpxx.a */,
643EE9672A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt-ghc8.10.7.a */,
643EE9632A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a */,
5CCAA6D42A4B38F600BAF93B /* libffi.a */,
5CCAA6D12A4B38F600BAF93B /* libgmp.a */,
5CCAA6D32A4B38F600BAF93B /* libgmpxx.a */,
5CCAA6D22A4B38F600BAF93B /* libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ-ghc8.10.7.a */,
5CCAA6D02A4B38F600BAF93B /* libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ.a */,
);
path = Libraries;
sourceTree = "<group>";

View File

@@ -1090,9 +1090,9 @@ public struct KeepAliveOpts: Codable, Equatable {
public struct ChatSettings: Codable {
public var enableNtfs: Bool
public var favorite: Bool? = false
public var favorite: Bool
public init(enableNtfs: Bool, favorite: Bool?) {
public init(enableNtfs: Bool, favorite: Bool) {
self.enableNtfs = enableNtfs
self.favorite = favorite
}

View File

@@ -667,10 +667,11 @@ public enum ChatFeature: String, Decodable, Feature {
public enum GroupFeature: String, Decodable, Feature {
case timedMessages
case directMessages
case fullDelete
case reactions
case voice
case directMessages
case files
public var id: Self { self }
@@ -688,6 +689,7 @@ public enum GroupFeature: String, Decodable, Feature {
case .fullDelete: return NSLocalizedString("Delete for everyone", comment: "chat feature")
case .reactions: return NSLocalizedString("Message reactions", comment: "chat feature")
case .voice: return NSLocalizedString("Voice messages", comment: "chat feature")
case .files: return NSLocalizedString("Files and media", comment: "chat feature")
}
}
@@ -698,6 +700,7 @@ public enum GroupFeature: String, Decodable, Feature {
case .fullDelete: return "trash.slash"
case .reactions: return "face.smiling"
case .voice: return "mic"
case .files: return "doc"
}
}
@@ -708,6 +711,7 @@ public enum GroupFeature: String, Decodable, Feature {
case .fullDelete: return "trash.slash.fill"
case .reactions: return "face.smiling.fill"
case .voice: return "mic.fill"
case .files: return "doc.fill"
}
}
@@ -746,6 +750,11 @@ public enum GroupFeature: String, Decodable, Feature {
case .on: return "Allow to send voice messages."
case .off: return "Prohibit sending voice messages."
}
case .files:
switch enabled {
case .on: return "Allow to send files and media."
case .off: return "Prohibit sending files and media."
}
}
} else {
switch self {
@@ -774,6 +783,11 @@ public enum GroupFeature: String, Decodable, Feature {
case .on: return "Group members can send voice messages."
case .off: return "Voice messages are prohibited in this group."
}
case .files:
switch enabled {
case .on: return "Group members can send files and media."
case .off: return "Files and media are prohibited in this group."
}
}
}
}
@@ -912,19 +926,22 @@ public struct FullGroupPreferences: Decodable, Equatable {
public var fullDelete: GroupPreference
public var reactions: GroupPreference
public var voice: GroupPreference
public var files: GroupPreference
public init(
timedMessages: TimedMessagesGroupPreference,
directMessages: GroupPreference,
fullDelete: GroupPreference,
reactions: GroupPreference,
voice: GroupPreference
voice: GroupPreference,
files: GroupPreference
) {
self.timedMessages = timedMessages
self.directMessages = directMessages
self.fullDelete = fullDelete
self.reactions = reactions
self.voice = voice
self.files = files
}
public static let sampleData = FullGroupPreferences(
@@ -932,7 +949,8 @@ public struct FullGroupPreferences: Decodable, Equatable {
directMessages: GroupPreference(enable: .off),
fullDelete: GroupPreference(enable: .off),
reactions: GroupPreference(enable: .on),
voice: GroupPreference(enable: .on)
voice: GroupPreference(enable: .on),
files: GroupPreference(enable: .on)
)
}
@@ -942,19 +960,22 @@ public struct GroupPreferences: Codable {
public var fullDelete: GroupPreference?
public var reactions: GroupPreference?
public var voice: GroupPreference?
public var files: GroupPreference?
public init(
timedMessages: TimedMessagesGroupPreference?,
directMessages: GroupPreference?,
fullDelete: GroupPreference?,
reactions: GroupPreference?,
voice: GroupPreference?
voice: GroupPreference?,
files: GroupPreference?
) {
self.timedMessages = timedMessages
self.directMessages = directMessages
self.fullDelete = fullDelete
self.reactions = reactions
self.voice = voice
self.files = files
}
public static let sampleData = GroupPreferences(
@@ -962,7 +983,8 @@ public struct GroupPreferences: Codable {
directMessages: GroupPreference(enable: .off),
fullDelete: GroupPreference(enable: .off),
reactions: GroupPreference(enable: .on),
voice: GroupPreference(enable: .on)
voice: GroupPreference(enable: .on),
files: GroupPreference(enable: .on)
)
}
@@ -972,7 +994,8 @@ public func toGroupPreferences(_ fullPreferences: FullGroupPreferences) -> Group
directMessages: fullPreferences.directMessages,
fullDelete: fullPreferences.fullDelete,
reactions: fullPreferences.reactions,
voice: fullPreferences.voice
voice: fullPreferences.voice,
files: fullPreferences.files
)
}

View File

@@ -1,5 +1,5 @@
name: simplex-chat
version: 5.1.3.0
version: 5.2.0.0
#synopsis:
#description:
homepage: https://github.com/simplex-chat/simplex-chat#readme

View File

@@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack
name: simplex-chat
version: 5.1.3.0
version: 5.2.0.0
category: Web, System, Services, Cryptography
homepage: https://github.com/simplex-chat/simplex-chat#readme
author: simplex.chat