From 37d9954cf719de719f41925a5e609b0567723d7a Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Mon, 3 Feb 2025 22:41:06 +0000 Subject: [PATCH 1/5] ios: update core library --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index c8c7db46c0..e3b286f469 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -167,9 +167,9 @@ 648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; }; 648679AB2BC96A74006456E7 /* ChatItemForwardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */; }; 649B28DD2CFE07CF00536B68 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 649B28D82CFE07CF00536B68 /* libffi.a */; }; - 649B28DE2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.1-HduHbmAnH3q9HOCIBFU5AE-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 649B28D92CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.1-HduHbmAnH3q9HOCIBFU5AE-ghc9.6.3.a */; }; + 649B28DE2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 649B28D92CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH-ghc9.6.3.a */; }; 649B28DF2CFE07CF00536B68 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 649B28DA2CFE07CF00536B68 /* libgmpxx.a */; }; - 649B28E02CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.1-HduHbmAnH3q9HOCIBFU5AE.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 649B28DB2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.1-HduHbmAnH3q9HOCIBFU5AE.a */; }; + 649B28E02CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 649B28DB2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH.a */; }; 649B28E12CFE07CF00536B68 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 649B28DC2CFE07CF00536B68 /* libgmp.a */; }; 649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; }; 649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; }; @@ -520,9 +520,9 @@ 648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemForwardingView.swift; sourceTree = ""; }; 6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 649B28D82CFE07CF00536B68 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - 649B28D92CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.1-HduHbmAnH3q9HOCIBFU5AE-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.0.1-HduHbmAnH3q9HOCIBFU5AE-ghc9.6.3.a"; sourceTree = ""; }; + 649B28D92CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH-ghc9.6.3.a"; sourceTree = ""; }; 649B28DA2CFE07CF00536B68 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; - 649B28DB2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.1-HduHbmAnH3q9HOCIBFU5AE.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.0.1-HduHbmAnH3q9HOCIBFU5AE.a"; sourceTree = ""; }; + 649B28DB2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH.a"; sourceTree = ""; }; 649B28DC2CFE07CF00536B68 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = ""; }; 649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = ""; }; @@ -679,9 +679,9 @@ 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */, 649B28E12CFE07CF00536B68 /* libgmp.a in Frameworks */, 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */, - 649B28E02CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.1-HduHbmAnH3q9HOCIBFU5AE.a in Frameworks */, + 649B28E02CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH.a in Frameworks */, CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */, - 649B28DE2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.1-HduHbmAnH3q9HOCIBFU5AE-ghc9.6.3.a in Frameworks */, + 649B28DE2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH-ghc9.6.3.a in Frameworks */, 649B28DD2CFE07CF00536B68 /* libffi.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -762,8 +762,8 @@ 649B28D82CFE07CF00536B68 /* libffi.a */, 649B28DC2CFE07CF00536B68 /* libgmp.a */, 649B28DA2CFE07CF00536B68 /* libgmpxx.a */, - 649B28D92CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.1-HduHbmAnH3q9HOCIBFU5AE-ghc9.6.3.a */, - 649B28DB2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.1-HduHbmAnH3q9HOCIBFU5AE.a */, + 649B28D92CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH-ghc9.6.3.a */, + 649B28DB2CFE07CF00536B68 /* libHSsimplex-chat-6.3.0.2-Dof9ekfAaNQ8X3suD73WcH.a */, ); path = Libraries; sourceTree = ""; From f4b93f6e8a43de799af2919b6c6c15fbd6cf7283 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Tue, 4 Feb 2025 11:24:39 +0000 Subject: [PATCH 2/5] 6.3-beta.2: ios 261, android 271, desktop 89 --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 20 ++++++++++---------- apps/multiplatform/gradle.properties | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index e3b286f469..9b2c6737d5 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -1947,7 +1947,7 @@ CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 260; + CURRENT_PROJECT_VERSION = 261; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; @@ -1996,7 +1996,7 @@ CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 260; + CURRENT_PROJECT_VERSION = 261; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; @@ -2037,7 +2037,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 260; + CURRENT_PROJECT_VERSION = 261; DEVELOPMENT_TEAM = 5NN7GUYB6T; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.0; @@ -2057,7 +2057,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 260; + CURRENT_PROJECT_VERSION = 261; DEVELOPMENT_TEAM = 5NN7GUYB6T; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.0; @@ -2082,7 +2082,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 260; + CURRENT_PROJECT_VERSION = 261; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; GCC_OPTIMIZATION_LEVEL = s; @@ -2119,7 +2119,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 260; + CURRENT_PROJECT_VERSION = 261; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; ENABLE_CODE_COVERAGE = NO; @@ -2156,7 +2156,7 @@ CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 260; + CURRENT_PROJECT_VERSION = 261; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; @@ -2207,7 +2207,7 @@ CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 260; + CURRENT_PROJECT_VERSION = 261; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; @@ -2258,7 +2258,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 260; + CURRENT_PROJECT_VERSION = 261; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; @@ -2292,7 +2292,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 260; + CURRENT_PROJECT_VERSION = 261; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; diff --git a/apps/multiplatform/gradle.properties b/apps/multiplatform/gradle.properties index 6c04bf65d7..9fa745c88f 100644 --- a/apps/multiplatform/gradle.properties +++ b/apps/multiplatform/gradle.properties @@ -24,11 +24,11 @@ android.nonTransitiveRClass=true kotlin.mpp.androidSourceSetLayoutVersion=2 kotlin.jvm.target=11 -android.version_name=6.3-beta.1 -android.version_code=270 +android.version_name=6.3-beta.2 +android.version_code=271 -desktop.version_name=6.3-beta.1 -desktop.version_code=88 +desktop.version_name=6.3-beta.2 +desktop.version_code=89 kotlin.version=1.9.23 gradle.plugin.version=8.2.0 From 844b24be9d15e8d223a8ff7f2c3c33a770d0339b Mon Sep 17 00:00:00 2001 From: Evgeny Date: Wed, 5 Feb 2025 09:40:42 +0000 Subject: [PATCH 3/5] core: forward reports only to moderators and above roles (#5605) * core: do not forward reports * test * core: forward reports only to moderators and above roles (#5606) * core: forward reports only to moderators and above roles * test * name * name --------- Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> --- src/Simplex/Chat/Protocol.hs | 19 ++++++- src/Simplex/Chat/Store/Groups.hs | 2 +- .../SQLite/Migrations/chat_query_plans.txt | 2 +- tests/ChatTests/Groups.hs | 53 +++++++++++++++++++ 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/Simplex/Chat/Protocol.hs b/src/Simplex/Chat/Protocol.hs index 53af11ada7..b366cc3979 100644 --- a/src/Simplex/Chat/Protocol.hs +++ b/src/Simplex/Chat/Protocol.hs @@ -390,19 +390,34 @@ forwardedGroupMsg msg@ChatMessage {chatMsgEvent} = case encoding @e of _ -> Nothing -- applied after checking forwardedGroupMsg and building list of group members to forward to, see Chat; +-- -- this filters out members if any of forwarded events in batch is an XGrpMemRestrict event referring to them, -- but practically XGrpMemRestrict is not batched with other events so it wouldn't prevent forwarding of other events --- to these members +-- to these members; +-- +-- same for reports (MCReport) - they are not batched with other events, so we can safely filter out +-- members with role less than moderator when forwarding forwardedToGroupMembers :: forall e. MsgEncodingI e => [GroupMember] -> NonEmpty (ChatMessage e) -> [GroupMember] forwardedToGroupMembers ms forwardedMsgs = - filter (\GroupMember {memberId} -> memberId `notElem` restrictMemberIds) ms + filter forwardToMember ms where + forwardToMember GroupMember {memberId, memberRole} = + (memberId `notElem` restrictMemberIds) + && (not hasReport || memberRole >= GRModerator) restrictMemberIds = mapMaybe restrictMemberId $ L.toList forwardedMsgs restrictMemberId ChatMessage {chatMsgEvent} = case encoding @e of SJson -> case chatMsgEvent of XGrpMemRestrict mId _ -> Just mId _ -> Nothing _ -> Nothing + hasReport = any isReport forwardedMsgs + isReport ChatMessage {chatMsgEvent} = case encoding @e of + SJson -> case chatMsgEvent of + XMsgNew mc -> case mcExtMsgContent mc of + ExtMsgContent {content = MCReport {}} -> True + _ -> False + _ -> False + _ -> False data MsgReaction = MREmoji {emoji :: MREmojiChar} | MRUnknown {tag :: Text, json :: J.Object} deriving (Eq, Show) diff --git a/src/Simplex/Chat/Store/Groups.hs b/src/Simplex/Chat/Store/Groups.hs index 75a6c446b6..204689a7b9 100644 --- a/src/Simplex/Chat/Store/Groups.hs +++ b/src/Simplex/Chat/Store/Groups.hs @@ -891,7 +891,7 @@ getGroupModerators db vr user@User {userId, userContactId} GroupInfo {groupId} = map (toContactMember vr user) <$> DB.query db - (groupMemberQuery <> " WHERE m.user_id = ? AND m.group_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?) AND member_role IN (?,?,?)") + (groupMemberQuery <> " WHERE m.user_id = ? AND m.group_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?) AND m.member_role IN (?,?,?)") (userId, userId, groupId, userContactId, GRModerator, GRAdmin, GROwner) getGroupMembersForExpiration :: DB.Connection -> VersionRangeChat -> User -> GroupInfo -> IO [GroupMember] diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt index ed3853a743..a94da2dbe6 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt +++ b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt @@ -4577,7 +4577,7 @@ Query: FROM connections cc WHERE cc.user_id = ? AND cc.group_member_id = m.group_member_id ) - WHERE m.user_id = ? AND m.group_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?) AND member_role IN (?,?,?) + WHERE m.user_id = ? AND m.group_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?) AND m.member_role IN (?,?,?) Plan: SEARCH m USING INDEX idx_group_members_group_id (user_id=? AND group_id=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) diff --git a/tests/ChatTests/Groups.hs b/tests/ChatTests/Groups.hs index 2e4e777959..0c5a6bef36 100644 --- a/tests/ChatTests/Groups.hs +++ b/tests/ChatTests/Groups.hs @@ -133,6 +133,7 @@ chatGroupTests = do it "re-create member contact after deletion, many groups" testRecreateMemberContactManyGroups describe "group message forwarding" $ do it "forward messages between invitee and introduced (x.msg.new)" testGroupMsgForward + it "forward reports to moderators, don't forward to members (x.msg.new, MCReport)" testGroupMsgForwardReport it "deduplicate forwarded messages" testGroupMsgForwardDeduplicate it "forward message edit (x.msg.update)" testGroupMsgForwardEdit it "forward message reaction (x.msg.react)" testGroupMsgForwardReaction @@ -3980,6 +3981,58 @@ testGroupMsgForward = cath <# "#team bob> hi there [>>]" cath <# "#team hey team" +testGroupMsgForwardReport :: HasCallStack => TestParams -> IO () +testGroupMsgForwardReport = + testChat3 aliceProfile bobProfile cathProfile $ + \alice bob cath -> do + setupGroupForwarding3 "team" alice bob cath + + bob #> "#team hi there" + alice <# "#team bob> hi there" + cath <# "#team bob> hi there [>>]" + + alice ##> "/mr team bob moderator" + concurrentlyN_ + [ alice <## "#team: you changed the role of bob from admin to moderator", + bob <## "#team: alice changed your role from admin to moderator", + cath <## "#team: alice changed the role of bob from admin to moderator" + ] + + cath ##> "/report #team content hi there" + cath <# "#team > bob hi there" + cath <## " report content" + concurrentlyN_ + [ do + alice <# "#team cath> > bob hi there" + alice <## " report content", + do + bob <# "#team cath!> > bob hi there [>>]" + bob <## " report content [>>]" + ] + + alice ##> "/mr team bob member" + concurrentlyN_ + [ alice <## "#team: you changed the role of bob from moderator to member", + bob <## "#team: alice changed your role from moderator to member", + cath <## "#team: alice changed the role of bob from moderator to member" + ] + + cath ##> "/report #team content hi there" + cath <# "#team > bob hi there" + cath <## " report content" + concurrentlyN_ + [ do + alice <# "#team cath> > bob hi there" + alice <## " report content", + (bob "#team hey team" + alice <# "#team cath> hey team" + bob <# "#team cath> hey team [>>]" + setupGroupForwarding3 :: String -> TestCC -> TestCC -> TestCC -> IO () setupGroupForwarding3 gName alice bob cath = do createGroup3 gName alice bob cath From a622cb91f9c74a9859691a491bd13ce66c7db062 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Wed, 5 Feb 2025 22:22:32 +0700 Subject: [PATCH 4/5] ios: fix members ruins layout of ComposeView (#5607) * ios: fix members ruins layout of ComposeView * change to func * filter --------- Co-authored-by: Evgeny Poberezkin --- .../Views/Chat/Group/GroupMentions.swift | 127 ++++++++++-------- 1 file changed, 69 insertions(+), 58 deletions(-) diff --git a/apps/ios/Shared/Views/Chat/Group/GroupMentions.swift b/apps/ios/Shared/Views/Chat/Group/GroupMentions.swift index a621dd1f67..0b9db8493b 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupMentions.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupMentions.swift @@ -27,79 +27,76 @@ struct GroupMentionsView: View { @State private var mentionName: String = "" @State private var mentionRange: NSRange? @State private var mentionMemberId: String? + @State private var sortedMembers: [GMember] = [] var body: some View { ZStack { if isVisible { - Color.white.opacity(0.01) - .edgesIgnoringSafeArea(.all) - .onTapGesture { - isVisible = false - } - } - VStack { - Spacer() - VStack { - Spacer() + let filtered = filteredMembers() + if filtered.count > 0 { + Color.white.opacity(0.01) + .edgesIgnoringSafeArea(.all) + .onTapGesture { + isVisible = false + } VStack { - Divider() - let list = List { - ForEach(filteredMembers, id: \.wrapped.groupMemberId) { member in - let mentioned = mentionMemberId == member.wrapped.memberId - let disabled = composeState.mentions.count >= MAX_NUMBER_OF_MENTIONS && !mentioned - memberRowView(member.wrapped, mentioned) - .contentShape(Rectangle()) - .disabled(disabled) - .opacity(disabled ? 0.6 : 1) - .onTapGesture { - memberSelected(member) + Spacer() + VStack { + Spacer() + VStack { + Divider() + let list = List { + ForEach(filtered, id: \.wrapped.groupMemberId) { member in + let mentioned = mentionMemberId == member.wrapped.memberId + let disabled = composeState.mentions.count >= MAX_NUMBER_OF_MENTIONS && !mentioned + memberRowView(member.wrapped, mentioned) + .contentShape(Rectangle()) + .disabled(disabled) + .opacity(disabled ? 0.6 : 1) + .onTapGesture { + memberSelected(member) + } + } + } + .listStyle(PlainListStyle()) + .frame(maxHeight: MEMBER_ROW_SIZE * min(MAX_VISIBLE_MEMBER_ROWS, CGFloat(filtered.count))) + + if #available(iOS 16.0, *) { + list.scrollDismissesKeyboard(.never) + } else { + list } } + .background(Color(UIColor.systemBackground)) } - .listStyle(PlainListStyle()) - .frame(height: MEMBER_ROW_SIZE * min(MAX_VISIBLE_MEMBER_ROWS, CGFloat(filteredMembers.count))) - - if #available(iOS 16.0, *) { - list.scrollDismissesKeyboard(.never) - } else { - list - } + .frame(maxWidth: .infinity, maxHeight: MEMBER_ROW_SIZE * MAX_VISIBLE_MEMBER_ROWS) } - .background(Color(UIColor.systemBackground)) - } - .frame(maxWidth: .infinity, maxHeight: MEMBER_ROW_SIZE * MAX_VISIBLE_MEMBER_ROWS) - } - .offset(y: isVisible ? 0 : 300) - .animation(.spring(), value: isVisible) - .onChange(of: composeState.parsedMessage) { parsedMsg in - currentMessage = composeState.message - messageChanged(currentMessage, parsedMsg, selectedRange) - } - .onChange(of: selectedRange) { r in - // This condition is needed to prevent messageChanged called twice, - // because composeState.formattedText triggers later when message changes. - // The condition is only true if position changed without text change - if currentMessage == composeState.message { - messageChanged(currentMessage, composeState.parsedMessage, r) + .animation(.spring(), value: isVisible) } } - .onAppear { - currentMessage = composeState.message + } + .onChange(of: composeState.parsedMessage) { parsedMsg in + currentMessage = composeState.message + messageChanged(currentMessage, parsedMsg, selectedRange) + } + .onChange(of: selectedRange) { r in + // This condition is needed to prevent messageChanged called twice, + // because composeState.formattedText triggers later when message changes. + // The condition is only true if position changed without text change + if currentMessage == composeState.message { + messageChanged(currentMessage, composeState.parsedMessage, r) } } + .onAppear { + currentMessage = composeState.message + } } - private var filteredMembers: [GMember] { - let members = m.groupMembers - .filter { m in - let status = m.wrapped.memberStatus - return status != .memLeft && status != .memRemoved && status != .memInvited - } - .sorted { $0.wrapped.memberRole > $1.wrapped.memberRole } + private func filteredMembers() -> [GMember] { let s = mentionName.lowercased() return s.isEmpty - ? members - : members.filter { $0.wrapped.localAliasAndFullName.localizedLowercase.contains(s) } + ? sortedMembers + : sortedMembers.filter { $0.wrapped.localAliasAndFullName.localizedLowercase.contains(s) } } private func messageChanged(_ msg: String, _ parsedMsg: [FormattedText], _ range: NSRange) { @@ -112,7 +109,10 @@ struct GroupMentionsView: View { mentionRange = r mentionMemberId = composeState.mentions[name]?.memberId if !m.membersLoaded { - Task { await m.loadGroupMembers(groupInfo) } + Task { + await m.loadGroupMembers(groupInfo) + sortMembers() + } } return case .none: () // @@ -124,7 +124,10 @@ struct GroupMentionsView: View { mentionName = "" mentionRange = atRange mentionMemberId = nil - Task { await m.loadGroupMembers(groupInfo) } + Task { + await m.loadGroupMembers(groupInfo) + sortMembers() + } return } } @@ -134,6 +137,14 @@ struct GroupMentionsView: View { closeMemberList() } + private func sortMembers() { + sortedMembers = m.groupMembers.filter({ m in + let status = m.wrapped.memberStatus + return status != .memLeft && status != .memRemoved && status != .memInvited + }) + .sorted { $0.wrapped.memberRole > $1.wrapped.memberRole } + } + private func removeUnusedMentions(_ parsedMsg: [FormattedText]) { let usedMentions: Set = Set(parsedMsg.compactMap { ft in if case let .mention(name) = ft.format { name } else { nil } From 5b947b31306f89598267ed820a2420b88906cba7 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Wed, 5 Feb 2025 17:57:04 +0000 Subject: [PATCH 5/5] core: 6.3.0.3 --- simplex-chat.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simplex-chat.cabal b/simplex-chat.cabal index 6a6a0b5549..55b3f11e96 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: 6.3.0.2 +version: 6.3.0.3 category: Web, System, Services, Cryptography homepage: https://github.com/simplex-chat/simplex-chat#readme author: simplex.chat