From 58941973066c9fe130a70d7c387da83a62ff7979 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO <> Date: Tue, 6 Feb 2024 09:10:16 +1100 Subject: [PATCH] WIP: swipe actions for global search screen --- Podfile | 1 + Podfile.lock | 6 +- .../GlobalSearch/GlobalSearchScreen.swift | 226 +++++++++++------- 3 files changed, 142 insertions(+), 91 deletions(-) diff --git a/Podfile b/Podfile index 201db8853..5511ff792 100644 --- a/Podfile +++ b/Podfile @@ -27,6 +27,7 @@ abstract_target 'GlobalDependencies' do pod 'NVActivityIndicatorView' pod 'YYImage/libwebp', git: 'https://github.com/signalapp/YYImage' pod 'DifferenceKit' + pod 'SwipeActions' target 'SessionTests' do inherit! :complete diff --git a/Podfile.lock b/Podfile.lock index f337b4a69..27b444763 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -44,6 +44,7 @@ PODS: - SQLCipher/standard (4.5.3): - SQLCipher/common - SwiftProtobuf (1.5.0) + - SwipeActions (0.3.3) - WebRTC-lib (114.0.0) - xcbeautify (0.17.0) - YapDatabase/SQLCipher (3.1.1): @@ -127,6 +128,7 @@ DEPENDENCIES: - Sodium (from `https://github.com/oxen-io/session-ios-swift-sodium.git`, branch `session-build`) - SQLCipher (~> 4.5.3) - SwiftProtobuf (~> 1.5.0) + - SwipeActions - WebRTC-lib - xcbeautify - YapDatabase/SQLCipher (from `https://github.com/oxen-io/session-ios-yap-database.git`, branch `signal-release`) @@ -147,6 +149,7 @@ SPEC REPOS: - SAMKeychain - SQLCipher - SwiftProtobuf + - SwipeActions - WebRTC-lib - xcbeautify @@ -200,11 +203,12 @@ SPEC CHECKSUMS: Sodium: a7d42cb46e789d2630fa552d35870b416ed055ae SQLCipher: 57fa9f863fa4a3ed9dd3c90ace52315db8c0fdca SwiftProtobuf: 241400280f912735c1e1b9fe675fdd2c6c4d42e2 + SwipeActions: 3c35871b408cab23ea67f3946a650356795250d2 WebRTC-lib: d83df8976fa608b980f1d85796b3de66d60a1953 xcbeautify: 6e2f57af5c3a86d490376d5758030a8dcc201c1b YapDatabase: b418a4baa6906e8028748938f9159807fd039af4 YYImage: f1ddd15ac032a58b78bbed1e012b50302d318331 -PODFILE CHECKSUM: dd814a5a92577bb2a94dac6a1cc482f193721cdf +PODFILE CHECKSUM: 27f8a988cf382c38e480ea914df9d0899bab1ed9 COCOAPODS: 1.15.0 diff --git a/Session/Home/GlobalSearch/GlobalSearchScreen.swift b/Session/Home/GlobalSearch/GlobalSearchScreen.swift index ec5fc42d7..58b502686 100644 --- a/Session/Home/GlobalSearch/GlobalSearchScreen.swift +++ b/Session/Home/GlobalSearch/GlobalSearchScreen.swift @@ -8,6 +8,7 @@ import SessionMessagingKit import SessionUtilitiesKit import SignalUtilitiesKit import SignalCoreKit +import SwipeActions enum SearchSection: Int, Differentiable { case noResults @@ -31,6 +32,7 @@ struct GlobalSearchScreen: View { @State private var readConnection: Atomic = Atomic(nil) @State private var termForCurrentSearchResultSet: String = "" @State private var lastSearchText: String? + @State private var swipeState: SwipeActions.SwipeState = .untouched fileprivate static var defaultSearchResults: [SectionModel] = { let result: [SessionThreadViewModel]? = Storage.shared.read { db -> [SessionThreadViewModel]? in @@ -187,6 +189,50 @@ struct GlobalSearchScreen: View { }() ) } + .addSwipeAction( + edge: .trailing, + state: $swipeState + ) { + Button { + + } label: { + VStack { + Image("icon_bin") + .renderingMode(.template) + .foregroundColor(themeColor: .textPrimary) + Text("TXT_DELETE_TITLE".localized()) + .foregroundColor(themeColor: .textPrimary) + } + } + .frame(width: 60) + .frame(maxHeight: .infinity) + .contentShape(Rectangle()) + .backgroundColor(themeColor: .danger) + } + + + Text("Text") + .addSwipeAction( + edge: .trailing, + state: $swipeState + ) { + Button { + + } label: { + VStack { + Image("icon_bin") + .renderingMode(.template) + .foregroundColor(themeColor: .textPrimary) + Text("TXT_DELETE_TITLE".localized()) + .font(.system(size: Values.mediumFontSize)) + .foregroundColor(themeColor: .textPrimary) + } + } + .frame(width: 100) + .frame(maxHeight: .infinity) + .contentShape(Rectangle()) + .backgroundColor(themeColor: .danger) + } } } } @@ -315,102 +361,102 @@ struct SearchResultCell: View { var action: () -> Void var body: some View { - Button { - action() - } label: { - HStack( - alignment: .center, - spacing: Values.mediumSpacing + HStack( + alignment: .center, + spacing: Values.mediumSpacing + ) { + let size: ProfilePictureView.Size = .list + + ProfilePictureSwiftUI( + size: size, + publicKey: viewModel.threadId, + threadVariant: viewModel.threadVariant, + customImageData: viewModel.openGroupProfilePictureData, + profile: viewModel.profile, + additionalProfile: viewModel.additionalProfile + ) + .frame( + width: size.viewSize, + height: size.viewSize, + alignment: .topLeading + ) + .padding(.vertical, Values.smallSpacing) + + VStack( + alignment: .leading, + spacing: Values.verySmallSpacing ) { - let size: ProfilePictureView.Size = .list - - ProfilePictureSwiftUI( - size: size, - publicKey: viewModel.threadId, - threadVariant: viewModel.threadVariant, - customImageData: viewModel.openGroupProfilePictureData, - profile: viewModel.profile, - additionalProfile: viewModel.additionalProfile - ) - .frame( - width: size.viewSize, - height: size.viewSize, - alignment: .topLeading - ) - .padding(.vertical, Values.smallSpacing) - - VStack( - alignment: .leading, - spacing: Values.verySmallSpacing - ) { - HStack { - Text(viewModel.displayName) - .bold() - .font(.system(size: Values.mediumFontSize)) - .foregroundColor(themeColor: .textPrimary) - - Spacer() - - if searchSection == .messages { - Text(viewModel.lastInteractionDate.formattedForDisplay) - .font(.system(size: Values.smallFontSize)) - .foregroundColor(themeColor: .textSecondary) - .opacity(Values.lowOpacity) - } - } + HStack { + Text(viewModel.displayName) + .bold() + .font(.system(size: Values.mediumFontSize)) + .foregroundColor(themeColor: .textPrimary) - if let textColor: UIColor = ThemeManager.currentTheme.color(for: .textPrimary) { - let maybeSnippet: NSAttributedString? = { - switch searchSection { - case .noResults, .defaultContacts: - return nil - case .contactsAndGroups: - switch viewModel.threadVariant { - case .contact, .community: return nil - case .legacyGroup, .group: - return self.getHighlightedSnippet( - content: (viewModel.threadMemberNames ?? ""), - currentUserPublicKey: viewModel.currentUserPublicKey, - currentUserBlinded15PublicKey: viewModel.currentUserBlinded15PublicKey, - currentUserBlinded25PublicKey: viewModel.currentUserBlinded25PublicKey, - searchText: searchText.lowercased(), - fontSize: Values.smallFontSize, - textColor: textColor - ) - } - case .messages: - return self.getHighlightedSnippet( - content: Interaction.previewText( - variant: (viewModel.interactionVariant ?? .standardIncoming), - body: viewModel.interactionBody, - authorDisplayName: viewModel.authorName(for: .contact), - attachmentDescriptionInfo: viewModel.interactionAttachmentDescriptionInfo, - attachmentCount: viewModel.interactionAttachmentCount, - isOpenGroupInvitation: (viewModel.interactionIsOpenGroupInvitation == true) - ), - authorName: (viewModel.authorId != viewModel.currentUserPublicKey ? - viewModel.authorName(for: .contact) : - nil - ), - currentUserPublicKey: viewModel.currentUserPublicKey, - currentUserBlinded15PublicKey: viewModel.currentUserBlinded15PublicKey, - currentUserBlinded25PublicKey: viewModel.currentUserBlinded25PublicKey, - searchText: searchText.lowercased(), - fontSize: Values.smallFontSize, - textColor: textColor - ) - } - }() - - if let snippet = maybeSnippet { - AttributedText(snippet).lineLimit(1) - } + Spacer() + + if searchSection == .messages { + Text(viewModel.lastInteractionDate.formattedForDisplay) + .font(.system(size: Values.smallFontSize)) + .foregroundColor(themeColor: .textSecondary) + .opacity(Values.lowOpacity) } } - Spacer(minLength: 0) + if let textColor: UIColor = ThemeManager.currentTheme.color(for: .textPrimary) { + let maybeSnippet: NSAttributedString? = { + switch searchSection { + case .noResults, .defaultContacts: + return nil + case .contactsAndGroups: + switch viewModel.threadVariant { + case .contact, .community: return nil + case .legacyGroup, .group: + return self.getHighlightedSnippet( + content: (viewModel.threadMemberNames ?? ""), + currentUserPublicKey: viewModel.currentUserPublicKey, + currentUserBlinded15PublicKey: viewModel.currentUserBlinded15PublicKey, + currentUserBlinded25PublicKey: viewModel.currentUserBlinded25PublicKey, + searchText: searchText.lowercased(), + fontSize: Values.smallFontSize, + textColor: textColor + ) + } + case .messages: + return self.getHighlightedSnippet( + content: Interaction.previewText( + variant: (viewModel.interactionVariant ?? .standardIncoming), + body: viewModel.interactionBody, + authorDisplayName: viewModel.authorName(for: .contact), + attachmentDescriptionInfo: viewModel.interactionAttachmentDescriptionInfo, + attachmentCount: viewModel.interactionAttachmentCount, + isOpenGroupInvitation: (viewModel.interactionIsOpenGroupInvitation == true) + ), + authorName: (viewModel.authorId != viewModel.currentUserPublicKey ? + viewModel.authorName(for: .contact) : + nil + ), + currentUserPublicKey: viewModel.currentUserPublicKey, + currentUserBlinded15PublicKey: viewModel.currentUserBlinded15PublicKey, + currentUserBlinded25PublicKey: viewModel.currentUserBlinded25PublicKey, + searchText: searchText.lowercased(), + fontSize: Values.smallFontSize, + textColor: textColor + ) + } + }() + + if let snippet = maybeSnippet { + AttributedText(snippet).lineLimit(1) + } + } } - .padding(.leading, Values.mediumSpacing) + + Spacer(minLength: 0) + } + .padding(.leading, Values.mediumSpacing) + .contentShape(Rectangle()) + .onTapGesture { + action() } }