mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
core, mobile: add group feature to allow direct messages (#1465)
* core, mobile: split group features to a separate type (to add directAllowed later) * add directMessages group feature, update tests
This commit is contained in:
committed by
GitHub
parent
303aeaaba5
commit
1872744543
@@ -1098,6 +1098,7 @@ data class ChatItem (
|
||||
is CIContent.RcvGroupFeature -> false
|
||||
is CIContent.SndGroupFeature -> showNtfDir
|
||||
is CIContent.RcvChatFeatureRejected -> showNtfDir
|
||||
is CIContent.RcvGroupFeatureRejected -> showNtfDir
|
||||
}
|
||||
|
||||
fun withStatus(status: CIStatus): ChatItem = this.copy(meta = meta.copy(itemStatus = status))
|
||||
@@ -1171,7 +1172,7 @@ data class ChatItem (
|
||||
file = null
|
||||
)
|
||||
|
||||
fun getChatFeatureSample(feature: Feature, enabled: FeatureEnabled): ChatItem {
|
||||
fun getChatFeatureSample(feature: ChatFeature, enabled: FeatureEnabled): ChatItem {
|
||||
val content = CIContent.RcvChatFeature(feature = feature, enabled = enabled)
|
||||
return ChatItem(
|
||||
chatDir = CIDirection.DirectRcv(),
|
||||
@@ -1277,11 +1278,12 @@ sealed class CIContent: ItemContent {
|
||||
@Serializable @SerialName("sndGroupEvent") class SndGroupEventContent(val sndGroupEvent: SndGroupEvent): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvConnEvent") class RcvConnEventContent(val rcvConnEvent: RcvConnEvent): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("sndConnEvent") class SndConnEventContent(val sndConnEvent: SndConnEvent): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvChatFeature") class RcvChatFeature(val feature: Feature, val enabled: FeatureEnabled): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("sndChatFeature") class SndChatFeature(val feature: Feature, val enabled: FeatureEnabled): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvGroupFeature") class RcvGroupFeature(val feature: Feature, val preference: GroupPreference): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("sndGroupFeature") class SndGroupFeature(val feature: Feature, val preference: GroupPreference): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvChatFeatureRejected") class RcvChatFeatureRejected(val feature: Feature): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvChatFeature") class RcvChatFeature(val feature: ChatFeature, val enabled: FeatureEnabled): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("sndChatFeature") class SndChatFeature(val feature: ChatFeature, val enabled: FeatureEnabled): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvGroupFeature") class RcvGroupFeature(val groupFeature: GroupFeature, val preference: GroupPreference): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("sndGroupFeature") class SndGroupFeature(val groupFeature: GroupFeature, val preference: GroupPreference): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvChatFeatureRejected") class RcvChatFeatureRejected(val feature: ChatFeature): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvGroupFeatureRejected") class RcvGroupFeatureRejected(val groupFeature: GroupFeature): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
|
||||
override val text: String get() = when (this) {
|
||||
is SndMsgContent -> msgContent.text
|
||||
@@ -1299,9 +1301,10 @@ sealed class CIContent: ItemContent {
|
||||
is SndConnEventContent -> sndConnEvent.text
|
||||
is RcvChatFeature -> "${feature.text}: ${enabled.text}"
|
||||
is SndChatFeature -> "${feature.text}: ${enabled.text}"
|
||||
is RcvGroupFeature -> "${feature.text}: ${preference.enable.text}"
|
||||
is SndGroupFeature -> "${feature.text}: ${preference.enable.text}"
|
||||
is RcvGroupFeature -> "${groupFeature.text}: ${preference.enable.text}"
|
||||
is SndGroupFeature -> "${groupFeature.text}: ${preference.enable.text}"
|
||||
is RcvChatFeatureRejected -> "${feature.text}: ${generalGetString(R.string.feature_received_prohibited)}"
|
||||
is RcvGroupFeatureRejected -> "${groupFeature.text}: ${generalGetString(R.string.feature_received_prohibited)}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@ import android.util.Log
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.DeleteForever
|
||||
import androidx.compose.material.icons.filled.KeyboardVoice
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material.icons.outlined.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -2048,12 +2047,18 @@ sealed class ContactUserPref {
|
||||
@Serializable @SerialName("user") data class User(val preference: ChatPreference): ContactUserPref() // global user default is used
|
||||
}
|
||||
|
||||
interface Feature {
|
||||
// val icon: ImageVector
|
||||
val text: String
|
||||
val iconFilled: ImageVector
|
||||
}
|
||||
|
||||
@Serializable
|
||||
enum class Feature {
|
||||
enum class ChatFeature: Feature {
|
||||
@SerialName("fullDelete") FullDelete,
|
||||
@SerialName("voice") Voice;
|
||||
|
||||
val text: String
|
||||
override val text: String
|
||||
get() = when(this) {
|
||||
FullDelete -> generalGetString(R.string.full_deletion)
|
||||
Voice -> generalGetString(R.string.voice_messages)
|
||||
@@ -2065,7 +2070,7 @@ enum class Feature {
|
||||
Voice -> Icons.Outlined.KeyboardVoice
|
||||
}
|
||||
|
||||
val iconFilled: ImageVector
|
||||
override val iconFilled: ImageVector
|
||||
get() = when(this) {
|
||||
FullDelete -> Icons.Filled.DeleteForever
|
||||
Voice -> Icons.Filled.KeyboardVoice
|
||||
@@ -2100,31 +2105,67 @@ enum class Feature {
|
||||
else -> generalGetString(R.string.voice_prohibited_in_this_chat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun enableGroupPrefDescription(enabled: GroupFeatureEnabled, canEdit: Boolean): String =
|
||||
if (canEdit) {
|
||||
when(this) {
|
||||
FullDelete -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_delete_messages)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_message_deletion)
|
||||
@Serializable
|
||||
enum class GroupFeature: Feature {
|
||||
@SerialName("directMessages") DirectMessages,
|
||||
@SerialName("fullDelete") FullDelete,
|
||||
@SerialName("voice") Voice;
|
||||
|
||||
override val text: String
|
||||
get() = when(this) {
|
||||
DirectMessages -> generalGetString(R.string.direct_messages)
|
||||
FullDelete -> generalGetString(R.string.full_deletion)
|
||||
Voice -> generalGetString(R.string.voice_messages)
|
||||
}
|
||||
|
||||
val icon: ImageVector
|
||||
get() = when(this) {
|
||||
DirectMessages -> Icons.Outlined.SwapHorizontalCircle
|
||||
FullDelete -> Icons.Outlined.DeleteForever
|
||||
Voice -> Icons.Outlined.KeyboardVoice
|
||||
}
|
||||
|
||||
override val iconFilled: ImageVector
|
||||
get() = when(this) {
|
||||
DirectMessages -> Icons.Filled.SwapHorizontalCircle
|
||||
FullDelete -> Icons.Filled.DeleteForever
|
||||
Voice -> Icons.Filled.KeyboardVoice
|
||||
}
|
||||
|
||||
fun enableDescription(enabled: GroupFeatureEnabled, canEdit: Boolean): String =
|
||||
if (canEdit) {
|
||||
when(this) {
|
||||
DirectMessages -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_direct_messages)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_direct_messages)
|
||||
}
|
||||
FullDelete -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_delete_messages)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_message_deletion)
|
||||
}
|
||||
Voice -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_send_voice)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_sending_voice)
|
||||
}
|
||||
}
|
||||
Voice -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_send_voice)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_sending_voice)
|
||||
} else {
|
||||
when(this) {
|
||||
DirectMessages -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_dms)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.direct_messages_are_prohibited_in_chat)
|
||||
}
|
||||
FullDelete -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_delete)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.message_deletion_prohibited_in_chat)
|
||||
}
|
||||
Voice -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_voice)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.voice_messages_are_prohibited)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
when(this) {
|
||||
FullDelete -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_delete)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.message_deletion_prohibited_in_chat)
|
||||
}
|
||||
Voice -> when(enabled) {
|
||||
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_voice)
|
||||
GroupFeatureEnabled.OFF -> generalGetString(R.string.voice_messages_are_prohibited)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@@ -2212,24 +2253,26 @@ enum class FeatureAllowed {
|
||||
|
||||
@Serializable
|
||||
data class FullGroupPreferences(
|
||||
val directMessages: GroupPreference,
|
||||
val fullDelete: GroupPreference,
|
||||
val voice: GroupPreference
|
||||
) {
|
||||
fun toGroupPreferences(): GroupPreferences =
|
||||
GroupPreferences(fullDelete = fullDelete, voice = voice)
|
||||
GroupPreferences(directMessages = directMessages, fullDelete = fullDelete, voice = voice)
|
||||
|
||||
companion object {
|
||||
val sampleData = FullGroupPreferences(fullDelete = GroupPreference(enable = GroupFeatureEnabled.OFF), voice = GroupPreference(enable = GroupFeatureEnabled.ON))
|
||||
val sampleData = FullGroupPreferences(directMessages = GroupPreference(GroupFeatureEnabled.OFF), fullDelete = GroupPreference(GroupFeatureEnabled.OFF), voice = GroupPreference(GroupFeatureEnabled.ON))
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class GroupPreferences(
|
||||
val directMessages: GroupPreference?,
|
||||
val fullDelete: GroupPreference?,
|
||||
val voice: GroupPreference?
|
||||
) {
|
||||
companion object {
|
||||
val sampleData = GroupPreferences(fullDelete = GroupPreference(enable = GroupFeatureEnabled.OFF), voice = GroupPreference(enable = GroupFeatureEnabled.ON))
|
||||
val sampleData = GroupPreferences(directMessages = GroupPreference(GroupFeatureEnabled.OFF), fullDelete = GroupPreference(GroupFeatureEnabled.OFF), voice = GroupPreference(GroupFeatureEnabled.ON))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ private fun ContactPreferencesLayout(
|
||||
// }
|
||||
// SectionSpacer()
|
||||
val allowVoice: MutableState<ContactFeatureAllowed> = remember(featuresAllowed) { mutableStateOf(featuresAllowed.voice) }
|
||||
FeatureSection(Feature.Voice, user.fullPreferences.voice.allow, contact.mergedPreferences.voice, allowVoice) {
|
||||
FeatureSection(ChatFeature.Voice, user.fullPreferences.voice.allow, contact.mergedPreferences.voice, allowVoice) {
|
||||
applyPrefs(featuresAllowed.copy(voice = it))
|
||||
}
|
||||
SectionSpacer()
|
||||
@@ -92,7 +92,7 @@ private fun ContactPreferencesLayout(
|
||||
|
||||
@Composable
|
||||
private fun FeatureSection(
|
||||
feature: Feature,
|
||||
feature: ChatFeature,
|
||||
userDefault: FeatureAllowed,
|
||||
pref: ContactUserPreference,
|
||||
allowFeature: State<ContactFeatureAllowed>,
|
||||
|
||||
+5
-3
@@ -133,10 +133,12 @@ fun GroupMemberInfoLayout(
|
||||
}
|
||||
SectionSpacer()
|
||||
|
||||
SectionView {
|
||||
OpenChatButton(openDirectChat)
|
||||
if (member.memberContactId != null && groupInfo.fullGroupPreferences.directMessages.enable == GroupFeatureEnabled.ON) {
|
||||
SectionView {
|
||||
OpenChatButton(openDirectChat)
|
||||
}
|
||||
SectionSpacer()
|
||||
}
|
||||
SectionSpacer()
|
||||
|
||||
SectionView(title = stringResource(R.string.member_info_section_title_member)) {
|
||||
InfoRow(stringResource(R.string.info_row_group), groupInfo.displayName)
|
||||
|
||||
+7
-3
@@ -62,13 +62,17 @@ private fun GroupPreferencesLayout(
|
||||
horizontalAlignment = Alignment.Start,
|
||||
) {
|
||||
AppBarTitle(stringResource(R.string.group_preferences))
|
||||
val allowDirectMessages = remember(preferences) { mutableStateOf(preferences.directMessages.enable) }
|
||||
FeatureSection(GroupFeature.DirectMessages, allowDirectMessages, groupInfo) {
|
||||
applyPrefs(preferences.copy(directMessages = GroupPreference(enable = it)))
|
||||
}
|
||||
// val allowFullDeletion = remember(preferences) { mutableStateOf(preferences.fullDelete.enable) }
|
||||
// FeatureSection(Feature.FullDelete, allowFullDeletion, groupInfo) {
|
||||
// applyPrefs(preferences.copy(fullDelete = GroupPreference(enable = it)))
|
||||
// }
|
||||
// SectionSpacer()
|
||||
val allowVoice = remember(preferences) { mutableStateOf(preferences.voice.enable) }
|
||||
FeatureSection(Feature.Voice, allowVoice, groupInfo) {
|
||||
FeatureSection(GroupFeature.Voice, allowVoice, groupInfo) {
|
||||
applyPrefs(preferences.copy(voice = GroupPreference(enable = it)))
|
||||
}
|
||||
if (groupInfo.canEdit) {
|
||||
@@ -83,7 +87,7 @@ private fun GroupPreferencesLayout(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FeatureSection(feature: Feature, enableFeature: State<GroupFeatureEnabled>, groupInfo: GroupInfo, onSelected: (GroupFeatureEnabled) -> Unit) {
|
||||
private fun FeatureSection(feature: GroupFeature, enableFeature: State<GroupFeatureEnabled>, groupInfo: GroupInfo, onSelected: (GroupFeatureEnabled) -> Unit) {
|
||||
SectionView {
|
||||
if (groupInfo.canEdit) {
|
||||
SectionItemView {
|
||||
@@ -102,7 +106,7 @@ private fun FeatureSection(feature: Feature, enableFeature: State<GroupFeatureEn
|
||||
)
|
||||
}
|
||||
}
|
||||
SectionTextFooter(feature.enableGroupPrefDescription(enableFeature.value, groupInfo.canEdit))
|
||||
SectionTextFooter(feature.enableDescription(enableFeature.value, groupInfo.canEdit))
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -172,8 +172,8 @@ fun ChatItemView(
|
||||
is CIContent.SndConnEventContent -> CIEventView(cItem)
|
||||
is CIContent.RcvChatFeature -> CIChatFeatureView(cItem, c.feature, c.enabled.iconColor)
|
||||
is CIContent.SndChatFeature -> CIChatFeatureView(cItem, c.feature, c.enabled.iconColor)
|
||||
is CIContent.RcvGroupFeature -> CIChatFeatureView(cItem, c.feature, c.preference.enable.iconColor)
|
||||
is CIContent.SndGroupFeature -> CIChatFeatureView(cItem, c.feature, c.preference.enable.iconColor)
|
||||
is CIContent.RcvGroupFeature -> CIChatFeatureView(cItem, c.groupFeature, c.preference.enable.iconColor)
|
||||
is CIContent.SndGroupFeature -> CIChatFeatureView(cItem, c.groupFeature, c.preference.enable.iconColor)
|
||||
is CIContent.RcvChatFeatureRejected -> CIChatFeatureView(cItem, c.feature, Color.Red)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ private fun PreferencesLayout(
|
||||
// }
|
||||
// SectionSpacer()
|
||||
val allowVoice = remember(preferences) { mutableStateOf(preferences.voice.allow) }
|
||||
FeatureSection(Feature.Voice, allowVoice) {
|
||||
FeatureSection(ChatFeature.Voice, allowVoice) {
|
||||
applyPrefs(preferences.copy(voice = ChatPreference(allow = it)))
|
||||
}
|
||||
SectionSpacer()
|
||||
@@ -80,7 +80,7 @@ private fun PreferencesLayout(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FeatureSection(feature: Feature, allowFeature: State<FeatureAllowed>, onSelected: (FeatureAllowed) -> Unit) {
|
||||
private fun FeatureSection(feature: ChatFeature, allowFeature: State<FeatureAllowed>, onSelected: (FeatureAllowed) -> Unit) {
|
||||
SectionView {
|
||||
SectionItemView {
|
||||
ExposedDropDownSettingRow(
|
||||
|
||||
@@ -947,6 +947,7 @@
|
||||
<string name="contact_preferences">Contact preferences</string>
|
||||
<string name="group_preferences">Group preferences</string>
|
||||
<string name="your_preferences">Your preferences</string>
|
||||
<string name="direct_messages">Direct messages</string>
|
||||
<string name="full_deletion">Full deletion</string>
|
||||
<string name="voice_messages">Voice messages</string>
|
||||
<string name="feature_enabled">enabled</string>
|
||||
@@ -968,13 +969,17 @@
|
||||
<string name="only_you_can_send_voice">Only you can send voice messages.</string>
|
||||
<string name="only_your_contact_can_send_voice">Only your contact can send voice messages.</string>
|
||||
<string name="voice_prohibited_in_this_chat">Voice messages are prohibited in this chat.</string>
|
||||
<string name="allow_direct_messages">Allow sending direct messages to members.</string>
|
||||
<string name="prohibit_direct_messages">Prohibit sending direct messages to members.</string>
|
||||
<string name="allow_to_delete_messages">Allow to irreversibly delete sent messages.</string>
|
||||
<string name="prohibit_message_deletion">Prohibit irreversible message deletion.</string>
|
||||
<string name="allow_to_send_voice">Allow to send voice messages.</string>
|
||||
<string name="prohibit_sending_voice">Prohibit sending voice messages.</string>
|
||||
<string name="group_members_can_send_dms">Group members can send direct messages.</string>
|
||||
<string name="direct_messages_are_prohibited_in_chat">Direct messages between members are prohibited in this group.</string>
|
||||
<string name="group_members_can_delete">Group members can irreversibly delete sent messages.</string>
|
||||
<string name="message_deletion_prohibited_in_chat">Irreversible message deletion is prohibited in this chat.</string>
|
||||
<string name="message_deletion_prohibited_in_chat">Irreversible message deletion is prohibited in this group.</string>
|
||||
<string name="group_members_can_send_voice">Group members can send voice messages.</string>
|
||||
<string name="voice_messages_are_prohibited">Voice messages are prohibited in this chat.</string>
|
||||
<string name="voice_messages_are_prohibited">Voice messages are prohibited in this group.</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -29,6 +29,6 @@ struct CIChatFeatureView: View {
|
||||
struct CIChatFeatureView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let enabled = FeatureEnabled(forUser: false, forContact: false)
|
||||
CIChatFeatureView(chatItem: ChatItem.getChatFeatureSample(.fullDelete, enabled), feature: .fullDelete, iconColor: enabled.iconColor)
|
||||
CIChatFeatureView(chatItem: ChatItem.getChatFeatureSample(.fullDelete, enabled), feature: ChatFeature.fullDelete, iconColor: enabled.iconColor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ struct ChatItemView: View {
|
||||
case let .rcvGroupFeature(feature, preference): chatFeatureView(feature, preference.enable.iconColor)
|
||||
case let .sndGroupFeature(feature, preference): chatFeatureView(feature, preference.enable.iconColor)
|
||||
case let .rcvChatFeatureRejected(feature): chatFeatureView(feature, .red)
|
||||
case let .rcvGroupFeatureRejected(feature): chatFeatureView(feature, .red)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ struct ContactPreferencesView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func featureSection(_ feature: Feature, _ userDefault: FeatureAllowed, _ pref: ContactUserPreference, _ allowFeature: Binding<ContactFeatureAllowed>) -> some View {
|
||||
private func featureSection(_ feature: ChatFeature, _ userDefault: FeatureAllowed, _ pref: ContactUserPreference, _ allowFeature: Binding<ContactFeatureAllowed>) -> some View {
|
||||
let enabled = FeatureEnabled.enabled(
|
||||
user: Preference(allow: allowFeature.wrappedValue.allowed),
|
||||
contact: pref.contactPreference
|
||||
|
||||
@@ -42,7 +42,7 @@ struct GroupMemberInfoView: View {
|
||||
groupMemberInfoHeader(member)
|
||||
.listRowBackground(Color.clear)
|
||||
|
||||
if let contactId = member.memberContactId {
|
||||
if let contactId = member.memberContactId, groupInfo.fullGroupPreferences.directMessages.enable == .on {
|
||||
Section {
|
||||
openDirectChatButton(contactId)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ struct GroupPreferencesView: View {
|
||||
VStack {
|
||||
List {
|
||||
// featureSection(.fullDelete, $preferences.fullDelete.enable)
|
||||
featureSection(.directMessages, $preferences.directMessages.enable)
|
||||
featureSection(.voice, $preferences.voice.enable)
|
||||
|
||||
if groupInfo.canEdit {
|
||||
@@ -32,7 +33,7 @@ struct GroupPreferencesView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func featureSection(_ feature: Feature, _ enableFeature: Binding<GroupFeatureEnabled>) -> some View {
|
||||
private func featureSection(_ feature: GroupFeature, _ enableFeature: Binding<GroupFeatureEnabled>) -> some View {
|
||||
Section {
|
||||
if (groupInfo.canEdit) {
|
||||
settingsRow(feature.icon) {
|
||||
@@ -50,7 +51,7 @@ struct GroupPreferencesView: View {
|
||||
}
|
||||
}
|
||||
} footer: {
|
||||
Text(feature.enableGroupPrefDescription(enableFeature.wrappedValue, groupInfo.canEdit))
|
||||
Text(feature.enableDescription(enableFeature.wrappedValue, groupInfo.canEdit))
|
||||
.frame(height: 36, alignment: .topLeading)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ struct PreferencesView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func featureSection(_ feature: Feature, _ allowFeature: Binding<FeatureAllowed>) -> some View {
|
||||
private func featureSection(_ feature: ChatFeature, _ allowFeature: Binding<FeatureAllowed>) -> some View {
|
||||
Section {
|
||||
settingsRow(feature.icon) {
|
||||
Picker(feature.text, selection: allowFeature) {
|
||||
|
||||
@@ -245,11 +245,15 @@ public enum ContactUserPref: Decodable {
|
||||
}
|
||||
}
|
||||
|
||||
public enum Feature: String, Decodable {
|
||||
public protocol Feature {
|
||||
var iconFilled: String { get }
|
||||
}
|
||||
|
||||
public enum ChatFeature: String, Decodable, Feature {
|
||||
case fullDelete
|
||||
case voice
|
||||
|
||||
public var values: [Feature] { [.fullDelete, .voice] }
|
||||
public var values: [ChatFeature] { [.fullDelete, .voice] }
|
||||
|
||||
public var id: Self { self }
|
||||
|
||||
@@ -311,10 +315,49 @@ public enum Feature: String, Decodable {
|
||||
: "Voice messages are prohibited in this chat."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func enableGroupPrefDescription(_ enabled: GroupFeatureEnabled, _ canEdit: Bool) -> LocalizedStringKey {
|
||||
public enum GroupFeature: String, Decodable, Feature {
|
||||
case fullDelete
|
||||
case voice
|
||||
case directMessages
|
||||
|
||||
public var values: [GroupFeature] { [.directMessages, .fullDelete, .voice] }
|
||||
|
||||
public var id: Self { self }
|
||||
|
||||
public var text: String {
|
||||
switch self {
|
||||
case .directMessages: return NSLocalizedString("Direct messages", comment: "chat feature")
|
||||
case .fullDelete: return NSLocalizedString("Full deletion", comment: "chat feature")
|
||||
case .voice: return NSLocalizedString("Voice messages", comment: "chat feature")
|
||||
}
|
||||
}
|
||||
|
||||
public var icon: String {
|
||||
switch self {
|
||||
case .directMessages: return "arrow.left.and.right.circle"
|
||||
case .fullDelete: return "trash.slash"
|
||||
case .voice: return "mic"
|
||||
}
|
||||
}
|
||||
|
||||
public var iconFilled: String {
|
||||
switch self {
|
||||
case .directMessages: return "arrow.left.and.right.circle.fill"
|
||||
case .fullDelete: return "trash.slash.fill"
|
||||
case .voice: return "mic.fill"
|
||||
}
|
||||
}
|
||||
|
||||
public func enableDescription(_ enabled: GroupFeatureEnabled, _ canEdit: Bool) -> LocalizedStringKey {
|
||||
if canEdit {
|
||||
switch self {
|
||||
case .directMessages:
|
||||
switch enabled {
|
||||
case .on: return "Allow sending direct messages to members."
|
||||
case .off: return "Prohibit sending direct messages to members."
|
||||
}
|
||||
case .fullDelete:
|
||||
switch enabled {
|
||||
case .on: return "Allow to irreversibly delete sent messages."
|
||||
@@ -328,15 +371,20 @@ public enum Feature: String, Decodable {
|
||||
}
|
||||
} else {
|
||||
switch self {
|
||||
case .directMessages:
|
||||
switch enabled {
|
||||
case .on: return "Group members can send direct messages."
|
||||
case .off: return "Direct messages between members are prohibited in this group."
|
||||
}
|
||||
case .fullDelete:
|
||||
switch enabled {
|
||||
case .on: return "Group members can irreversibly delete sent messages."
|
||||
case .off: return "Irreversible message deletion is prohibited in this chat."
|
||||
case .off: return "Irreversible message deletion is prohibited in this group."
|
||||
}
|
||||
case .voice:
|
||||
switch enabled {
|
||||
case .on: return "Group members can send voice messages."
|
||||
case .off: return "Voice messages are prohibited in this chat."
|
||||
case .off: return "Voice messages are prohibited in this group."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -443,31 +491,35 @@ public enum FeatureAllowed: String, Codable, Identifiable {
|
||||
}
|
||||
|
||||
public struct FullGroupPreferences: Decodable, Equatable {
|
||||
public var directMessages: GroupPreference
|
||||
public var fullDelete: GroupPreference
|
||||
public var voice: GroupPreference
|
||||
|
||||
public init(fullDelete: GroupPreference, voice: GroupPreference) {
|
||||
public init(directMessages: GroupPreference, fullDelete: GroupPreference, voice: GroupPreference) {
|
||||
self.directMessages = directMessages
|
||||
self.fullDelete = fullDelete
|
||||
self.voice = voice
|
||||
}
|
||||
|
||||
public static let sampleData = FullGroupPreferences(fullDelete: GroupPreference(enable: .off), voice: GroupPreference(enable: .on))
|
||||
public static let sampleData = FullGroupPreferences(directMessages: GroupPreference(enable: .off), fullDelete: GroupPreference(enable: .off), voice: GroupPreference(enable: .on))
|
||||
}
|
||||
|
||||
public struct GroupPreferences: Codable {
|
||||
public var directMessages: GroupPreference?
|
||||
public var fullDelete: GroupPreference?
|
||||
public var voice: GroupPreference?
|
||||
|
||||
public init(fullDelete: GroupPreference?, voice: GroupPreference?) {
|
||||
public init(directMessages: GroupPreference?, fullDelete: GroupPreference?, voice: GroupPreference?) {
|
||||
self.directMessages = directMessages
|
||||
self.fullDelete = fullDelete
|
||||
self.voice = voice
|
||||
}
|
||||
|
||||
public static let sampleData = GroupPreferences(fullDelete: GroupPreference(enable: .off), voice: GroupPreference(enable: .on))
|
||||
public static let sampleData = GroupPreferences(directMessages: GroupPreference(enable: .off), fullDelete: GroupPreference(enable: .off), voice: GroupPreference(enable: .on))
|
||||
}
|
||||
|
||||
public func toGroupPreferences(_ fullPreferences: FullGroupPreferences) -> GroupPreferences {
|
||||
GroupPreferences(fullDelete: fullPreferences.fullDelete, voice: fullPreferences.voice)
|
||||
GroupPreferences(directMessages: fullPreferences.directMessages, fullDelete: fullPreferences.fullDelete, voice: fullPreferences.voice)
|
||||
}
|
||||
|
||||
public struct GroupPreference: Codable, Equatable {
|
||||
@@ -1371,6 +1423,7 @@ public struct ChatItem: Identifiable, Decodable {
|
||||
case .rcvGroupFeature: return false
|
||||
case .sndGroupFeature: return showNtfDir
|
||||
case .rcvChatFeatureRejected: return showNtfDir
|
||||
case .rcvGroupFeatureRejected: return showNtfDir
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1462,7 +1515,7 @@ public struct ChatItem: Identifiable, Decodable {
|
||||
)
|
||||
}
|
||||
|
||||
public static func getChatFeatureSample(_ feature: Feature, _ enabled: FeatureEnabled) -> ChatItem {
|
||||
public static func getChatFeatureSample(_ feature: ChatFeature, _ enabled: FeatureEnabled) -> ChatItem {
|
||||
let content = CIContent.rcvChatFeature(feature: feature, enabled: enabled)
|
||||
return ChatItem(
|
||||
chatDir: .directRcv,
|
||||
@@ -1573,11 +1626,12 @@ public enum CIContent: Decodable, ItemContent {
|
||||
case sndGroupEvent(sndGroupEvent: SndGroupEvent)
|
||||
case rcvConnEvent(rcvConnEvent: RcvConnEvent)
|
||||
case sndConnEvent(sndConnEvent: SndConnEvent)
|
||||
case rcvChatFeature(feature: Feature, enabled: FeatureEnabled)
|
||||
case sndChatFeature(feature: Feature, enabled: FeatureEnabled)
|
||||
case rcvGroupFeature(feature: Feature, preference: GroupPreference)
|
||||
case sndGroupFeature(feature: Feature, preference: GroupPreference)
|
||||
case rcvChatFeatureRejected(feature: Feature)
|
||||
case rcvChatFeature(feature: ChatFeature, enabled: FeatureEnabled)
|
||||
case sndChatFeature(feature: ChatFeature, enabled: FeatureEnabled)
|
||||
case rcvGroupFeature(groupFeature: GroupFeature, preference: GroupPreference)
|
||||
case sndGroupFeature(groupFeature: GroupFeature, preference: GroupPreference)
|
||||
case rcvChatFeatureRejected(feature: ChatFeature)
|
||||
case rcvGroupFeatureRejected(groupFeature: GroupFeature)
|
||||
|
||||
public var text: String {
|
||||
get {
|
||||
@@ -1600,6 +1654,7 @@ public enum CIContent: Decodable, ItemContent {
|
||||
case let .rcvGroupFeature(feature, preference): return "\(feature.text): \(preference.enable.text)"
|
||||
case let .sndGroupFeature(feature, preference): return "\(feature.text): \(preference.enable.text)"
|
||||
case let .rcvChatFeatureRejected(feature): return String.localizedStringWithFormat("%@: received, prohibited", feature.text)
|
||||
case let .rcvGroupFeatureRejected(groupFeature): return String.localizedStringWithFormat("%@: received, prohibited", groupFeature.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user