From 044c7a8191e622cd3359797d36ff994c853ba7a8 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Wed, 14 Dec 2022 13:53:31 +0000 Subject: [PATCH] mobile: update types for timed messages preference (#1574) --- .../java/chat/simplex/app/model/SimpleXAPI.kt | 63 ++++++++++- .../app/src/main/res/values/strings.xml | 12 +++ apps/ios/SimpleXChat/ChatTypes.swift | 100 +++++++++++++++--- 3 files changed, 159 insertions(+), 16 deletions(-) diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt index 440cfb4ebf..ce5448c5c3 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt @@ -1983,11 +1983,16 @@ data class FullChatPreferences( @Serializable data class ChatPreferences( + val timedMessages: ChatPreference? = null, val fullDelete: ChatPreference? = null, val voice: ChatPreference? = null, ) { companion object { - val sampleData = ChatPreferences(fullDelete = ChatPreference(allow = FeatureAllowed.NO), voice = ChatPreference(allow = FeatureAllowed.YES)) + val sampleData = ChatPreferences( + timedMessages = ChatPreference(allow = FeatureAllowed.NO), + fullDelete = ChatPreference(allow = FeatureAllowed.NO), + voice = ChatPreference(allow = FeatureAllowed.YES) + ) } } @@ -1998,16 +2003,23 @@ data class ChatPreference( @Serializable data class ContactUserPreferences( + val timedMessages: ContactUserPreference, val fullDelete: ContactUserPreference, val voice: ContactUserPreference, ) { fun toPreferences(): ChatPreferences = ChatPreferences( + timedMessages = timedMessages.userPreference.pref, fullDelete = fullDelete.userPreference.pref, voice = voice.userPreference.pref ) companion object { val sampleData = ContactUserPreferences( + timedMessages = ContactUserPreference( + enabled = FeatureEnabled(forUser = false, forContact = false), + userPreference = ContactUserPref.User(preference = ChatPreference(allow = FeatureAllowed.NO)), + contactPreference = ChatPreference(allow = FeatureAllowed.NO) + ), fullDelete = ContactUserPreference( enabled = FeatureEnabled(forUser = false, forContact = false), userPreference = ContactUserPref.User(preference = ChatPreference(allow = FeatureAllowed.NO)), @@ -2079,29 +2091,38 @@ interface Feature { @Serializable enum class ChatFeature: Feature { + @SerialName("timedMessages") TimedMessages, @SerialName("fullDelete") FullDelete, @SerialName("voice") Voice; override val text: String get() = when(this) { + TimedMessages -> generalGetString(R.string.timed_messages) FullDelete -> generalGetString(R.string.full_deletion) Voice -> generalGetString(R.string.voice_messages) } val icon: ImageVector get() = when(this) { + TimedMessages -> Icons.Outlined.Timer FullDelete -> Icons.Outlined.DeleteForever Voice -> Icons.Outlined.KeyboardVoice } override val iconFilled: ImageVector get() = when(this) { + TimedMessages -> Icons.Filled.Timer FullDelete -> Icons.Filled.DeleteForever Voice -> Icons.Filled.KeyboardVoice } fun allowDescription(allowed: FeatureAllowed): String = when (this) { + TimedMessages -> when (allowed) { + FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_to_send_disappearing_messages) + FeatureAllowed.YES -> generalGetString(R.string.allow_disappearing_messages_only_if) + FeatureAllowed.NO -> generalGetString(R.string.prohibit_sending_disappearing_messages) + } FullDelete -> when (allowed) { FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_irreversibly_delete) FeatureAllowed.YES -> generalGetString(R.string.allow_irreversible_message_deletion_only_if) @@ -2116,6 +2137,12 @@ enum class ChatFeature: Feature { fun enabledDescription(enabled: FeatureEnabled): String = when (this) { + TimedMessages -> when { + enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contact_can_send_disappearing) + enabled.forUser -> generalGetString(R.string.only_you_can_send_disappearing) + enabled.forContact -> generalGetString(R.string.only_your_contact_can_send_disappearing) + else -> generalGetString(R.string.disappearing_prohibited_in_this_chat) + } FullDelete -> when { enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contacts_can_delete) enabled.forUser -> generalGetString(R.string.only_you_can_delete_messages) @@ -2133,12 +2160,14 @@ enum class ChatFeature: Feature { @Serializable enum class GroupFeature: Feature { + @SerialName("timedMessages") TimedMessages, @SerialName("directMessages") DirectMessages, @SerialName("fullDelete") FullDelete, @SerialName("voice") Voice; override val text: String get() = when(this) { + TimedMessages -> generalGetString(R.string.timed_messages) DirectMessages -> generalGetString(R.string.direct_messages) FullDelete -> generalGetString(R.string.full_deletion) Voice -> generalGetString(R.string.voice_messages) @@ -2146,6 +2175,7 @@ enum class GroupFeature: Feature { val icon: ImageVector get() = when(this) { + TimedMessages -> Icons.Outlined.Timer DirectMessages -> Icons.Outlined.SwapHorizontalCircle FullDelete -> Icons.Outlined.DeleteForever Voice -> Icons.Outlined.KeyboardVoice @@ -2153,6 +2183,7 @@ enum class GroupFeature: Feature { override val iconFilled: ImageVector get() = when(this) { + TimedMessages -> Icons.Filled.Timer DirectMessages -> Icons.Filled.SwapHorizontalCircle FullDelete -> Icons.Filled.DeleteForever Voice -> Icons.Filled.KeyboardVoice @@ -2161,6 +2192,10 @@ enum class GroupFeature: Feature { fun enableDescription(enabled: GroupFeatureEnabled, canEdit: Boolean): String = if (canEdit) { when(this) { + TimedMessages -> when(enabled) { + GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_send_disappearing) + GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_sending_disappearing) + } DirectMessages -> when(enabled) { GroupFeatureEnabled.ON -> generalGetString(R.string.allow_direct_messages) GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_direct_messages) @@ -2176,6 +2211,10 @@ enum class GroupFeature: Feature { } } else { when(this) { + TimedMessages -> when(enabled) { + GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_disappearing) + GroupFeatureEnabled.OFF -> generalGetString(R.string.disappearing_messages_are_prohibited) + } DirectMessages -> when(enabled) { GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_dms) GroupFeatureEnabled.OFF -> generalGetString(R.string.direct_messages_are_prohibited_in_chat) @@ -2221,11 +2260,13 @@ sealed class ContactFeatureAllowed { @Serializable data class ContactFeaturesAllowed( + val timedMessages: ContactFeatureAllowed, val fullDelete: ContactFeatureAllowed, val voice: ContactFeatureAllowed ) { companion object { val sampleData = ContactFeaturesAllowed( + timedMessages = ContactFeatureAllowed.UserDefault(FeatureAllowed.NO), fullDelete = ContactFeatureAllowed.UserDefault(FeatureAllowed.NO), voice = ContactFeatureAllowed.UserDefault(FeatureAllowed.YES) ) @@ -2234,6 +2275,7 @@ data class ContactFeaturesAllowed( fun contactUserPrefsToFeaturesAllowed(contactUserPreferences: ContactUserPreferences): ContactFeaturesAllowed = ContactFeaturesAllowed( + timedMessages = contactUserPrefToFeatureAllowed(contactUserPreferences.timedMessages), fullDelete = contactUserPrefToFeatureAllowed(contactUserPreferences.fullDelete), voice = contactUserPrefToFeatureAllowed(contactUserPreferences.voice) ) @@ -2250,6 +2292,7 @@ fun contactUserPrefToFeatureAllowed(contactUserPreference: ContactUserPreference fun contactFeaturesAllowedToPrefs(contactFeaturesAllowed: ContactFeaturesAllowed): ChatPreferences = ChatPreferences( + timedMessages = contactFeatureAllowedToPref(contactFeaturesAllowed.timedMessages), fullDelete = contactFeatureAllowedToPref(contactFeaturesAllowed.fullDelete), voice = contactFeatureAllowedToPref(contactFeaturesAllowed.voice) ) @@ -2278,26 +2321,38 @@ enum class FeatureAllowed { @Serializable data class FullGroupPreferences( + val timedMessages: GroupPreference, val directMessages: GroupPreference, val fullDelete: GroupPreference, val voice: GroupPreference ) { fun toGroupPreferences(): GroupPreferences = - GroupPreferences(directMessages = directMessages, fullDelete = fullDelete, voice = voice) + GroupPreferences(timedMessages = timedMessages, directMessages = directMessages, fullDelete = fullDelete, voice = voice) companion object { - val sampleData = FullGroupPreferences(directMessages = GroupPreference(GroupFeatureEnabled.OFF), fullDelete = GroupPreference(GroupFeatureEnabled.OFF), voice = GroupPreference(GroupFeatureEnabled.ON)) + val sampleData = FullGroupPreferences( + timedMessages = GroupPreference(GroupFeatureEnabled.OFF), + directMessages = GroupPreference(GroupFeatureEnabled.OFF), + fullDelete = GroupPreference(GroupFeatureEnabled.OFF), + voice = GroupPreference(GroupFeatureEnabled.ON) + ) } } @Serializable data class GroupPreferences( + val timedMessages: GroupPreference?, val directMessages: GroupPreference?, val fullDelete: GroupPreference?, val voice: GroupPreference? ) { companion object { - val sampleData = GroupPreferences(directMessages = GroupPreference(GroupFeatureEnabled.OFF), fullDelete = GroupPreference(GroupFeatureEnabled.OFF), voice = GroupPreference(GroupFeatureEnabled.ON)) + val sampleData = GroupPreferences( + timedMessages = GroupPreference(GroupFeatureEnabled.OFF), + directMessages = GroupPreference(GroupFeatureEnabled.OFF), + fullDelete = GroupPreference(GroupFeatureEnabled.OFF), + voice = GroupPreference(GroupFeatureEnabled.ON) + ) } } diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index bb3bb545ca..c227420408 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -968,6 +968,7 @@ Group preferences Set group preferences Your preferences + Disappearing messages Direct messages Delete for everyone Voice messages @@ -976,12 +977,19 @@ enabled for contact off received, prohibited + Allow your contacts to send disappearing messages. + Allow disappearing messages only if your contact allows them. + Prohibit sending disappearing messages. Allow your contacts to irreversibly delete sent messages. Allow irreversible message deletion only if your contact allows it to you. Contacts can mark messages for deletion; you will be able to view them. Allow your contacts to send voice messages. Allow voice messages only if your contact allows them. Prohibit sending voice messages. + Both you and your contact can send disappearing messages. + Only you can send disappearing messages. + Only your contact can send disappearing messages. + Disappearing messages are prohibited in this chat. Both you and your contact can irreversibly delete sent messages. Only you can irreversibly delete messages (your contact can mark them for deletion). Only your contact can irreversibly delete messages (you can mark them for deletion). @@ -990,12 +998,16 @@ Only you can send voice messages. Only your contact can send voice messages. Voice messages are prohibited in this chat. + Allow to send disappearing messages. + Prohibit sending disappearing messages. Allow sending direct messages to members. Prohibit sending direct messages to members. Allow to irreversibly delete sent messages. Prohibit irreversible message deletion. Allow to send voice messages. Prohibit sending voice messages. + Group members can send disappearing messages. + Disappearing messages are prohibited in this group. Group members can send direct messages. Direct messages between members are prohibited in this group. Group members can irreversibly delete sent messages. diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index 3eb258be81..4c53bf7359 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -125,35 +125,48 @@ extension NamedChat { public typealias ChatId = String public struct FullPreferences: Decodable, Equatable { + public var timedMessages: Preference public var fullDelete: Preference public var voice: Preference - public init(fullDelete: Preference, voice: Preference) { + public init(timedMessages: Preference, fullDelete: Preference, voice: Preference) { + self.timedMessages = timedMessages self.fullDelete = fullDelete self.voice = voice } - public static let sampleData = FullPreferences(fullDelete: Preference(allow: .no), voice: Preference(allow: .yes)) + public static let sampleData = FullPreferences( + timedMessages: Preference(allow: .no), + fullDelete: Preference(allow: .no), + voice: Preference(allow: .yes) + ) } public struct Preferences: Codable { + public var timedMessages: Preference? public var fullDelete: Preference? public var voice: Preference? - public init(fullDelete: Preference?, voice: Preference?) { + public init(timedMessages: Preference?, fullDelete: Preference?, voice: Preference?) { + self.timedMessages = timedMessages self.fullDelete = fullDelete self.voice = voice } - public static let sampleData = Preferences(fullDelete: Preference(allow: .no), voice: Preference(allow: .yes)) + public static let sampleData = Preferences(timedMessages: Preference(allow: .no), fullDelete: Preference(allow: .no), voice: Preference(allow: .yes)) } public func fullPreferencesToPreferences(_ fullPreferences: FullPreferences) -> Preferences { - Preferences(fullDelete: fullPreferences.fullDelete, voice: fullPreferences.voice) + Preferences( + timedMessages: fullPreferences.timedMessages, + fullDelete: fullPreferences.fullDelete, + voice: fullPreferences.voice + ) } public func contactUserPreferencesToPreferences(_ contactUserPreferences: ContactUserPreferences) -> Preferences { Preferences( + timedMessages: contactUserPreferences.timedMessages.userPreference.preference, fullDelete: contactUserPreferences.fullDelete.userPreference.preference, voice: contactUserPreferences.voice.userPreference.preference ) @@ -168,15 +181,22 @@ public struct Preference: Codable, Equatable { } public struct ContactUserPreferences: Decodable { + public var timedMessages: ContactUserPreference public var fullDelete: ContactUserPreference public var voice: ContactUserPreference - public init(fullDelete: ContactUserPreference, voice: ContactUserPreference) { + public init(timedMessages: ContactUserPreference, fullDelete: ContactUserPreference, voice: ContactUserPreference) { + self.timedMessages = timedMessages self.fullDelete = fullDelete self.voice = voice } public static let sampleData = ContactUserPreferences( + timedMessages: ContactUserPreference( + enabled: FeatureEnabled(forUser: false, forContact: false), + userPreference: .user(preference: Preference(allow: .no)), + contactPreference: Preference(allow: .no) + ), fullDelete: ContactUserPreference( enabled: FeatureEnabled(forUser: false, forContact: false), userPreference: .user(preference: Preference(allow: .no)), @@ -250,6 +270,7 @@ public protocol Feature { } public enum ChatFeature: String, Decodable, Feature { + case timedMessages case fullDelete case voice @@ -259,6 +280,7 @@ public enum ChatFeature: String, Decodable, Feature { public var text: String { switch self { + case .timedMessages: return NSLocalizedString("Disappearing messages", comment: "chat feature") case .fullDelete: return NSLocalizedString("Delete for everyone", comment: "chat feature") case .voice: return NSLocalizedString("Voice messages", comment: "chat feature") } @@ -266,6 +288,7 @@ public enum ChatFeature: String, Decodable, Feature { public var icon: String { switch self { + case .timedMessages: return "timer" case .fullDelete: return "trash.slash" case .voice: return "mic" } @@ -273,6 +296,7 @@ public enum ChatFeature: String, Decodable, Feature { public var iconFilled: String { switch self { + case .timedMessages: return "timer" case .fullDelete: return "trash.slash.fill" case .voice: return "mic.fill" } @@ -280,6 +304,12 @@ public enum ChatFeature: String, Decodable, Feature { public func allowDescription(_ allowed: FeatureAllowed) -> LocalizedStringKey { switch self { + case .timedMessages: + switch allowed { + case .always: return "Allow your contacts to send disappearing messages." + case .yes: return "Allow disappearing messages only if your contact allows it to you." + case .no: return "Prohibit sending disappearing messages." + } case .fullDelete: switch allowed { case .always: return "Allow your contacts to irreversibly delete sent messages." @@ -297,6 +327,14 @@ public enum ChatFeature: String, Decodable, Feature { public func enabledDescription(_ enabled: FeatureEnabled) -> LocalizedStringKey { switch self { + case .timedMessages: + return enabled.forUser && enabled.forContact + ? "Both you and your contact can send disappearing messages." + : enabled.forUser + ? "Only you can send disappearing messages." + : enabled.forContact + ? "Only your contact can send disappearing messages." + : "Disappearing messages are prohibited in this chat." case .fullDelete: return enabled.forUser && enabled.forContact ? "Both you and your contact can irreversibly delete sent messages." @@ -318,6 +356,7 @@ public enum ChatFeature: String, Decodable, Feature { } public enum GroupFeature: String, Decodable, Feature { + case timedMessages case fullDelete case voice case directMessages @@ -328,6 +367,7 @@ public enum GroupFeature: String, Decodable, Feature { public var text: String { switch self { + case .timedMessages: return NSLocalizedString("Disappearing messages", comment: "chat feature") case .directMessages: return NSLocalizedString("Direct messages", comment: "chat feature") case .fullDelete: return NSLocalizedString("Delete for everyone", comment: "chat feature") case .voice: return NSLocalizedString("Voice messages", comment: "chat feature") @@ -336,6 +376,7 @@ public enum GroupFeature: String, Decodable, Feature { public var icon: String { switch self { + case .timedMessages: return "timer" case .directMessages: return "arrow.left.and.right.circle" case .fullDelete: return "trash.slash" case .voice: return "mic" @@ -344,6 +385,7 @@ public enum GroupFeature: String, Decodable, Feature { public var iconFilled: String { switch self { + case .timedMessages: return "timer" case .directMessages: return "arrow.left.and.right.circle.fill" case .fullDelete: return "trash.slash.fill" case .voice: return "mic.fill" @@ -353,6 +395,11 @@ public enum GroupFeature: String, Decodable, Feature { public func enableDescription(_ enabled: GroupFeatureEnabled, _ canEdit: Bool) -> LocalizedStringKey { if canEdit { switch self { + case .timedMessages: + switch enabled { + case .on: return "Allow sending disappearing messages." + case .off: return "Prohibit sending disappearing messages." + } case .directMessages: switch enabled { case .on: return "Allow sending direct messages to members." @@ -371,6 +418,11 @@ public enum GroupFeature: String, Decodable, Feature { } } else { switch self { + case .timedMessages: + switch enabled { + case .on: return "Group members can send disappearing messages." + case .off: return "Disappearing messages are prohibited in this group." + } case .directMessages: switch enabled { case .on: return "Group members can send direct messages." @@ -423,15 +475,18 @@ public enum ContactFeatureAllowed: Identifiable, Hashable { } public struct ContactFeaturesAllowed: Equatable { + public var timedMessages: ContactFeatureAllowed public var fullDelete: ContactFeatureAllowed public var voice: ContactFeatureAllowed - public init(fullDelete: ContactFeatureAllowed, voice: ContactFeatureAllowed) { + public init(timedMessages: ContactFeatureAllowed, fullDelete: ContactFeatureAllowed, voice: ContactFeatureAllowed) { + self.timedMessages = timedMessages self.fullDelete = fullDelete self.voice = voice } public static let sampleData = ContactFeaturesAllowed( + timedMessages: ContactFeatureAllowed.userDefault(.no), fullDelete: ContactFeatureAllowed.userDefault(.no), voice: ContactFeatureAllowed.userDefault(.yes) ) @@ -439,6 +494,7 @@ public struct ContactFeaturesAllowed: Equatable { public func contactUserPrefsToFeaturesAllowed(_ contactUserPreferences: ContactUserPreferences) -> ContactFeaturesAllowed { ContactFeaturesAllowed( + timedMessages: contactUserPrefToFeatureAllowed(contactUserPreferences.timedMessages), fullDelete: contactUserPrefToFeatureAllowed(contactUserPreferences.fullDelete), voice: contactUserPrefToFeatureAllowed(contactUserPreferences.voice) ) @@ -458,6 +514,7 @@ public func contactUserPrefToFeatureAllowed(_ contactUserPreference: ContactUser public func contactFeaturesAllowedToPrefs(_ contactFeaturesAllowed: ContactFeaturesAllowed) -> Preferences { Preferences( + timedMessages: contactFeatureAllowedToPref(contactFeaturesAllowed.timedMessages), fullDelete: contactFeatureAllowedToPref(contactFeaturesAllowed.fullDelete), voice: contactFeatureAllowedToPref(contactFeaturesAllowed.voice) ) @@ -491,35 +548,54 @@ public enum FeatureAllowed: String, Codable, Identifiable { } public struct FullGroupPreferences: Decodable, Equatable { + public var timedMessages: GroupPreference public var directMessages: GroupPreference public var fullDelete: GroupPreference public var voice: GroupPreference - public init(directMessages: GroupPreference, fullDelete: GroupPreference, voice: GroupPreference) { + public init(timedMessages: GroupPreference, directMessages: GroupPreference, fullDelete: GroupPreference, voice: GroupPreference) { + self.timedMessages = timedMessages self.directMessages = directMessages self.fullDelete = fullDelete self.voice = voice } - public static let sampleData = FullGroupPreferences(directMessages: GroupPreference(enable: .off), fullDelete: GroupPreference(enable: .off), voice: GroupPreference(enable: .on)) + public static let sampleData = FullGroupPreferences( + timedMessages: GroupPreference(enable: .off), + directMessages: GroupPreference(enable: .off), + fullDelete: GroupPreference(enable: .off), + voice: GroupPreference(enable: .on) + ) } public struct GroupPreferences: Codable { + public var timedMessages: GroupPreference? public var directMessages: GroupPreference? public var fullDelete: GroupPreference? public var voice: GroupPreference? - public init(directMessages: GroupPreference?, fullDelete: GroupPreference?, voice: GroupPreference?) { + public init(timedMessages: GroupPreference?, directMessages: GroupPreference?, fullDelete: GroupPreference?, voice: GroupPreference?) { + self.timedMessages = timedMessages self.directMessages = directMessages self.fullDelete = fullDelete self.voice = voice } - public static let sampleData = GroupPreferences(directMessages: GroupPreference(enable: .off), fullDelete: GroupPreference(enable: .off), voice: GroupPreference(enable: .on)) + public static let sampleData = GroupPreferences( + timedMessages: GroupPreference(enable: .off), + directMessages: GroupPreference(enable: .off), + fullDelete: GroupPreference(enable: .off), + voice: GroupPreference(enable: .on) + ) } public func toGroupPreferences(_ fullPreferences: FullGroupPreferences) -> GroupPreferences { - GroupPreferences(directMessages: fullPreferences.directMessages, fullDelete: fullPreferences.fullDelete, voice: fullPreferences.voice) + GroupPreferences( + timedMessages: fullPreferences.timedMessages, + directMessages: fullPreferences.directMessages, + fullDelete: fullPreferences.fullDelete, + voice: fullPreferences.voice + ) } public struct GroupPreference: Codable, Equatable {