From 3e370a7c16ff17f9b5bf3ce88317fe5805672e57 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Tue, 27 Jun 2023 07:55:33 +0100 Subject: [PATCH 1/7] ios: group preference to prohibit files and media (#2611) * ios: group preference to prohibit files and media * style --- .../Chat/ComposeMessage/ComposeView.swift | 13 ++++++- .../Chat/Group/GroupPreferencesView.swift | 2 ++ apps/ios/SimpleXChat/ChatTypes.swift | 35 +++++++++++++++---- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift index a70f79ecb..7f58d90b8 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift @@ -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, diff --git a/apps/ios/Shared/Views/Chat/Group/GroupPreferencesView.swift b/apps/ios/Shared/Views/Chat/Group/GroupPreferencesView.swift index c013c29f1..af1a778ad 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupPreferencesView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupPreferencesView.swift @@ -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 { diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index 58d1642f5..7b0f87ea1 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -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 ) } From 388bdc70837d7e87fb0beb57ec934c97a7526add Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Tue, 27 Jun 2023 10:28:47 +0100 Subject: [PATCH 2/7] ios: improve chat filter, "No filtered chats" note (#2619) * ios: improve chat filter, "No filtered chats" note * refactor filter --- .../Shared/Views/ChatList/ChatListView.swift | 62 +++++++++++++------ 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 90ff8433e..6de638257 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -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) + } } } From 2ad9d0ddbce89dc70e39595d3a97e4929eef717b Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Tue, 27 Jun 2023 16:35:27 +0100 Subject: [PATCH 3/7] ios: update library --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index ea24c3325..4e6f128f9 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -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 = ""; }; 5CC2C0FE2809BF11000C35E3 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = "ru.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = ""; }; 5CC868F229EB540C0017BBFD /* CIRcvDecryptionError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIRcvDecryptionError.swift; sourceTree = ""; }; + 5CCAA6D02A4B38F600BAF93B /* libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.1.3.0-5OWMsZbPutPDzQF8wFktLQ.a"; sourceTree = ""; }; + 5CCAA6D12A4B38F600BAF93B /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + 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 = ""; }; + 5CCAA6D32A4B38F600BAF93B /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; + 5CCAA6D42A4B38F600BAF93B /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; 5CCB939B297EFCB100399E78 /* NavStackCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavStackCompat.swift; sourceTree = ""; }; 5CCD403327A5F6DF00368C90 /* AddContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContactView.swift; sourceTree = ""; }; 5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanToConnectView.swift; sourceTree = ""; }; @@ -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 = ""; }; 6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupPreferencesView.swift; sourceTree = ""; }; - 643EE9632A372E8700678085 /* libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.1.3.0-7OTLHAmjBPvIoz7MIh3bdt.a"; sourceTree = ""; }; - 643EE9642A372E8700678085 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - 643EE9652A372E8700678085 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; - 643EE9662A372E8700678085 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; - 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 = ""; }; 6440C9FF288857A10062C672 /* CIEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIEventView.swift; sourceTree = ""; }; 6440CA02288AECA70062C672 /* AddGroupMembersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddGroupMembersView.swift; sourceTree = ""; }; 6442E0B9287F169300CEC0F9 /* AddGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddGroupView.swift; sourceTree = ""; }; @@ -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 = ""; From 534151f1bb7e2c5ddfb630339e40367a75b06557 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Tue, 27 Jun 2023 20:58:04 +0300 Subject: [PATCH 4/7] android: group preference to prohibit files and media (#2620) Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> --- .../java/chat/simplex/app/model/SimpleXAPI.kt | 29 +++++++++++++++---- .../simplex/app/views/chat/ComposeView.kt | 16 ++++++++-- .../app/views/chat/group/GroupPreferences.kt | 6 ++++ .../app/src/main/res/values/strings.xml | 7 +++++ 4 files changed, 50 insertions(+), 8 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 fdc038d64..c20fe976b 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 @@ -2930,7 +2930,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 +2945,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 +2955,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 +2965,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 +2991,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 +3018,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 +3134,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 +3143,8 @@ data class FullGroupPreferences( directMessages = directMessages, fullDelete = fullDelete, reactions = reactions, - voice = voice + voice = voice, + files = files, ) companion object { @@ -3139,7 +3153,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 +3165,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 +3174,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), ) } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ComposeView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ComposeView.kt index 32f68a8b9..189a8e4ad 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ComposeView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ComposeView.kt @@ -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) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupPreferences.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupPreferences.kt index e23f0dd26..d6157140b 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupPreferences.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupPreferences.kt @@ -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( diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index 4130f55ac..fa79b17d3 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -281,6 +281,8 @@ you are observer You can\'t send messages! Please contact group admin. + Files and media prohibited! + Only group owners can enable files and media. Image @@ -1290,6 +1292,7 @@ Delete for everyone Message reactions Voice messages + Files and media Audio/video calls \nAvailable in v5.1 enabled @@ -1344,6 +1347,8 @@ Prohibit sending voice messages. Allow message reactions. Prohibit messages reactions. + Allow to send files and media. + Prohibit sending files and media. Group members can send disappearing messages. Disappearing messages are prohibited in this group. Group members can send direct messages. @@ -1354,6 +1359,8 @@ Voice messages are prohibited in this group. Group members can add message reactions. Message reactions are prohibited in this group. + Group members can send files and media. + Files and media are prohibited in this group. Delete after %d sec %ds From f23c0b55f8791e94ab7729c47301d1931ed7ff44 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Wed, 28 Jun 2023 14:20:23 +0300 Subject: [PATCH 5/7] android: filter favorite and unread chats (#2623) * android: filter favorite and unread chats * style * unused icons * inverted colors * change colors, size * changes to strings and icon --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> --- .../java/chat/simplex/app/model/ChatModel.kt | 11 ++- .../java/chat/simplex/app/model/SimpleXAPI.kt | 11 ++- .../chat/simplex/app/views/chat/ChatView.kt | 2 +- .../app/views/chatlist/ChatListNavLinkView.kt | 39 ++++++++-- .../app/views/chatlist/ChatListView.kt | 78 ++++++++++++++++--- .../app/views/chatlist/ChatPreviewView.kt | 15 ++++ .../src/main/res/drawable/ic_filter_list.xml | 4 + .../src/main/res/drawable/ic_star_filled.xml | 9 +++ .../app/src/main/res/drawable/ic_star_off.xml | 9 +++ .../app/src/main/res/values-cs/strings.xml | 2 +- .../app/src/main/res/values-de/strings.xml | 2 +- .../app/src/main/res/values-fr/strings.xml | 2 +- .../app/src/main/res/values-it/strings.xml | 2 +- .../app/src/main/res/values-iw/strings.xml | 2 +- .../app/src/main/res/values-ja/strings.xml | 2 +- .../app/src/main/res/values-lt/strings.xml | 2 +- .../app/src/main/res/values-nl/strings.xml | 2 +- .../app/src/main/res/values-pl/strings.xml | 2 +- .../src/main/res/values-pt-rBR/strings.xml | 2 +- .../app/src/main/res/values-ru/strings.xml | 2 +- .../app/src/main/res/values-th/strings.xml | 2 +- .../app/src/main/res/values-uk/strings.xml | 2 +- .../src/main/res/values-zh-rCN/strings.xml | 2 +- .../app/src/main/res/values/strings.xml | 6 +- apps/ios/SimpleXChat/APITypes.swift | 4 +- 25 files changed, 179 insertions(+), 37 deletions(-) create mode 100644 apps/android/app/src/main/res/drawable/ic_filter_list.xml create mode 100644 apps/android/app/src/main/res/drawable/ic_star_filled.xml create mode 100644 apps/android/app/src/main/res/drawable/ic_star_off.xml 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 9fcc0b14f..3d9de2d35 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 @@ -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() ) 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 c20fe976b..e1fbbaa0c 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 @@ -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( 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 ed26b2d76..7681b79b7 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 @@ -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 diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt index 5e9bceb20..dc9aaca3b 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt @@ -145,6 +145,7 @@ fun ContactMenuItems(chat: Chat, chatModel: ChatModel, showMenu: MutableState) { + 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) { 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, chat: Chat, chatModel: ChatModel) { +fun toggleNotifications(chat: Chat, enableNtfs: Boolean, chatModel: ChatModel, currentState: MutableState? = 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? = 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 } 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 + } } } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt index 07c859e50..f18142c69 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt @@ -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 { + 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()) + diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt index 5a4745ced..4726cc825 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt @@ -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( diff --git a/apps/android/app/src/main/res/drawable/ic_filter_list.xml b/apps/android/app/src/main/res/drawable/ic_filter_list.xml new file mode 100644 index 000000000..c34f1d13b --- /dev/null +++ b/apps/android/app/src/main/res/drawable/ic_filter_list.xml @@ -0,0 +1,4 @@ + + + diff --git a/apps/android/app/src/main/res/drawable/ic_star_filled.xml b/apps/android/app/src/main/res/drawable/ic_star_filled.xml new file mode 100644 index 000000000..278b86718 --- /dev/null +++ b/apps/android/app/src/main/res/drawable/ic_star_filled.xml @@ -0,0 +1,9 @@ + + + diff --git a/apps/android/app/src/main/res/drawable/ic_star_off.xml b/apps/android/app/src/main/res/drawable/ic_star_off.xml new file mode 100644 index 000000000..8806fd1a5 --- /dev/null +++ b/apps/android/app/src/main/res/drawable/ic_star_off.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/apps/android/app/src/main/res/values-cs/strings.xml b/apps/android/app/src/main/res/values-cs/strings.xml index 126d23d19..932d4df23 100644 --- a/apps/android/app/src/main/res/values-cs/strings.xml +++ b/apps/android/app/src/main/res/values-cs/strings.xml @@ -951,7 +951,7 @@ Budete připojeni, jakmile bude zařízení vašeho kontaktu online, vyčkejte prosím nebo se podívejte později! Váš chat profil bude odeslán \nvašemu kontaktu - Vaše konverzace + Konverzace Do níže uvedeného pole vložte odkaz, který jste obdrželi pro spojení s kontaktem. Sdílet jednorázovou pozvánku koncově šifrované diff --git a/apps/android/app/src/main/res/values-de/strings.xml b/apps/android/app/src/main/res/values-de/strings.xml index 05427e2b5..5c265adfe 100644 --- a/apps/android/app/src/main/res/values-de/strings.xml +++ b/apps/android/app/src/main/res/values-de/strings.xml @@ -170,7 +170,7 @@ Willkommen %1$s! Willkommen! Dieser Text ist in den Einstellungen verfügbar. - Meine Chats + Chats verbinde … Sie sind zu der Gruppe eingeladen Beitreten als %s diff --git a/apps/android/app/src/main/res/values-fr/strings.xml b/apps/android/app/src/main/res/values-fr/strings.xml index 8e7ba8e18..ace389afb 100644 --- a/apps/android/app/src/main/res/values-fr/strings.xml +++ b/apps/android/app/src/main/res/values-fr/strings.xml @@ -118,7 +118,7 @@ Autoriser Supprimer le message \? Supprimer pour moi - Vos chats + Chats Texte du message Caché Pour protéger vos informations, activez la fonction SimpleX Lock. diff --git a/apps/android/app/src/main/res/values-it/strings.xml b/apps/android/app/src/main/res/values-it/strings.xml index d8fe11b76..6e817c23c 100644 --- a/apps/android/app/src/main/res/values-it/strings.xml +++ b/apps/android/app/src/main/res/values-it/strings.xml @@ -145,7 +145,7 @@ Benvenuto/a %1$s! Benvenuto/a! Questo testo è disponibile nelle impostazioni - Le tue chat + Сhat sei stato invitato in un gruppo entra come %s in connessione… diff --git a/apps/android/app/src/main/res/values-iw/strings.xml b/apps/android/app/src/main/res/values-iw/strings.xml index 480996f98..cdda3579b 100644 --- a/apps/android/app/src/main/res/values-iw/strings.xml +++ b/apps/android/app/src/main/res/values-iw/strings.xml @@ -1220,7 +1220,7 @@ פרופיל הצ׳אט שלך יישלח לחברי הקבוצה מסד הנתונים שלך אינו מוצפן – יש להגדיר סיסמה כדי להגן עליו. אנשי הקשר שלך יכולים לאפשר מחיקת הודעות מלאה. - הצ׳אטים שלך + הצ׳אטים איש הקשר שלך שלח קובץ גדול יותר מהגודל המרבי הנתמך כעת (%1$s). איש הקשר שלך צריך להיות מקוון כדי שהחיבור יושלם. \nניתן לבטל חיבור זה ולהסיר את איש הקשר (ולנסות מאוחר יותר עם קישור חדש). diff --git a/apps/android/app/src/main/res/values-ja/strings.xml b/apps/android/app/src/main/res/values-ja/strings.xml index 883cf2b99..38ae6fe4a 100644 --- a/apps/android/app/src/main/res/values-ja/strings.xml +++ b/apps/android/app/src/main/res/values-ja/strings.xml @@ -704,7 +704,7 @@ 画像数の上限を超えてます! ようこそ! グループ招待が届きました - あなたのチャット + チャット 連絡先を設定… ファイル待ち 受信アドレスを変えますか? diff --git a/apps/android/app/src/main/res/values-lt/strings.xml b/apps/android/app/src/main/res/values-lt/strings.xml index b0d0fc4dc..083c517f7 100644 --- a/apps/android/app/src/main/res/values-lt/strings.xml +++ b/apps/android/app/src/main/res/values-lt/strings.xml @@ -347,7 +347,7 @@ Jūs nustosite gauti žinutes iš šios grupės. Pokalbio istorija bus išsaugota. jūs: %1$s Sveiki, %1$s! - Jūsų pokalbiai + Pokalbiai Neteisinga duomenų bazės slaptafrazė Vaizdo įrašas išsiųstas Balso žinutė diff --git a/apps/android/app/src/main/res/values-nl/strings.xml b/apps/android/app/src/main/res/values-nl/strings.xml index 79cd95524..04e55d297 100644 --- a/apps/android/app/src/main/res/values-nl/strings.xml +++ b/apps/android/app/src/main/res/values-nl/strings.xml @@ -662,7 +662,7 @@ Welkom! je bent uitgenodigd voor de groep Je hebt geen gesprekken - Jouw gesprekken + Gesprekken Deel bestand… Afbeelding delen… Wachten op afbeelding diff --git a/apps/android/app/src/main/res/values-pl/strings.xml b/apps/android/app/src/main/res/values-pl/strings.xml index e27e43663..7d4474bc0 100644 --- a/apps/android/app/src/main/res/values-pl/strings.xml +++ b/apps/android/app/src/main/res/values-pl/strings.xml @@ -156,7 +156,7 @@ Witaj %1$s! jesteś zaproszony do grupy Nie masz czatów - Twoje czaty + Czaty Poproszony o odbiór obrazu Poproszony o odbiór filmu Błąd dekodowania diff --git a/apps/android/app/src/main/res/values-pt-rBR/strings.xml b/apps/android/app/src/main/res/values-pt-rBR/strings.xml index ff3d9e8e1..e12e60ac0 100644 --- a/apps/android/app/src/main/res/values-pt-rBR/strings.xml +++ b/apps/android/app/src/main/res/values-pt-rBR/strings.xml @@ -573,7 +573,7 @@ Executa quando o aplicativo está aberto enviado o envio falhou - Seus chats + Chats Seu perfil de chat será enviado para seu contato Colar Link de convite de uso único diff --git a/apps/android/app/src/main/res/values-ru/strings.xml b/apps/android/app/src/main/res/values-ru/strings.xml index a66bc7d20..6ecbc40e9 100644 --- a/apps/android/app/src/main/res/values-ru/strings.xml +++ b/apps/android/app/src/main/res/values-ru/strings.xml @@ -172,7 +172,7 @@ Здравствуйте %1$s! Здравствуйте! Этот текст можно найти в Настройках - Ваши чаты + Чаты соединяется… Вы приглашены в группу вступить как %s diff --git a/apps/android/app/src/main/res/values-th/strings.xml b/apps/android/app/src/main/res/values-th/strings.xml index bfb1a424e..d604bcd42 100644 --- a/apps/android/app/src/main/res/values-th/strings.xml +++ b/apps/android/app/src/main/res/values-th/strings.xml @@ -1103,7 +1103,7 @@ ยินดีต้อนรับ %1$s! คุณได้รับเชิญให้เข้าร่วมกลุ่ม คุณไม่มีการแชท - แชทของคุณ + แชท คุณเป็นผู้สังเกตการณ์ ไม่สามารถถอดรหัสภาพได้ โปรดลองใช้ภาพอื่นหรือติดต่อผู้พัฒนาแอป คุณไม่สามารถส่งข้อความได้! diff --git a/apps/android/app/src/main/res/values-uk/strings.xml b/apps/android/app/src/main/res/values-uk/strings.xml index d008a23e5..64ef76a4b 100644 --- a/apps/android/app/src/main/res/values-uk/strings.xml +++ b/apps/android/app/src/main/res/values-uk/strings.xml @@ -331,7 +331,7 @@ Зупинити чат Відкрийте консоль чату Повідомлення буде позначено як модероване для всіх учасників. - Ваші чати + Чати підключення… підключення… Натисніть, щоб почати новий чат diff --git a/apps/android/app/src/main/res/values-zh-rCN/strings.xml b/apps/android/app/src/main/res/values-zh-rCN/strings.xml index bdeedf511..82882bcda 100644 --- a/apps/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/apps/android/app/src/main/res/values-zh-rCN/strings.xml @@ -495,7 +495,7 @@ 只显示联系人 为保护您的信息,请打开 SimpleX 锁定。 \n在启用此功能之前,系统将提示您完成身份验证。 - 您的聊天 + 聊天 分享文件…… 分享媒体…… 分享消息…… diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index fa79b17d3..bd82c3c94 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -253,7 +253,7 @@ Welcome %1$s! Welcome! This text is available in settings - Your chats + Chats connecting… you are invited to group join as %s @@ -261,6 +261,7 @@ Tap to start a new chat Chat with the developers You have no chats + No filtered chats Share message… @@ -424,6 +425,9 @@ Mute Unmute + Favorite + Unfavorite + You invited your contact diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index 41961c693..c10bad448 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -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 } From a5f8641d50c903b3f4e425611029c952a84057aa Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:00:42 +0300 Subject: [PATCH 6/7] android: search members (#2621) * android: search members * changed placement of search fields * less diff * remove unused function --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> --- .../views/chat/group/AddGroupMembersView.kt | 40 ++++++++++++++++--- .../app/views/chat/group/GroupChatInfoView.kt | 24 ++++++++++- .../app/views/helpers/DefaultTopAppBar.kt | 2 +- .../simplex/app/views/helpers/ModalView.kt | 6 +++ .../app/views/helpers/SearchTextField.kt | 21 ++++++---- .../app/views/usersettings/SettingsView.kt | 2 +- 6 files changed, 79 insertions(+), 16 deletions(-) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt index 096b19de0..9d5284bbe 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt @@ -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() } 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 { +fun getContactsToAdd(chatModel: ChatModel, search: String): List { + val s = search.trim().lowercase() val memberContactIds = chatModel.groupMembers .filter { it.memberCurrent } .mapNotNull { it.memberContactId } @@ -78,7 +85,7 @@ fun getContactsToAdd(chatModel: ChatModel): List { .map { it.chatInfo } .filterIsInstance() .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, selectedRole: MutableState, allowModifyMembers: Boolean, + searchText: MutableState, 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 = 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, 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 = {}, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt index 472282093..fdb94ac6f 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt @@ -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 = 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() { diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/DefaultTopAppBar.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/DefaultTopAppBar.kt index 9896b0302..81cad18f5 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/DefaultTopAppBar.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/DefaultTopAppBar.kt @@ -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, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/ModalView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/ModalView.kt index d4b48bdb9..64c2d7fc4 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/ModalView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/ModalView.kt @@ -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 diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/SearchTextField.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/SearchTextField.kt index 2655f75e3..5b299d385 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/SearchTextField.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/SearchTextField.kt @@ -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 = 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,) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt index 2966a6570..682c44a12 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt @@ -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) }) } From 3f93397031ca568acdfb15385c1472f056aee908 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Wed, 28 Jun 2023 16:13:14 +0400 Subject: [PATCH 7/7] core: 5.2.0.0 (#2626) --- package.yaml | 2 +- simplex-chat.cabal | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.yaml b/package.yaml index c7b5aca49..0e0f49a2b 100644 --- a/package.yaml +++ b/package.yaml @@ -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 diff --git a/simplex-chat.cabal b/simplex-chat.cabal index 162a57c23..8a2bb16a6 100644 --- a/simplex-chat.cabal +++ b/simplex-chat.cabal @@ -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