diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt b/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt index 48a916536b..f3f88e5b39 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt @@ -1431,7 +1431,7 @@ sealed class CIContent: ItemContent { companion object { fun featureText(feature: Feature, enabled: String, param: Int?): String = - if (feature.hasParam && param != null) { + if (feature.hasParam) { "${feature.text}: ${TimedMessagesPreference.ttlText(param)}" } else { "${feature.text}: $enabled" 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 a54328b65d..eb3d9cc602 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 @@ -984,8 +984,8 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a } } - suspend fun allowFeatureToContact(contact: Contact, feature: ChatFeature) { - val prefs = contact.mergedPreferences.toPreferences().setAllowed(feature) + suspend fun allowFeatureToContact(contact: Contact, feature: ChatFeature, param: Int? = null) { + val prefs = contact.mergedPreferences.toPreferences().setAllowed(feature, param = param) val toContact = apiSetContactPrefs(contact.contactId, prefs) if (toContact != null) { chatModel.updateContact(toContact) @@ -2044,9 +2044,9 @@ data class ChatPreferences( val fullDelete: SimpleChatPreference?, val voice: SimpleChatPreference?, ) { - fun setAllowed(feature: ChatFeature, allowed: FeatureAllowed = FeatureAllowed.YES): ChatPreferences = + fun setAllowed(feature: ChatFeature, allowed: FeatureAllowed = FeatureAllowed.YES, param: Int? = null): ChatPreferences = when (feature) { - ChatFeature.TimedMessages -> this.copy(timedMessages = TimedMessagesPreference(allow = allowed, ttl = this.timedMessages?.ttl)) + ChatFeature.TimedMessages -> this.copy(timedMessages = TimedMessagesPreference(allow = allowed, ttl = param ?: this.timedMessages?.ttl)) ChatFeature.FullDelete -> this.copy(fullDelete = SimpleChatPreference(allow = allowed)) ChatFeature.Voice -> this.copy(voice = SimpleChatPreference(allow = allowed)) } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt index 96ee2059a1..e774bb9420 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt @@ -226,9 +226,9 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: () -> Unit) { chatModel.callManager.acceptIncomingCall(invitation = invitation) } }, - acceptFeature = { contact, feature -> + acceptFeature = { contact, feature, param -> withApi { - chatModel.controller.allowFeatureToContact(contact, feature) + chatModel.controller.allowFeatureToContact(contact, feature, param) } }, addMembers = { groupInfo -> @@ -287,7 +287,7 @@ fun ChatLayout( joinGroup: (Long) -> Unit, startCall: (CallMediaType) -> Unit, acceptCall: (Contact) -> Unit, - acceptFeature: (Contact, ChatFeature) -> Unit, + acceptFeature: (Contact, ChatFeature, Int?) -> Unit, addMembers: (GroupInfo) -> Unit, markRead: (CC.ItemRange, unreadCountAfter: Int?) -> Unit, changeNtfsState: (Boolean, currentValue: MutableState) -> Unit, @@ -503,7 +503,7 @@ fun BoxWithConstraintsScope.ChatItemsList( receiveFile: (Long) -> Unit, joinGroup: (Long) -> Unit, acceptCall: (Contact) -> Unit, - acceptFeature: (Contact, ChatFeature) -> Unit, + acceptFeature: (Contact, ChatFeature, Int?) -> Unit, markRead: (CC.ItemRange, unreadCountAfter: Int?) -> Unit, setFloatingButton: (@Composable () -> Unit) -> Unit, onComposed: () -> Unit, @@ -1026,7 +1026,7 @@ fun PreviewChatLayout() { joinGroup = {}, startCall = {}, acceptCall = { _ -> }, - acceptFeature = { _, _ -> }, + acceptFeature = { _, _, _ -> }, addMembers = { _ -> }, markRead = { _, _ -> }, changeNtfsState = { _, _ -> }, @@ -1085,7 +1085,7 @@ fun PreviewGroupChatLayout() { joinGroup = {}, startCall = {}, acceptCall = { _ -> }, - acceptFeature = { _, _ -> }, + acceptFeature = { _, _, _ -> }, addMembers = { _ -> }, markRead = { _, _ -> }, changeNtfsState = { _, _ -> }, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIFeaturePreferenceView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIFeaturePreferenceView.kt index 4d2f51f1b1..bb3f400eab 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIFeaturePreferenceView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIFeaturePreferenceView.kt @@ -1,26 +1,17 @@ package chat.simplex.app.views.chat.item -import android.content.ActivityNotFoundException -import android.util.Log -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.* import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.app.R -import chat.simplex.app.TAG import chat.simplex.app.model.* import chat.simplex.app.ui.theme.HighOrLowlight -import chat.simplex.app.ui.theme.SimpleButton import chat.simplex.app.views.helpers.generalGetString @Composable @@ -29,7 +20,7 @@ fun CIFeaturePreferenceView( contact: Contact?, feature: ChatFeature, allowed: FeatureAllowed, - acceptFeature: (Contact, ChatFeature) -> Unit + acceptFeature: (Contact, ChatFeature, Int?) -> Unit ) { Row( Modifier.padding(horizontal = 6.dp, vertical = 6.dp), @@ -39,17 +30,20 @@ fun CIFeaturePreferenceView( Icon(feature.icon, feature.text, Modifier.size(18.dp), tint = HighOrLowlight) if (contact != null && allowed != FeatureAllowed.NO && contact.allowsFeature(feature) && !contact.userAllowsFeature(feature)) { val acceptStyle = SpanStyle(color = MaterialTheme.colors.primary, fontSize = 12.sp) + val setParam = feature == ChatFeature.TimedMessages && contact.mergedPreferences.timedMessages.userPreference.pref.ttl == null + val acceptTextId = if (setParam) R.string.accept_feature_set_1_day else R.string.accept_feature + val param = if (setParam) 86400 else null val annotatedText = buildAnnotatedString { withStyle(chatEventStyle) { append(chatItem.content.text + " ") } withAnnotation(tag = "Accept", annotation = "Accept") { - withStyle(acceptStyle) { append(generalGetString(R.string.accept) + " ") } + withStyle(acceptStyle) { append(generalGetString(acceptTextId) + " ") } } withStyle(chatEventStyle) { append(chatItem.timestampText) } } fun accept(offset: Int): Boolean = annotatedText.getStringAnnotations(tag = "Accept", start = offset, end = offset).isNotEmpty() ClickableText( annotatedText, - onClick = { if (accept(it)) { acceptFeature(contact, feature) } }, + onClick = { if (accept(it)) { acceptFeature(contact, feature, param) } }, shouldConsumeEvent = ::accept ) } else { diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/ChatItemView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/ChatItemView.kt index 3ae8acc2c9..64fd1d935c 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/ChatItemView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/ChatItemView.kt @@ -43,7 +43,7 @@ fun ChatItemView( joinGroup: (Long) -> Unit, acceptCall: (Contact) -> Unit, scrollToItem: (Long) -> Unit, - acceptFeature: (Contact, ChatFeature) -> Unit + acceptFeature: (Contact, ChatFeature, Int?) -> Unit ) { val context = LocalContext.current val uriHandler = LocalUriHandler.current @@ -326,7 +326,7 @@ fun PreviewChatItemView() { joinGroup = {}, acceptCall = { _ -> }, scrollToItem = {}, - acceptFeature = { _, _ -> } + acceptFeature = { _, _, _ -> } ) } } @@ -346,7 +346,7 @@ fun PreviewChatItemViewDeletedContent() { joinGroup = {}, acceptCall = { _ -> }, scrollToItem = {}, - acceptFeature = { _, _ -> } + acceptFeature = { _, _, _ -> } ) } } diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index 8ace468573..e60c9c791a 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -1001,6 +1001,8 @@ enabled for contact off received, prohibited + Accept + Set 1 day Allow your contacts to send disappearing messages. Allow disappearing messages only if your contact allows them. Prohibit sending disappearing messages. diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIFeaturePreferenceView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIFeaturePreferenceView.swift index 0f92bf2fca..5530f725ee 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIFeaturePreferenceView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIFeaturePreferenceView.swift @@ -23,9 +23,10 @@ struct CIFeaturePreferenceView: View { .scaleEffect(feature.iconScale) if let ct = chat.chatInfo.contact, allowed != .no && ct.allowsFeature(feature) && !ct.userAllowsFeature(feature) { - featurePreferenceView(accept: true) + let setParam = feature == .timedMessages && ct.mergedPreferences.timedMessages.userPreference.preference.ttl == nil + featurePreferenceView(acceptText: setParam ? "Set 1 day" : "Accept") .onTapGesture { - allowFeatureToContact(ct, feature) + allowFeatureToContact(ct, feature, param: setParam ? 86400 : nil) } } else { featurePreferenceView() @@ -36,26 +37,28 @@ struct CIFeaturePreferenceView: View { .textSelection(.disabled) } - private func featurePreferenceView(accept: Bool = false) -> some View { + private func featurePreferenceView(acceptText: LocalizedStringKey? = nil) -> some View { var r = Text(CIContent.preferenceText(feature, allowed, param) + " ") - .fontWeight(.light) - .foregroundColor(.secondary) - if accept { - r = r + Text("Accept" + " ") + .fontWeight(.light) + .foregroundColor(.secondary) + if let acceptText { + r = r + + Text(acceptText) .fontWeight(.medium) .foregroundColor(.accentColor) + + Text(" ") } r = r + chatItem.timestampText - .fontWeight(.light) - .foregroundColor(.secondary) + .fontWeight(.light) + .foregroundColor(.secondary) return r.font(.caption) } } -func allowFeatureToContact(_ contact: Contact, _ feature: ChatFeature) { +func allowFeatureToContact(_ contact: Contact, _ feature: ChatFeature, param: Int? = nil) { Task { do { - let prefs = contactUserPreferencesToPreferences(contact.mergedPreferences).setAllowed(feature) + let prefs = contactUserPreferencesToPreferences(contact.mergedPreferences).setAllowed(feature, param: param) if let toContact = try await apiSetContactPrefs(contactId: contact.contactId, preferences: prefs) { await MainActor.run { ChatModel.shared.updateContact(toContact) diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index 98cc0bbaf9..f97a469774 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -161,9 +161,9 @@ public struct Preferences: Codable { ) } - public func setAllowed(_ feature: ChatFeature, allowed: FeatureAllowed = .yes) -> Preferences { + public func setAllowed(_ feature: ChatFeature, allowed: FeatureAllowed = .yes, param: Int? = nil) -> Preferences { switch feature { - case .timedMessages: return copy(timedMessages: TimedMessagesPreference(allow: allowed, ttl: timedMessages?.ttl)) + case .timedMessages: return copy(timedMessages: TimedMessagesPreference(allow: allowed, ttl: param ?? timedMessages?.ttl)) case .fullDelete: return copy(fullDelete: SimplePreference(allow: allowed)) case .voice: return copy(voice: SimplePreference(allow: allowed)) } @@ -244,7 +244,7 @@ public struct TimedMessagesPreference: Preference { : String.localizedStringWithFormat(NSLocalizedString("%d hours", comment: "message ttl"), h) ) + maybe(m, String.localizedStringWithFormat(NSLocalizedString("%d min", comment: "message ttl"), m)) - + maybe (s, String.localizedStringWithFormat(NSLocalizedString("%d sec", comment: "message ttl"), s)) + + maybe(s, String.localizedStringWithFormat(NSLocalizedString("%d sec", comment: "message ttl"), s)) } public static func shortTtlText(_ ttl: Int?) -> LocalizedStringKey { @@ -1999,7 +1999,7 @@ public enum CIContent: Decodable, ItemContent { } static func featureText(_ feature: Feature, _ enabled: String, _ param: Int?) -> String { - feature.hasParam && param != nil + feature.hasParam ? "\(feature.text): \(TimedMessagesPreference.ttlText(param))" : "\(feature.text): \(enabled)" }