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 6293fc7726..a7bd23b6ac 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 @@ -2101,10 +2101,10 @@ data class FeatureEnabled( get() = if (forUser) SimplexGreen else if (forContact) WarningYellow else HighOrLowlight companion object { - fun enabled(user: ChatPreference, contact: ChatPreference): FeatureEnabled = + fun enabled(asymmetric: Boolean, user: ChatPreference, contact: ChatPreference): FeatureEnabled = when { - user.allow == FeatureAllowed.ALWAYS && contact.allow == FeatureAllowed.NO -> FeatureEnabled(forUser = false, forContact = true) - user.allow == FeatureAllowed.NO && contact.allow == FeatureAllowed.ALWAYS -> FeatureEnabled(forUser = true, forContact = false) + user.allow == FeatureAllowed.ALWAYS && contact.allow == FeatureAllowed.NO -> FeatureEnabled(forUser = false, forContact = asymmetric) + user.allow == FeatureAllowed.NO && contact.allow == FeatureAllowed.ALWAYS -> FeatureEnabled(forUser = asymmetric, forContact = false) contact.allow == FeatureAllowed.NO -> FeatureEnabled(forUser = false, forContact = false) user.allow == FeatureAllowed.NO -> FeatureEnabled(forUser = false, forContact = false) else -> FeatureEnabled(forUser = true, forContact = true) @@ -2138,6 +2138,11 @@ enum class ChatFeature: Feature { @SerialName("fullDelete") FullDelete, @SerialName("voice") Voice; + val asymmetric: Boolean get() = when (this) { + TimedMessages -> false + else -> true + } + override val text: String get() = when(this) { TimedMessages -> generalGetString(R.string.timed_messages) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ContactPreferences.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ContactPreferences.kt index 299ae6e493..3e628a71b5 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ContactPreferences.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ContactPreferences.kt @@ -112,6 +112,7 @@ private fun FeatureSection( onSelected: (ContactFeatureAllowed) -> Unit ) { val enabled = FeatureEnabled.enabled( + feature.asymmetric, user = ChatPreference(allow = allowFeature.value.allowed), contact = pref.contactPreference ) diff --git a/apps/ios/Shared/Views/Chat/ContactPreferencesView.swift b/apps/ios/Shared/Views/Chat/ContactPreferencesView.swift index 63aa4b50c3..0cde3399c4 100644 --- a/apps/ios/Shared/Views/Chat/ContactPreferencesView.swift +++ b/apps/ios/Shared/Views/Chat/ContactPreferencesView.swift @@ -50,6 +50,7 @@ struct ContactPreferencesView: View { private func featureSection(_ feature: ChatFeature, _ userDefault: FeatureAllowed, _ pref: ContactUserPreference, _ allowFeature: Binding) -> some View { let enabled = FeatureEnabled.enabled( + asymmetric: feature.asymmetric, user: Preference(allow: allowFeature.wrappedValue.allowed), contact: pref.contactPreference ) diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index 4c53bf7359..26439c8e8c 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -231,10 +231,10 @@ public struct FeatureEnabled: Decodable { self.forContact = forContact } - public static func enabled(user: Preference, contact: Preference) -> FeatureEnabled { + public static func enabled(asymmetric: Bool, user: Preference, contact: Preference) -> FeatureEnabled { switch (user.allow, contact.allow) { - case (.always, .no): return FeatureEnabled(forUser: false, forContact: true) - case (.no, .always): return FeatureEnabled(forUser: true, forContact: false) + case (.always, .no): return FeatureEnabled(forUser: false, forContact: asymmetric) + case (.no, .always): return FeatureEnabled(forUser: asymmetric, forContact: false) case (_, .no): return FeatureEnabled(forUser: false, forContact: false) case (.no, _): return FeatureEnabled(forUser: false, forContact: false) default: return FeatureEnabled(forUser: true, forContact: true) @@ -278,6 +278,13 @@ public enum ChatFeature: String, Decodable, Feature { public var id: Self { self } + public var asymmetric: Bool { + switch self { + case .timedMessages: return false + default: return true + } + } + public var text: String { switch self { case .timedMessages: return NSLocalizedString("Disappearing messages", comment: "chat feature") diff --git a/src/Simplex/Chat/Messages.hs b/src/Simplex/Chat/Messages.hs index 6d637c71bc..438ac9748d 100644 --- a/src/Simplex/Chat/Messages.hs +++ b/src/Simplex/Chat/Messages.hs @@ -305,11 +305,10 @@ ciTimedToTTL timed_ = timed_ >>= \CITimed {ttl} -> Just ttl contactCITimedTTL :: Contact -> Maybe Int contactCITimedTTL Contact {mergedPreferences = ContactUserPreferences {timedMessages = ContactUserPreference {enabled, userPreference}}} - | forUser enabled && forContact enabled = case userPreference of - CUPContact TimedMessagesPreference {ttl = Just t} -> Just t - CUPUser TimedMessagesPreference {ttl = Just t} -> Just t - _ -> Nothing + | forUser enabled && forContact enabled = ttl | otherwise = Nothing + where + TimedMessagesPreference {ttl} = preference (userPreference :: ContactUserPref TimedMessagesPreference) groupCITimedTTL :: GroupInfo -> Maybe Int groupCITimedTTL GroupInfo {fullGroupPreferences = FullGroupPreferences {timedMessages = TimedMessagesGroupPreference {enable, ttl}}} diff --git a/src/Simplex/Chat/Types.hs b/src/Simplex/Chat/Types.hs index bb9e1aa149..d5f3207e73 100644 --- a/src/Simplex/Chat/Types.hs +++ b/src/Simplex/Chat/Types.hs @@ -787,10 +787,10 @@ instance ToJSON PrefEnabled where toJSON = J.genericToJSON J.defaultOptions toEncoding = J.genericToEncoding J.defaultOptions -prefEnabled :: FeatureI f => FeaturePreference f -> FeaturePreference f -> PrefEnabled -prefEnabled user contact = case (getField @"allow" user, getField @"allow" contact) of - (FAAlways, FANo) -> PrefEnabled {forUser = False, forContact = True} - (FANo, FAAlways) -> PrefEnabled {forUser = True, forContact = False} +prefEnabled :: FeatureI f => Bool -> FeaturePreference f -> FeaturePreference f -> PrefEnabled +prefEnabled asymmetric user contact = case (getField @"allow" user, getField @"allow" contact) of + (FAAlways, FANo) -> PrefEnabled {forUser = False, forContact = asymmetric} + (FANo, FAAlways) -> PrefEnabled {forUser = asymmetric, forContact = False} (_, FANo) -> PrefEnabled False False (FANo, _) -> PrefEnabled False False _ -> PrefEnabled True True @@ -819,12 +819,14 @@ contactUserPreferences user userPreferences contactPreferences connectedIncognit pref :: FeatureI f => SChatFeature f -> ContactUserPreference (FeaturePreference f) pref f = ContactUserPreference - { enabled = prefEnabled userPref ctPref, + { enabled = prefEnabled (asymmetric f) userPref ctPref, -- incognito contact cannot have default user preference used userPreference = if connectedIncognito then CUPContact ctUserPref else maybe (CUPUser userPref) CUPContact ctUserPref_, contactPreference = ctPref } where + asymmetric SCFTimedMessages = False + asymmetric _ = True ctUserPref = getPreference f userPreferences ctUserPref_ = chatPrefSel f userPreferences userPref = getPreference f ctUserPrefs