From b3378992ed6bb40b9b5c251c867c38cad9550152 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 24 Feb 2023 17:03:45 +1100 Subject: [PATCH 01/32] WIP: feat: modify conversation swap actions --- Session.xcodeproj/project.pbxproj | 4 ++ Session/Home/HomeVC.swift | 16 +++++++ .../Shared/UIContextualAction+Session.swift | 42 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 Session/Shared/UIContextualAction+Session.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 3f59874b7..561e309c9 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -113,6 +113,7 @@ 7B4C75CB26B37E0F0000AC89 /* UnsendRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4C75CA26B37E0F0000AC89 /* UnsendRequest.swift */; }; 7B4C75CD26BB92060000AC89 /* DeletedMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */; }; 7B50D64D28AC7CF80086CCEC /* silence.aiff in Resources */ = {isa = PBXBuildFile; fileRef = 7B50D64C28AC7CF80086CCEC /* silence.aiff */; }; + 7B521E0629A87CEA00C3C36A /* UIContextualAction+Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B521E0529A87CEA00C3C36A /* UIContextualAction+Session.swift */; }; 7B7037432834B81F000DCF35 /* ReactionContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7037422834B81F000DCF35 /* ReactionContainerView.swift */; }; 7B7037452834BCC0000DCF35 /* ReactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7037442834BCC0000DCF35 /* ReactionView.swift */; }; 7B7CB18E270D066F0079FF93 /* IncomingCallBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7CB18D270D066F0079FF93 /* IncomingCallBanner.swift */; }; @@ -1181,6 +1182,7 @@ 7B4C75CA26B37E0F0000AC89 /* UnsendRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsendRequest.swift; sourceTree = ""; }; 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedMessageView.swift; sourceTree = ""; }; 7B50D64C28AC7CF80086CCEC /* silence.aiff */ = {isa = PBXFileReference; lastKnownFileType = audio.aiff; path = silence.aiff; sourceTree = ""; }; + 7B521E0529A87CEA00C3C36A /* UIContextualAction+Session.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIContextualAction+Session.swift"; sourceTree = ""; }; 7B7037422834B81F000DCF35 /* ReactionContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionContainerView.swift; sourceTree = ""; }; 7B7037442834BCC0000DCF35 /* ReactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionView.swift; sourceTree = ""; }; 7B7CB18D270D066F0079FF93 /* IncomingCallBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncomingCallBanner.swift; sourceTree = ""; }; @@ -2582,6 +2584,7 @@ FD52090828B59411006098F6 /* ScreenLockUI.swift */, FD37EA0828AA2D27003AE748 /* SessionTableViewModel.swift */, FD37EA0628AA2CCA003AE748 /* SessionTableViewController.swift */, + 7B521E0529A87CEA00C3C36A /* UIContextualAction+Session.swift */, ); path = Shared; sourceTree = ""; @@ -5712,6 +5715,7 @@ 4539B5861F79348F007141FF /* PushRegistrationManager.swift in Sources */, B8041A9525C8FA1D003C2166 /* MediaLoaderView.swift in Sources */, 45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */, + 7B521E0629A87CEA00C3C36A /* UIContextualAction+Session.swift in Sources */, 7B9F71D42852EEE2006DFE7B /* Emoji+Name.swift in Sources */, 4CA46F4C219CCC630038ABDE /* CaptionView.swift in Sources */, C328253025CA55370062D0A7 /* ContextMenuWindow.swift in Sources */, diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index 84351d6ca..3ed8a59ca 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -618,6 +618,20 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi return true } + func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { + let section: HomeViewModel.SectionModel = self.viewModel.threadData[indexPath.section] + let unswipeAnimationDelay: DispatchTimeInterval = .milliseconds(500) + + switch section.model { + case .messageRequests: + return nil + case .threads: + + return UISwipeActionsConfiguration(actions: [ ]) + default: return nil + } + } + func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let section: HomeViewModel.SectionModel = self.viewModel.threadData[indexPath.section] let unswipeAnimationDelay: DispatchTimeInterval = .milliseconds(500) @@ -665,6 +679,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi self?.present(confirmationModal, animated: true, completion: nil) } delete.themeBackgroundColor = .conversationButton_swipeDestructive + delete.setupSessionStyle(with: UIImage(systemName: "trash")) let pin: UIContextualAction = UIContextualAction( style: .normal, @@ -688,6 +703,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi } } pin.themeBackgroundColor = .conversationButton_swipeTertiary + pin.setupSessionStyle(with: UIImage(systemName: "pin")) guard threadViewModel.threadVariant == .contact && !threadViewModel.threadIsNoteToSelf else { return UISwipeActionsConfiguration(actions: [ delete, pin ]) diff --git a/Session/Shared/UIContextualAction+Session.swift b/Session/Shared/UIContextualAction+Session.swift new file mode 100644 index 000000000..64e01217c --- /dev/null +++ b/Session/Shared/UIContextualAction+Session.swift @@ -0,0 +1,42 @@ +// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. + +import UIKit + +extension UIContextualAction { + + func setupSessionStyle(with image: UIImage?) { + guard let title = self.title, let image = image else { + self.image = image + return + } + + let text = NSMutableAttributedString(string: "") + let attachment = NSTextAttachment() + attachment.image = image.withTintColor(.white) + text.append(NSAttributedString(attachment: attachment)) + text.append( + NSAttributedString( + string: "\n\(title)", + attributes: [ + .font : UIFont.systemFont(ofSize: Values.smallFontSize), + .foregroundColor : UIColor.white + ] + ) + ) + + let label = UILabel(frame: CGRect(x: 0, y: 0, width: 50, height: 50)) + label.textAlignment = .center + label.numberOfLines = 2 + label.attributedText = text + + let renderer = UIGraphicsImageRenderer(bounds: label.bounds) + let renderedImage = renderer.image { context in + label.layer.render(in: context.cgContext) + } + if let cgImage = renderedImage.cgImage { + let finalImage = UIImage(cgImage: cgImage, scale: UIScreen.main.scale, orientation: .up) + self.image = finalImage + self.title = nil + } + } +} From 9112231f66e8285f878ebc23d41df91762edf540 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Mon, 27 Feb 2023 11:37:25 +1100 Subject: [PATCH 02/32] WIP --- Session.xcodeproj/project.pbxproj | 8 +- Session/Home/HomeVC.swift | 23 ++- .../Shared/UIContextualAction+Session.swift | 42 ---- .../UIContextualAction+Theming.swift | 181 ++++++++++++++++++ .../General/Dictionary+Utilities.swift | 6 + 5 files changed, 209 insertions(+), 51 deletions(-) delete mode 100644 Session/Shared/UIContextualAction+Session.swift create mode 100644 SessionUIKit/Utilities/UIContextualAction+Theming.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 561e309c9..358eaf7e4 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -109,11 +109,11 @@ 7B1D74AA27BCC16E0030B423 /* NSENotificationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1D74A927BCC16E0030B423 /* NSENotificationPresenter.swift */; }; 7B1D74AC27BDE7510030B423 /* Promise+Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1D74AB27BDE7510030B423 /* Promise+Timeout.swift */; }; 7B1D74B027C365960030B423 /* Timer+MainThread.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1D74AF27C365960030B423 /* Timer+MainThread.swift */; }; + 7B2E985829AC227C001792D7 /* UIContextualAction+Theming.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2E985729AC227C001792D7 /* UIContextualAction+Theming.swift */; }; 7B46AAAF28766DF4001AF2DC /* AllMediaViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B46AAAE28766DF4001AF2DC /* AllMediaViewController.swift */; }; 7B4C75CB26B37E0F0000AC89 /* UnsendRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4C75CA26B37E0F0000AC89 /* UnsendRequest.swift */; }; 7B4C75CD26BB92060000AC89 /* DeletedMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */; }; 7B50D64D28AC7CF80086CCEC /* silence.aiff in Resources */ = {isa = PBXBuildFile; fileRef = 7B50D64C28AC7CF80086CCEC /* silence.aiff */; }; - 7B521E0629A87CEA00C3C36A /* UIContextualAction+Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B521E0529A87CEA00C3C36A /* UIContextualAction+Session.swift */; }; 7B7037432834B81F000DCF35 /* ReactionContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7037422834B81F000DCF35 /* ReactionContainerView.swift */; }; 7B7037452834BCC0000DCF35 /* ReactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7037442834BCC0000DCF35 /* ReactionView.swift */; }; 7B7CB18E270D066F0079FF93 /* IncomingCallBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7CB18D270D066F0079FF93 /* IncomingCallBanner.swift */; }; @@ -1178,11 +1178,11 @@ 7B1D74AB27BDE7510030B423 /* Promise+Timeout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Promise+Timeout.swift"; sourceTree = ""; }; 7B1D74AF27C365960030B423 /* Timer+MainThread.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Timer+MainThread.swift"; sourceTree = ""; }; 7B2DB2AD26F1B0FF0035B509 /* si */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = si; path = si.lproj/Localizable.strings; sourceTree = ""; }; + 7B2E985729AC227C001792D7 /* UIContextualAction+Theming.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIContextualAction+Theming.swift"; sourceTree = ""; }; 7B46AAAE28766DF4001AF2DC /* AllMediaViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllMediaViewController.swift; sourceTree = ""; }; 7B4C75CA26B37E0F0000AC89 /* UnsendRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsendRequest.swift; sourceTree = ""; }; 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedMessageView.swift; sourceTree = ""; }; 7B50D64C28AC7CF80086CCEC /* silence.aiff */ = {isa = PBXFileReference; lastKnownFileType = audio.aiff; path = silence.aiff; sourceTree = ""; }; - 7B521E0529A87CEA00C3C36A /* UIContextualAction+Session.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIContextualAction+Session.swift"; sourceTree = ""; }; 7B7037422834B81F000DCF35 /* ReactionContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionContainerView.swift; sourceTree = ""; }; 7B7037442834BCC0000DCF35 /* ReactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionView.swift; sourceTree = ""; }; 7B7CB18D270D066F0079FF93 /* IncomingCallBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncomingCallBanner.swift; sourceTree = ""; }; @@ -2584,7 +2584,6 @@ FD52090828B59411006098F6 /* ScreenLockUI.swift */, FD37EA0828AA2D27003AE748 /* SessionTableViewModel.swift */, FD37EA0628AA2CCA003AE748 /* SessionTableViewController.swift */, - 7B521E0529A87CEA00C3C36A /* UIContextualAction+Session.swift */, ); path = Shared; sourceTree = ""; @@ -2819,6 +2818,7 @@ B885D5F52334A32100EE0D8E /* UIView+Constraints.swift */, C33100272559000A00070591 /* UIView+Utilities.swift */, FD71161F28D97ABC00B47552 /* UIImage+Tinting.swift */, + 7B2E985729AC227C001792D7 /* UIContextualAction+Theming.swift */, ); path = Utilities; sourceTree = ""; @@ -5142,6 +5142,7 @@ FD37E9D528A1FCE8003AE748 /* Theme+OceanLight.swift in Sources */, FD37E9C828A1D73F003AE748 /* Theme+Colors.swift in Sources */, FD37EA0128A60473003AE748 /* UIKit+Theme.swift in Sources */, + 7B2E985829AC227C001792D7 /* UIContextualAction+Theming.swift in Sources */, FD37E9CF28A1EB1B003AE748 /* Theme.swift in Sources */, C331FFB92558FA8D00070591 /* UIView+Constraints.swift in Sources */, FD37E9F628A5F106003AE748 /* Configuration.swift in Sources */, @@ -5715,7 +5716,6 @@ 4539B5861F79348F007141FF /* PushRegistrationManager.swift in Sources */, B8041A9525C8FA1D003C2166 /* MediaLoaderView.swift in Sources */, 45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */, - 7B521E0629A87CEA00C3C36A /* UIContextualAction+Session.swift in Sources */, 7B9F71D42852EEE2006DFE7B /* Emoji+Name.swift in Sources */, 4CA46F4C219CCC630038ABDE /* CaptionView.swift in Sources */, C328253025CA55370062D0A7 /* ContextMenuWindow.swift in Sources */, diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index 3ed8a59ca..522a54db9 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -626,7 +626,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi case .messageRequests: return nil case .threads: - + let threadViewModel: SessionThreadViewModel = section.elements[indexPath.row] return UISwipeActionsConfiguration(actions: [ ]) default: return nil } @@ -649,8 +649,15 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi case .threads: let threadViewModel: SessionThreadViewModel = section.elements[indexPath.row] let delete: UIContextualAction = UIContextualAction( - style: .destructive, - title: "TXT_DELETE_TITLE".localized() + title: "TXT_DELETE_TITLE".localized(), + icon: UIImage(named: "icon_bin"), + iconHeight: 5, + themeTintColor: .textPrimary, + themeBackgroundColor: .conversationButton_swipeDestructive, + side: .trailing, + actionIndex: 2, + indexPath: indexPath, + tableView: tableView ) { [weak self] _, _, completionHandler in let confirmationModal: ConfirmationModal = ConfirmationModal( info: ConfirmationModal.Info( @@ -679,7 +686,6 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi self?.present(confirmationModal, animated: true, completion: nil) } delete.themeBackgroundColor = .conversationButton_swipeDestructive - delete.setupSessionStyle(with: UIImage(systemName: "trash")) let pin: UIContextualAction = UIContextualAction( style: .normal, @@ -703,7 +709,6 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi } } pin.themeBackgroundColor = .conversationButton_swipeTertiary - pin.setupSessionStyle(with: UIImage(systemName: "pin")) guard threadViewModel.threadVariant == .contact && !threadViewModel.threadIsNoteToSelf else { return UISwipeActionsConfiguration(actions: [ delete, pin ]) @@ -749,6 +754,14 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi } } + func tableView(_ tableView: UITableView, willBeginEditingRowAt indexPath: IndexPath) { + UIContextualAction.willBeginEditing(indexPath: indexPath, tableView: tableView) + } + + func tableView(_ tableView: UITableView, didEndEditingRowAt indexPath: IndexPath?) { + UIContextualAction.didEndEditing(indexPath: indexPath, tableView: tableView) + } + // MARK: - Interaction func handleContinueButtonTapped(from seedReminderView: SeedReminderView) { diff --git a/Session/Shared/UIContextualAction+Session.swift b/Session/Shared/UIContextualAction+Session.swift deleted file mode 100644 index 64e01217c..000000000 --- a/Session/Shared/UIContextualAction+Session.swift +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. - -import UIKit - -extension UIContextualAction { - - func setupSessionStyle(with image: UIImage?) { - guard let title = self.title, let image = image else { - self.image = image - return - } - - let text = NSMutableAttributedString(string: "") - let attachment = NSTextAttachment() - attachment.image = image.withTintColor(.white) - text.append(NSAttributedString(attachment: attachment)) - text.append( - NSAttributedString( - string: "\n\(title)", - attributes: [ - .font : UIFont.systemFont(ofSize: Values.smallFontSize), - .foregroundColor : UIColor.white - ] - ) - ) - - let label = UILabel(frame: CGRect(x: 0, y: 0, width: 50, height: 50)) - label.textAlignment = .center - label.numberOfLines = 2 - label.attributedText = text - - let renderer = UIGraphicsImageRenderer(bounds: label.bounds) - let renderedImage = renderer.image { context in - label.layer.render(in: context.cgContext) - } - if let cgImage = renderedImage.cgImage { - let finalImage = UIImage(cgImage: cgImage, scale: UIScreen.main.scale, orientation: .up) - self.image = finalImage - self.title = nil - } - } -} diff --git a/SessionUIKit/Utilities/UIContextualAction+Theming.swift b/SessionUIKit/Utilities/UIContextualAction+Theming.swift new file mode 100644 index 000000000..99e563e97 --- /dev/null +++ b/SessionUIKit/Utilities/UIContextualAction+Theming.swift @@ -0,0 +1,181 @@ +// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. + +import UIKit +import SessionUtilitiesKit + +public extension UIContextualAction { + private static var lookupMap: Atomic<[Int: [String: [Int: ThemeValue]]]> = Atomic([:]) + + enum Side: Int { + case leading + case trailing + + func key(for indexPath: IndexPath) -> String { + return "\(indexPath.section)-\(indexPath.row)-\(rawValue)" + } + + init?(for view: UIView) { + guard view.frame.minX == 0 else { + self = .trailing + return + } + + self = .leading + } + } + + convenience init( + title: String? = nil, + icon: UIImage? = nil, + iconHeight: CGFloat = Values.mediumFontSize, + themeTintColor: ThemeValue = .textPrimary, + themeBackgroundColor: ThemeValue, + side: Side, + actionIndex: Int, + indexPath: IndexPath, + tableView: UITableView, + handler: @escaping UIContextualAction.Handler + ) { + self.init(style: .normal, title: title, handler: handler) + self.image = UIContextualAction + .imageWith( + title: title, + icon: icon, + iconHeight: iconHeight, + themeTintColor: themeTintColor + )? + .withRenderingMode(.alwaysTemplate) + self.themeBackgroundColor = themeBackgroundColor + + UIContextualAction.lookupMap.mutate { + $0[tableView.hashValue] = ($0[tableView.hashValue] ?? [:]) + .setting( + side.key(for: indexPath), + (($0[tableView.hashValue] ?? [:])[side.key(for: indexPath)] ?? [:]) + .setting(actionIndex, themeTintColor) + ) + } + } + + private static func imageWith( + title: String?, + icon: UIImage?, + iconHeight: CGFloat, + themeTintColor: ThemeValue + ) -> UIImage? { + let stackView: UIStackView = UIStackView() + stackView.axis = .vertical + stackView.alignment = .center + stackView.spacing = 3 + + if let icon: UIImage = icon { + let aspectRatio: CGFloat = (icon.size.width / icon.size.height) + let imageView: UIImageView = UIImageView(image: icon) + imageView.frame = CGRect(x: 0, y: 0, width: (iconHeight * aspectRatio), height: iconHeight) + imageView.contentMode = .scaleAspectFit + imageView.themeTintColor = themeTintColor + stackView.addArrangedSubview(imageView) + } + + if let title: String = title { + let label: UILabel = UILabel() + label.font = .systemFont(ofSize: Values.verySmallFontSize) + label.text = title + label.textAlignment = .center + label.themeTextColor = themeTintColor + label.minimumScaleFactor = 0.75 + label.numberOfLines = (title.components(separatedBy: " ").count > 1 ? 2 : 1) + label.frame = CGRect( + origin: .zero, + // Note: It looks like there is a semi-max width of 68px for images in the swipe actions + // if the image ends up larger then there an odd behaviour can occur where 8/10 times the + // image is scaled down to fit, but ocassionally (primarily if you hide the action and + // immediately swipe to show it again once the cell hits the edge of the screen) the image + // won't be scaled down but will be full size - appearing as if two different images are used + size: label.sizeThatFits(CGSize(width: 68, height: 999)) + ) + label.set(.width, to: label.frame.width) + + stackView.addArrangedSubview(label) + } + + stackView.frame = CGRect( + origin: .zero, + size: stackView.systemLayoutSizeFitting(CGSize(width: 999, height: 999)) + ) + + // Based on https://stackoverflow.com/a/41288197/1118398 + let renderFormat: UIGraphicsImageRendererFormat = UIGraphicsImageRendererFormat() + renderFormat.scale = UIScreen.main.scale + + let renderer: UIGraphicsImageRenderer = UIGraphicsImageRenderer( + size: stackView.bounds.size, + format: renderFormat + ) + return renderer.image { rendererContext in + stackView.layer.render(in: rendererContext.cgContext) + } + } + + private static func firstSubviewOfType(in superview: UIView) -> T? { + guard !(superview is T) else { return superview as? T } + guard !superview.subviews.isEmpty else { return nil } + + for subview in superview.subviews { + if let result: T = firstSubviewOfType(in: subview) { + return result + } + } + + return nil + } + + static func willBeginEditing(indexPath: IndexPath, tableView: UITableView) { + guard + let targetCell: UITableViewCell = tableView.cellForRow(at: indexPath), + targetCell.superview != tableView, + let targetSuperview: UIView = targetCell.superview? + .subviews + .filter({ $0 != targetCell }) + .first, + let side: Side = Side(for: targetSuperview), + let themeMap: [Int: ThemeValue] = UIContextualAction.lookupMap.wrappedValue + .getting(tableView.hashValue)? + .getting(side.key(for: indexPath)), + targetSuperview.subviews.count == themeMap.count + else { return } + + let targetViews: [UIImageView] = targetSuperview.subviews + .compactMap { subview in firstSubviewOfType(in: subview) } + + guard targetViews.count == themeMap.count else { return } + + // Set the imageView and background colours (so they change correctly when the theme changes) + targetViews.enumerated().forEach { index, targetView in + guard let themeTintColor: ThemeValue = themeMap[index] else { return } + + targetView.themeTintColor = themeTintColor + } + } + + static func didEndEditing(indexPath: IndexPath?, tableView: UITableView) { + guard let indexPath: IndexPath = indexPath else { return } + + let leadingKey: String = Side.leading.key(for: indexPath) + let trailingKey: String = Side.trailing.key(for: indexPath) + + guard + UIContextualAction.lookupMap.wrappedValue[tableView.hashValue]?[leadingKey] != nil || + UIContextualAction.lookupMap.wrappedValue[tableView.hashValue]?[trailingKey] != nil + else { return } + + UIContextualAction.lookupMap.mutate { + $0[tableView.hashValue]?[leadingKey] = nil + $0[tableView.hashValue]?[trailingKey] = nil + + if $0[tableView.hashValue]?.isEmpty == true { + $0[tableView.hashValue] = nil + } + } + } +} diff --git a/SessionUtilitiesKit/General/Dictionary+Utilities.swift b/SessionUtilitiesKit/General/Dictionary+Utilities.swift index d05bfe761..694844492 100644 --- a/SessionUtilitiesKit/General/Dictionary+Utilities.swift +++ b/SessionUtilitiesKit/General/Dictionary+Utilities.swift @@ -34,6 +34,12 @@ public extension Dictionary { return self[key] } + func getting(_ key: Key?) -> Value? { + guard let key: Key = key else { return nil } + + return self[key] + } + func setting(_ key: Key?, _ value: Value?) -> [Key: Value] { guard let key: Key = key else { return self } From 612be697efd036506894fa19de0670151ad29116 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Mon, 27 Feb 2023 15:42:48 +1100 Subject: [PATCH 03/32] feat: swap action leave/delete, pin, mute/unmute, mark read/unread --- Session/Home/HomeVC.swift | 241 +++++++++++++----- .../Session/icon_leave.imageset/Contents.json | 12 + .../Session/icon_leave.imageset/Group 21.pdf | 115 +++++++++ .../icon_mark_read.imageset/Contents.json | 12 + .../icon_mark_read.imageset/Vector.pdf | 115 +++++++++ .../icon_mark_unread.imageset/Contents.json | 12 + .../icon_mark_unread.imageset/Group 1.pdf | 119 +++++++++ .../Session/icon_mute.imageset/Contents.json | 12 + .../Session/icon_mute.imageset/Group (1).pdf | 108 ++++++++ .../Session/icon_pin.imageset/Contents.json | 12 + .../Session/icon_pin.imageset/Group.pdf | 108 ++++++++ .../Translations/de.lproj/Localizable.strings | 7 + .../Translations/en.lproj/Localizable.strings | 7 + .../Translations/es.lproj/Localizable.strings | 7 + .../Translations/fa.lproj/Localizable.strings | 7 + .../Translations/fi.lproj/Localizable.strings | 7 + .../Translations/fr.lproj/Localizable.strings | 7 + .../Translations/hi.lproj/Localizable.strings | 7 + .../Translations/hr.lproj/Localizable.strings | 7 + .../id-ID.lproj/Localizable.strings | 7 + .../Translations/it.lproj/Localizable.strings | 7 + .../Translations/ja.lproj/Localizable.strings | 7 + .../Translations/nl.lproj/Localizable.strings | 7 + .../Translations/pl.lproj/Localizable.strings | 7 + .../pt_BR.lproj/Localizable.strings | 7 + .../Translations/ru.lproj/Localizable.strings | 7 + .../Translations/si.lproj/Localizable.strings | 7 + .../Translations/sk.lproj/Localizable.strings | 7 + .../Translations/sv.lproj/Localizable.strings | 7 + .../Translations/th.lproj/Localizable.strings | 7 + .../vi-VN.lproj/Localizable.strings | 7 + .../zh-Hant.lproj/Localizable.strings | 7 + .../zh_CN.lproj/Localizable.strings | 7 + Session/Shared/FullConversationCell.swift | 32 ++- .../UIContextualAction+Theming.swift | 11 +- 35 files changed, 985 insertions(+), 78 deletions(-) create mode 100644 Session/Meta/Images.xcassets/Session/icon_leave.imageset/Contents.json create mode 100644 Session/Meta/Images.xcassets/Session/icon_leave.imageset/Group 21.pdf create mode 100644 Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Contents.json create mode 100644 Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Vector.pdf create mode 100644 Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Contents.json create mode 100644 Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Group 1.pdf create mode 100644 Session/Meta/Images.xcassets/Session/icon_mute.imageset/Contents.json create mode 100644 Session/Meta/Images.xcassets/Session/icon_mute.imageset/Group (1).pdf create mode 100644 Session/Meta/Images.xcassets/Session/icon_pin.imageset/Contents.json create mode 100644 Session/Meta/Images.xcassets/Session/icon_pin.imageset/Group.pdf diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index 522a54db9..c97c01ef2 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -627,7 +627,45 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi return nil case .threads: let threadViewModel: SessionThreadViewModel = section.elements[indexPath.row] - return UISwipeActionsConfiguration(actions: [ ]) + let hasUnread: Bool = (threadViewModel.threadUnreadCount ?? 0) > 0 + let mark: UIContextualAction = UIContextualAction( + title: ((hasUnread) ? "mark_read_button_text".localized() : "mark_unread_button_text".localized()), + icon: ((hasUnread) ? UIImage(named: "icon_mark_read") : UIImage(named: "icon_mark_unread")), + iconHeight: Values.mediumFontSize, + themeTintColor: .textPrimary, + themeBackgroundColor: .conversationButton_swipeDestructive, + side: .trailing, + actionIndex: 0, + indexPath: indexPath, + tableView: tableView + ) { _, _, completionHandler in + (tableView.cellForRow(at: indexPath) as? FullConversationCell)?.optimisticUpdate( + hasUnread: !hasUnread + ) + completionHandler(true) + + // Delay the change to give the cell "unswipe" animation some time to complete + DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + unswipeAnimationDelay) { + Storage.shared.writeAsync { db in + if hasUnread { + try Interaction.markAsRead( + db, + interactionId: threadViewModel.interactionId, + threadId: threadViewModel.threadId, + threadVariant: threadViewModel.threadVariant, + includingOlder: true, + trySendReadReceipt: true + ) + } else { + try Interaction + .filter(id: threadViewModel.interactionId) + .updateAll(db, Interaction.Columns.wasRead.set(to: false)) + } + } + } + } + mark.themeBackgroundColor = .conversationButton_swipeSecondary + return UISwipeActionsConfiguration(actions: [ mark ]) default: return nil } } @@ -648,51 +686,17 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi case .threads: let threadViewModel: SessionThreadViewModel = section.elements[indexPath.row] - let delete: UIContextualAction = UIContextualAction( - title: "TXT_DELETE_TITLE".localized(), - icon: UIImage(named: "icon_bin"), - iconHeight: 5, + + let pin: UIContextualAction = UIContextualAction( + title: (threadViewModel.threadIsPinned ? "UNPIN_BUTTON_TEXT".localized() : "PIN_BUTTON_TEXT".localized()), + icon: UIImage(named: "icon_pin"), + iconHeight: Values.mediumFontSize, themeTintColor: .textPrimary, themeBackgroundColor: .conversationButton_swipeDestructive, side: .trailing, - actionIndex: 2, + actionIndex: 0, indexPath: indexPath, tableView: tableView - ) { [weak self] _, _, completionHandler in - let confirmationModal: ConfirmationModal = ConfirmationModal( - info: ConfirmationModal.Info( - title: "CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE".localized(), - explanation: (threadViewModel.currentUserIsClosedGroupAdmin == true ? - "admin_group_leave_warning".localized() : - "CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE".localized() - ), - confirmTitle: "TXT_DELETE_TITLE".localized(), - confirmStyle: .danger, - cancelStyle: .alert_text, - dismissOnConfirm: true, - onConfirm: { [weak self] _ in - self?.viewModel.delete( - threadId: threadViewModel.threadId, - threadVariant: threadViewModel.threadVariant - ) - self?.dismiss(animated: true, completion: nil) - - completionHandler(true) - }, - afterClosed: { completionHandler(false) } - ) - ) - - self?.present(confirmationModal, animated: true, completion: nil) - } - delete.themeBackgroundColor = .conversationButton_swipeDestructive - - let pin: UIContextualAction = UIContextualAction( - style: .normal, - title: (threadViewModel.threadIsPinned ? - "UNPIN_BUTTON_TEXT".localized() : - "PIN_BUTTON_TEXT".localized() - ) ) { _, _, completionHandler in (tableView.cellForRow(at: indexPath) as? FullConversationCell)?.optimisticUpdate( isPinned: !threadViewModel.threadIsPinned @@ -709,47 +713,154 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi } } pin.themeBackgroundColor = .conversationButton_swipeTertiary - - guard threadViewModel.threadVariant == .contact && !threadViewModel.threadIsNoteToSelf else { - return UISwipeActionsConfiguration(actions: [ delete, pin ]) - } - - let block: UIContextualAction = UIContextualAction( - style: .normal, - title: (threadViewModel.threadIsBlocked == true ? - "BLOCK_LIST_UNBLOCK_BUTTON".localized() : - "BLOCK_LIST_BLOCK_BUTTON".localized() - ) + + let mute: UIContextualAction = UIContextualAction( + title: ((threadViewModel.threadMutedUntilTimestamp != nil) ? "unmute_button_text".localized() : "mute_button_text".localized()), + icon: UIImage(named: "icon_mute"), + iconHeight: Values.mediumFontSize, + themeTintColor: .textPrimary, + themeBackgroundColor: .conversationButton_swipeDestructive, + side: .trailing, + actionIndex: 1, + indexPath: indexPath, + tableView: tableView ) { _, _, completionHandler in (tableView.cellForRow(at: indexPath) as? FullConversationCell)?.optimisticUpdate( - isBlocked: (threadViewModel.threadIsBlocked == false) + isMuted: !(threadViewModel.threadMutedUntilTimestamp != nil) ) completionHandler(true) // Delay the change to give the cell "unswipe" animation some time to complete DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + unswipeAnimationDelay) { Storage.shared.writeAsync { db in - try Contact + let currentValue: TimeInterval? = try SessionThread + .filter(id: threadViewModel.threadId) + .select(.mutedUntilTimestamp) + .asRequest(of: TimeInterval.self) + .fetchOne(db) + + try SessionThread .filter(id: threadViewModel.threadId) .updateAll( db, - Contact.Columns.isBlocked.set( - to: (threadViewModel.threadIsBlocked == false ? - true: - false + SessionThread.Columns.mutedUntilTimestamp.set( + to: (currentValue == nil ? + Date.distantFuture.timeIntervalSince1970 : + nil ) ) ) - - try MessageSender.syncConfiguration(db, forceSyncNow: true) - .retainUntilComplete() } } } - block.themeBackgroundColor = .conversationButton_swipeSecondary - - return UISwipeActionsConfiguration(actions: [ delete, block, pin ]) - + mute.themeBackgroundColor = .conversationButton_swipeSecondary + + switch threadViewModel.threadVariant { + case .contact: + let delete: UIContextualAction = UIContextualAction( + title: "TXT_DELETE_TITLE".localized(), + icon: UIImage(named: "icon_bin"), + iconHeight: Values.smallFontSize, + themeTintColor: .textPrimary, + themeBackgroundColor: .conversationButton_swipeDestructive, + side: .trailing, + actionIndex: 2, + indexPath: indexPath, + tableView: tableView + ) { [weak self] _, _, completionHandler in + let confirmationModal: ConfirmationModal = ConfirmationModal( + info: ConfirmationModal.Info( + title: "CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE".localized(), + explanation: (threadViewModel.currentUserIsClosedGroupAdmin == true ? + "admin_group_leave_warning".localized() : + "CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE".localized() + ), + confirmTitle: "TXT_DELETE_TITLE".localized(), + confirmStyle: .danger, + cancelStyle: .alert_text, + dismissOnConfirm: true, + onConfirm: { [weak self] _ in + self?.viewModel.delete( + threadId: threadViewModel.threadId, + threadVariant: threadViewModel.threadVariant + ) + self?.dismiss(animated: true, completion: nil) + + completionHandler(true) + }, + afterClosed: { completionHandler(false) } + ) + ) + + self?.present(confirmationModal, animated: true, completion: nil) + } + delete.themeBackgroundColor = .conversationButton_swipeDestructive + + return UISwipeActionsConfiguration(actions: [ delete, mute, pin ]) + + case .openGroup, .closedGroup: + let leave: UIContextualAction = UIContextualAction( + title: "LEAVE_BUTTON_TITLE".localized(), + icon: UIImage(named: "icon_leave"), + iconHeight: Values.mediumFontSize, + themeTintColor: .textPrimary, + themeBackgroundColor: .conversationButton_swipeDestructive, + side: .trailing, + actionIndex: 2, + indexPath: indexPath, + tableView: tableView + ) { [weak self] _, _, completionHandler in + let confirmationModalTitle: String = (threadViewModel.threadVariant == .closedGroup) ? + "leave_group_confirmation_alert_title".localized() : + "leave_community_confirmation_alert_title".localized() + + let confirmationModalExplanation: NSAttributedString = { + if threadViewModel.threadVariant == .closedGroup && threadViewModel.currentUserIsClosedGroupAdmin == true { + return NSAttributedString(string: "admin_group_leave_warning".localized()) + } + + let mutableAttributedString = NSMutableAttributedString( + string: String( + format: "leave_community_confirmation_alert_message".localized(), + threadViewModel.displayName + ) + ) + mutableAttributedString.addAttribute( + .font, + value: UIFont.boldSystemFont(ofSize: Values.smallFontSize), + range: (mutableAttributedString.string as NSString).range(of: threadViewModel.displayName) + ) + return mutableAttributedString + }() + + let confirmationModal: ConfirmationModal = ConfirmationModal( + info: ConfirmationModal.Info( + title: confirmationModalTitle, + attributedExplanation: confirmationModalExplanation, + confirmTitle: "LEAVE_BUTTON_TITLE".localized(), + confirmStyle: .danger, + cancelStyle: .alert_text, + dismissOnConfirm: true, + onConfirm: { [weak self] _ in + self?.viewModel.delete( + threadId: threadViewModel.threadId, + threadVariant: threadViewModel.threadVariant + ) + self?.dismiss(animated: true, completion: nil) + + completionHandler(true) + }, + afterClosed: { completionHandler(false) } + ) + ) + + self?.present(confirmationModal, animated: true, completion: nil) + } + leave.themeBackgroundColor = .conversationButton_swipeDestructive + + return UISwipeActionsConfiguration(actions: [ leave, mute, pin ]) + } + default: return nil } } diff --git a/Session/Meta/Images.xcassets/Session/icon_leave.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/icon_leave.imageset/Contents.json new file mode 100644 index 000000000..ab1509796 --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/icon_leave.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Group 21.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Meta/Images.xcassets/Session/icon_leave.imageset/Group 21.pdf b/Session/Meta/Images.xcassets/Session/icon_leave.imageset/Group 21.pdf new file mode 100644 index 000000000..ad9dca31b --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/icon_leave.imageset/Group 21.pdf @@ -0,0 +1,115 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +-1.000000 0.000000 -0.000000 -1.000000 13.681108 22.054058 cm +1.000000 1.000000 1.000000 scn +0.000000 8.699632 m +0.000000 2.779560 l +0.000000 1.114012 1.164413 0.000002 2.902360 0.000002 c +10.825995 0.000002 l +12.538525 0.000002 13.681101 1.114012 13.681101 2.781368 c +13.681101 19.272701 l +13.681101 20.941874 12.538525 22.054058 10.825995 22.054058 c +2.902360 22.054058 l +1.164413 22.054058 0.000000 20.941874 0.000000 19.274517 c +0.000000 13.337048 l +1.977312 13.337048 l +1.977312 18.819965 l +1.977312 19.588516 2.433078 20.022297 3.241149 20.022297 c +10.451877 20.022297 l +11.249847 20.022297 11.705621 19.584885 11.705621 18.818157 c +11.705621 3.235851 l +11.705621 2.469200 11.249847 2.031755 10.451877 2.031755 c +3.241149 2.031755 l +2.433078 2.031755 1.977312 2.465502 1.977312 3.234045 c +1.977312 8.699632 l +0.000000 8.699632 l +h +f +n +Q +q +1.000000 -0.000000 0.000000 1.000000 6.456984 6.532265 cm +1.000000 1.000000 1.000000 scn +0.854047 3.650497 m +9.973925 3.650497 l +11.921844 3.749533 l +9.937829 1.989250 l +9.383045 1.430826 l +9.235626 1.271473 9.126730 1.047242 9.126730 0.808298 c +9.126730 0.331357 9.478227 0.000003 9.940446 0.000003 c +10.176593 0.000003 10.389956 0.087940 10.547450 0.247207 c +14.110446 3.806581 l +14.335536 4.023411 14.448080 4.265796 14.448080 4.493468 c +14.448080 4.722947 14.335536 4.980132 14.110446 5.190423 c +10.547450 8.741562 l +10.389956 8.900881 10.176593 8.988800 9.940446 8.988800 c +9.478227 8.988800 9.126730 8.657471 9.126730 8.186983 c +9.126730 7.939745 9.231996 7.725583 9.383045 7.566264 c +9.937829 6.997773 l +11.921844 5.245663 l +9.973925 5.346506 l +0.854047 5.346506 l +0.340408 5.346506 0.000000 4.944596 0.000000 4.493468 c +0.000000 4.044147 0.340408 3.650497 0.854047 3.650497 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 1767 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 20.905060 22.054062 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001857 00000 n +0000001880 00000 n +0000002053 00000 n +0000002127 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2186 +%%EOF \ No newline at end of file diff --git a/Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Contents.json new file mode 100644 index 000000000..c6f97a05d --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Vector.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Vector.pdf b/Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Vector.pdf new file mode 100644 index 000000000..1c44b148b --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Vector.pdf @@ -0,0 +1,115 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm +1.000000 1.000000 1.000000 scn +2.855198 -0.000004 m +16.669914 -0.000004 l +18.550127 -0.000004 19.526665 0.969404 19.526665 2.826668 c +19.526665 11.389789 l +19.526665 12.870333 19.235811 13.360014 18.252293 14.098968 c +11.707531 19.132406 l +10.997782 19.677958 10.466211 20.000000 9.762552 20.000000 c +9.060527 20.000000 8.530442 19.677958 7.819207 19.132406 c +1.274408 14.098968 l +0.295581 13.363148 0.000000 12.870333 0.000000 11.389789 c +0.000000 2.826668 l +0.000000 0.962275 0.976567 -0.000004 2.855198 -0.000004 c +h +2.851544 1.613646 m +2.040694 1.613646 1.599581 2.032692 1.599581 2.881479 c +1.599581 11.580967 l +1.599581 12.240508 1.779054 12.556168 2.225032 12.890715 c +8.729047 17.882366 l +9.139924 18.197447 9.379602 18.366127 9.762552 18.366127 c +10.139932 18.366127 10.388373 18.195879 10.797616 17.882366 c +17.298483 12.890715 l +17.744492 12.552974 17.927126 12.240508 17.927126 11.580967 c +17.927126 2.881479 l +17.927126 2.032692 17.471687 1.613646 16.673553 1.613646 c +2.851544 1.613646 l +h +1.064996 1.914450 m +2.115197 0.869879 l +8.758162 7.423330 l +9.115859 7.786597 9.427136 7.942571 9.754902 7.942571 c +10.075537 7.942571 10.388373 7.786597 10.751641 7.423330 c +17.396152 0.869879 l +18.437677 1.914450 l +11.638903 8.596021 l +11.013972 9.219392 10.398623 9.481946 9.754902 9.481946 c +9.104050 9.481946 8.495831 9.221025 7.869340 8.596021 c +1.064996 1.914450 l +h +6.495846 6.892206 m +7.547591 7.929720 l +2.146882 13.280460 l +1.103819 12.235829 l +6.495846 6.892206 l +h +11.962213 7.929720 m +13.006858 6.892206 l +18.400393 12.235829 l +17.355822 13.280460 l +11.962213 7.929720 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 1685 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 19.526665 20.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001775 00000 n +0000001798 00000 n +0000001971 00000 n +0000002045 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2104 +%%EOF \ No newline at end of file diff --git a/Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Contents.json new file mode 100644 index 000000000..15f04e720 --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Group 1.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Group 1.pdf b/Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Group 1.pdf new file mode 100644 index 000000000..ee5803cc0 --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Group 1.pdf @@ -0,0 +1,119 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm +1.000000 1.000000 1.000000 scn +2.787199 -0.000020 m +16.486496 -0.000020 l +18.115294 -0.000020 19.061613 0.946370 19.061613 2.759328 c +19.061613 9.586817 l +18.574244 9.380354 18.049170 9.293177 17.500172 9.318328 c +17.500172 2.805877 l +17.500172 1.982740 17.055578 1.575270 16.276453 1.575270 c +2.783631 1.575270 l +1.992093 1.575270 1.561486 1.982742 1.561486 2.812838 c +1.561486 12.095173 l +1.561486 12.916785 1.992093 13.325809 2.783631 13.325809 c +13.469756 13.325809 l +13.425384 13.865679 13.517972 14.419136 13.721417 14.901062 c +2.573595 14.901062 l +0.946341 14.901062 0.000000 13.961681 0.000000 12.148694 c +0.000000 2.759328 l +0.000000 0.939410 0.953309 -0.000020 2.787199 -0.000020 c +h +9.543965 5.139557 m +10.172357 5.139557 10.773123 5.402818 11.383170 6.002787 c +15.382624 9.937387 l +14.974646 10.187351 14.615897 10.528234 14.331102 10.912272 c +10.517039 7.147622 l +10.162351 6.794528 9.856965 6.640747 9.543965 6.640747 c +9.224007 6.640747 8.927103 6.794528 8.570965 7.147622 c +1.860897 13.775782 l +0.852536 12.740739 l +7.703311 6.002787 l +8.314881 5.401222 8.908615 5.139557 9.543965 5.139557 c +h +17.196671 1.166564 m +18.221004 2.188725 l +12.303679 8.048771 l +11.291525 7.022915 l +17.196671 1.166564 l +h +1.986481 1.267200 m +7.645381 6.878778 l +6.625601 7.895498 l +0.966048 2.286241 l +1.986481 1.267200 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 14.652039 10.501404 cm +1.000000 1.000000 1.000000 scn +2.929153 0.000005 m +4.535837 0.000005 5.865195 1.329370 5.865195 2.936068 c +5.865195 4.542760 4.535837 5.872131 2.929153 5.872131 c +1.322396 5.872131 0.000000 4.542760 0.000000 2.936068 c +0.000000 1.329370 1.322396 0.000005 2.929153 0.000005 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 1758 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 20.517242 16.373535 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001848 00000 n +0000001871 00000 n +0000002044 00000 n +0000002118 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2177 +%%EOF \ No newline at end of file diff --git a/Session/Meta/Images.xcassets/Session/icon_mute.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/icon_mute.imageset/Contents.json new file mode 100644 index 000000000..103f38787 --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/icon_mute.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Group (1).pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Meta/Images.xcassets/Session/icon_mute.imageset/Group (1).pdf b/Session/Meta/Images.xcassets/Session/icon_mute.imageset/Group (1).pdf new file mode 100644 index 000000000..82f2ccb5f --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/icon_mute.imageset/Group (1).pdf @@ -0,0 +1,108 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 1.777191 1.065613 cm +1.000000 1.000000 1.000000 scn +1.965486 4.165290 m +4.480973 4.165290 l +4.556003 4.165290 4.618963 4.140318 4.676248 4.090298 c +8.573530 0.603346 l +9.041570 0.191758 9.389591 0.000002 9.855134 0.000002 c +10.269597 0.000002 10.612472 0.202731 10.824432 0.550527 c +9.383916 1.983778 l +5.464605 5.521886 l +5.282459 5.686324 5.161677 5.726583 4.919939 5.726583 c +2.115349 5.726583 l +1.813488 5.726583 1.672305 5.869378 1.672305 6.162385 c +1.672305 9.702625 l +0.387879 10.985455 l +0.140821 10.674543 0.000000 10.221214 0.000000 9.624583 c +0.000000 6.215356 l +0.000000 4.840144 0.665267 4.165290 1.965486 4.165290 c +h +10.992882 5.767370 m +10.994472 14.682869 l +10.994472 15.337503 10.509784 15.863373 9.840604 15.863373 c +9.381418 15.863373 9.070704 15.660295 8.568763 15.214769 c +4.854671 11.916056 l +5.977557 10.789121 l +9.057764 13.588398 l +9.100519 13.631145 9.152128 13.654552 9.203737 13.654552 c +9.268968 13.654552 9.322166 13.608618 9.322166 13.527208 c +9.322166 7.441264 l +10.992882 5.767370 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 0.000107 -0.138275 cm +1.000000 1.000000 1.000000 scn +15.717578 0.344515 m +15.993180 0.070501 16.450928 0.068913 16.716087 0.344515 c +16.990101 0.625868 16.991690 1.067497 16.716087 1.341510 c +1.213316 16.844282 l +0.937698 17.119900 0.479934 17.119900 0.204318 16.844282 c +-0.068106 16.577534 -0.068106 16.112497 0.204318 15.845750 c +15.717578 0.344515 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 1493 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 16.922302 18.003113 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001583 00000 n +0000001606 00000 n +0000001779 00000 n +0000001853 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1912 +%%EOF \ No newline at end of file diff --git a/Session/Meta/Images.xcassets/Session/icon_pin.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/icon_pin.imageset/Contents.json new file mode 100644 index 000000000..93044cb41 --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/icon_pin.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Group.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Meta/Images.xcassets/Session/icon_pin.imageset/Group.pdf b/Session/Meta/Images.xcassets/Session/icon_pin.imageset/Group.pdf new file mode 100644 index 000000000..401f1ec61 --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/icon_pin.imageset/Group.pdf @@ -0,0 +1,108 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000061 0.000000 cm +1.000000 1.000000 1.000000 scn +5.862790 0.000008 m +6.062284 0.000008 6.593354 1.049471 6.593354 2.096780 c +6.593354 6.267460 l +5.127457 6.267460 l +5.127457 2.096780 l +5.127457 1.049471 5.658547 0.000008 5.862790 0.000008 c +h +1.157771 5.602798 m +10.563084 5.602798 l +11.267075 5.602798 11.720842 6.047764 11.720842 6.720025 c +11.720842 8.963408 9.209062 11.171642 5.862790 11.171642 c +2.511775 11.171642 0.000000 8.963408 0.000000 6.720025 c +0.000000 6.047764 0.453757 5.602798 1.157771 5.602798 c +h +1.497385 6.857010 m +1.346727 6.857010 1.281856 6.944154 1.308873 7.119138 c +1.488177 8.448398 3.233897 9.955872 5.862790 9.955872 c +8.486959 9.955872 10.232621 8.448398 10.411976 7.119138 c +10.438954 6.944154 10.374103 6.857010 10.223438 6.857010 c +1.497385 6.857010 l +h +0.942546 16.760296 m +0.942546 16.527699 1.038284 16.258003 1.240602 15.997648 c +1.617765 15.500992 2.499754 14.807369 3.452244 14.178015 c +3.174973 10.149855 l +4.498692 10.149855 l +4.777298 14.771296 l +4.784721 14.895235 4.761865 14.951048 4.667609 14.998844 c +3.659894 15.519547 2.877798 16.120106 2.762320 16.281898 c +2.701610 16.369028 2.752972 16.432411 2.831940 16.432411 c +8.888859 16.432411 l +8.967833 16.432411 9.019195 16.369028 8.958523 16.281898 c +8.843007 16.120106 8.060929 15.519547 7.053202 14.998844 c +6.965045 14.951048 6.936103 14.895235 6.949593 14.771296 c +7.222106 10.149855 l +8.545856 10.149855 l +8.268592 14.178015 l +9.227174 14.807369 10.103045 15.500992 10.480247 15.997648 c +10.688606 16.258003 10.784363 16.527699 10.784363 16.760296 c +10.784363 17.250416 10.407479 17.609772 9.853267 17.609772 c +1.873662 17.609772 l +1.313332 17.609772 0.942546 17.250416 0.942546 16.760296 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 1770 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 11.720917 18.003113 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001860 00000 n +0000001883 00000 n +0000002056 00000 n +0000002130 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2189 +%%EOF \ No newline at end of file diff --git a/Session/Meta/Translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings index 21f699aca..6be84d9be 100644 --- a/Session/Meta/Translations/de.lproj/Localizable.strings +++ b/Session/Meta/Translations/de.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index 9bef16abf..7b4de01eb 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings index bfb99bd79..531c4cd22 100644 --- a/Session/Meta/Translations/es.lproj/Localizable.strings +++ b/Session/Meta/Translations/es.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings index 262854bfe..2a0170dc3 100644 --- a/Session/Meta/Translations/fa.lproj/Localizable.strings +++ b/Session/Meta/Translations/fa.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/fi.lproj/Localizable.strings b/Session/Meta/Translations/fi.lproj/Localizable.strings index 8b1b9a3c5..d24651d21 100644 --- a/Session/Meta/Translations/fi.lproj/Localizable.strings +++ b/Session/Meta/Translations/fi.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings index 28b5ba47f..beea8bef7 100644 --- a/Session/Meta/Translations/fr.lproj/Localizable.strings +++ b/Session/Meta/Translations/fr.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/hi.lproj/Localizable.strings b/Session/Meta/Translations/hi.lproj/Localizable.strings index ff4d5d873..79f708099 100644 --- a/Session/Meta/Translations/hi.lproj/Localizable.strings +++ b/Session/Meta/Translations/hi.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/hr.lproj/Localizable.strings b/Session/Meta/Translations/hr.lproj/Localizable.strings index d5f5b0a94..f76e43cf6 100644 --- a/Session/Meta/Translations/hr.lproj/Localizable.strings +++ b/Session/Meta/Translations/hr.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings index effc945b5..1f32b9335 100644 --- a/Session/Meta/Translations/id-ID.lproj/Localizable.strings +++ b/Session/Meta/Translations/id-ID.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings index 766457324..7d34972cf 100644 --- a/Session/Meta/Translations/it.lproj/Localizable.strings +++ b/Session/Meta/Translations/it.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings index 798f4bac9..d548174c1 100644 --- a/Session/Meta/Translations/ja.lproj/Localizable.strings +++ b/Session/Meta/Translations/ja.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/nl.lproj/Localizable.strings b/Session/Meta/Translations/nl.lproj/Localizable.strings index 0a39aa25c..c3acfc996 100644 --- a/Session/Meta/Translations/nl.lproj/Localizable.strings +++ b/Session/Meta/Translations/nl.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings index be530b2f2..f9b3a16fe 100644 --- a/Session/Meta/Translations/pl.lproj/Localizable.strings +++ b/Session/Meta/Translations/pl.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings index c61ecd667..658cc1d23 100644 --- a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings +++ b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings index d683c3892..f650c8c4c 100644 --- a/Session/Meta/Translations/ru.lproj/Localizable.strings +++ b/Session/Meta/Translations/ru.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/si.lproj/Localizable.strings b/Session/Meta/Translations/si.lproj/Localizable.strings index ef161ff64..7af7c5365 100644 --- a/Session/Meta/Translations/si.lproj/Localizable.strings +++ b/Session/Meta/Translations/si.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/sk.lproj/Localizable.strings b/Session/Meta/Translations/sk.lproj/Localizable.strings index 4b023ae1e..2f6dc0039 100644 --- a/Session/Meta/Translations/sk.lproj/Localizable.strings +++ b/Session/Meta/Translations/sk.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/sv.lproj/Localizable.strings b/Session/Meta/Translations/sv.lproj/Localizable.strings index 066e5ba5d..481256826 100644 --- a/Session/Meta/Translations/sv.lproj/Localizable.strings +++ b/Session/Meta/Translations/sv.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/th.lproj/Localizable.strings b/Session/Meta/Translations/th.lproj/Localizable.strings index cafa26215..67f3f233e 100644 --- a/Session/Meta/Translations/th.lproj/Localizable.strings +++ b/Session/Meta/Translations/th.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings index 0b2bc8a02..f6d6d5f3e 100644 --- a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings +++ b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings index 9f4292ed6..06a310228 100644 --- a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings index 164c814da..9a14a5c83 100644 --- a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings @@ -609,3 +609,10 @@ "context_menu_resync" = "Resync"; "GIPHY_PERMISSION_TITLE" = "Search GIFs?"; "GIPHY_PERMISSION_MESSAGE" = "Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs."; +"mute_button_text" = "Mute"; +"unmute_button_text" = "Unmute"; +"mark_read_button_text" = "Mark read"; +"mark_unread_button_text" = "Mark unread"; +"leave_group_confirmation_alert_title" = "Leave Group"; +"leave_community_confirmation_alert_title" = "Leave Community"; +"leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; diff --git a/Session/Shared/FullConversationCell.swift b/Session/Shared/FullConversationCell.swift index 11fa90c97..9ab4b39fa 100644 --- a/Session/Shared/FullConversationCell.swift +++ b/Session/Shared/FullConversationCell.swift @@ -346,7 +346,7 @@ public final class FullConversationCell: UITableViewCell { } else { accentLineView.themeBackgroundColor = .conversationButton_unreadStripBackground - accentLineView.alpha = (unreadCount > 0 ? 1 : 0.0001) // Setting the alpha to exactly 0 causes an issue on iOS 12 + accentLineView.alpha = (unreadCount > 0 ? 1 : 0) } isPinnedIcon.isHidden = !cellViewModel.threadIsPinned @@ -406,23 +406,33 @@ public final class FullConversationCell: UITableViewCell { } public func optimisticUpdate( - isBlocked: Bool? = nil, - isPinned: Bool? = nil + isMuted: Bool? = nil, + isPinned: Bool? = nil, + hasUnread: Bool? = nil ) { - if let isBlocked: Bool = isBlocked { - if isBlocked { - accentLineView.themeBackgroundColor = .danger - accentLineView.alpha = 1 - } - else { - accentLineView.themeBackgroundColor = .conversationButton_unreadStripBackground - accentLineView.alpha = (!unreadCountView.isHidden ? 1 : 0.0001) // Setting the alpha to exactly 0 causes an issue on iOS 12 + if let isMuted: Bool = isMuted { + if isMuted { + + } else { + } } if let isPinned: Bool = isPinned { isPinnedIcon.isHidden = !isPinned } + + if let hasUnread: Bool = hasUnread { + if hasUnread { + unreadCountView.isHidden = false + unreadCountLabel.text = "1" + unreadCountLabel.font = .boldSystemFont(ofSize: Values.verySmallFontSize) + accentLineView.alpha = 1 + } else { + unreadCountView.isHidden = true + accentLineView.alpha = 0 + } + } } // MARK: - Snippet generation diff --git a/SessionUIKit/Utilities/UIContextualAction+Theming.swift b/SessionUIKit/Utilities/UIContextualAction+Theming.swift index 99e563e97..7ac0ae0fb 100644 --- a/SessionUIKit/Utilities/UIContextualAction+Theming.swift +++ b/SessionUIKit/Utilities/UIContextualAction+Theming.swift @@ -66,11 +66,18 @@ public extension UIContextualAction { let stackView: UIStackView = UIStackView() stackView.axis = .vertical stackView.alignment = .center - stackView.spacing = 3 + stackView.spacing = 4 if let icon: UIImage = icon { let aspectRatio: CGFloat = (icon.size.width / icon.size.height) - let imageView: UIImageView = UIImageView(image: icon) + let imageView: UIImageView = UIImageView( + image: icon.resizedImage( + to: CGSize( + width: iconHeight * aspectRatio, + height: iconHeight + ) + ) + ) imageView.frame = CGRect(x: 0, y: 0, width: (iconHeight * aspectRatio), height: iconHeight) imageView.contentMode = .scaleAspectFit imageView.themeTintColor = themeTintColor From f3c79007d8cb228e8a3c2a9921083f118974196a Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 7 Mar 2023 13:54:21 +1100 Subject: [PATCH 04/32] replace icon image with system SF Font --- Session/Home/HomeVC.swift | 14 +-- .../Session/icon_leave.imageset/Contents.json | 12 -- .../Session/icon_leave.imageset/Group 21.pdf | 115 ----------------- .../icon_mark_read.imageset/Contents.json | 12 -- .../icon_mark_read.imageset/Vector.pdf | 115 ----------------- .../icon_mark_unread.imageset/Contents.json | 12 -- .../icon_mark_unread.imageset/Group 1.pdf | 119 ------------------ .../Session/icon_mute.imageset/Contents.json | 12 -- .../Session/icon_mute.imageset/Group (1).pdf | 108 ---------------- .../Session/icon_pin.imageset/Contents.json | 12 -- .../Session/icon_pin.imageset/Group.pdf | 108 ---------------- .../UIContextualAction+Theming.swift | 12 +- 12 files changed, 10 insertions(+), 641 deletions(-) delete mode 100644 Session/Meta/Images.xcassets/Session/icon_leave.imageset/Contents.json delete mode 100644 Session/Meta/Images.xcassets/Session/icon_leave.imageset/Group 21.pdf delete mode 100644 Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Contents.json delete mode 100644 Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Vector.pdf delete mode 100644 Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Contents.json delete mode 100644 Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Group 1.pdf delete mode 100644 Session/Meta/Images.xcassets/Session/icon_mute.imageset/Contents.json delete mode 100644 Session/Meta/Images.xcassets/Session/icon_mute.imageset/Group (1).pdf delete mode 100644 Session/Meta/Images.xcassets/Session/icon_pin.imageset/Contents.json delete mode 100644 Session/Meta/Images.xcassets/Session/icon_pin.imageset/Group.pdf diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index c97c01ef2..d95c76515 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -630,8 +630,8 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi let hasUnread: Bool = (threadViewModel.threadUnreadCount ?? 0) > 0 let mark: UIContextualAction = UIContextualAction( title: ((hasUnread) ? "mark_read_button_text".localized() : "mark_unread_button_text".localized()), - icon: ((hasUnread) ? UIImage(named: "icon_mark_read") : UIImage(named: "icon_mark_unread")), - iconHeight: Values.mediumFontSize, + icon: ((hasUnread) ? UIImage(systemName: "envelope.open") : UIImage(systemName: "envelope.badge")), + iconHeight: Values.smallFontSize, themeTintColor: .textPrimary, themeBackgroundColor: .conversationButton_swipeDestructive, side: .trailing, @@ -689,7 +689,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi let pin: UIContextualAction = UIContextualAction( title: (threadViewModel.threadIsPinned ? "UNPIN_BUTTON_TEXT".localized() : "PIN_BUTTON_TEXT".localized()), - icon: UIImage(named: "icon_pin"), + icon: UIImage(systemName: "pin"), iconHeight: Values.mediumFontSize, themeTintColor: .textPrimary, themeBackgroundColor: .conversationButton_swipeDestructive, @@ -716,7 +716,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi let mute: UIContextualAction = UIContextualAction( title: ((threadViewModel.threadMutedUntilTimestamp != nil) ? "unmute_button_text".localized() : "mute_button_text".localized()), - icon: UIImage(named: "icon_mute"), + icon: UIImage(systemName: "speaker.slash"), iconHeight: Values.mediumFontSize, themeTintColor: .textPrimary, themeBackgroundColor: .conversationButton_swipeDestructive, @@ -759,8 +759,8 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi case .contact: let delete: UIContextualAction = UIContextualAction( title: "TXT_DELETE_TITLE".localized(), - icon: UIImage(named: "icon_bin"), - iconHeight: Values.smallFontSize, + icon: UIImage(named: "icon_bin")?.resizedImage(to: CGSize(width: Values.mediumFontSize, height: Values.mediumFontSize)), + iconHeight: Values.mediumFontSize, themeTintColor: .textPrimary, themeBackgroundColor: .conversationButton_swipeDestructive, side: .trailing, @@ -801,7 +801,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi case .openGroup, .closedGroup: let leave: UIContextualAction = UIContextualAction( title: "LEAVE_BUTTON_TITLE".localized(), - icon: UIImage(named: "icon_leave"), + icon: UIImage(systemName: "rectangle.portrait.and.arrow.right"), iconHeight: Values.mediumFontSize, themeTintColor: .textPrimary, themeBackgroundColor: .conversationButton_swipeDestructive, diff --git a/Session/Meta/Images.xcassets/Session/icon_leave.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/icon_leave.imageset/Contents.json deleted file mode 100644 index ab1509796..000000000 --- a/Session/Meta/Images.xcassets/Session/icon_leave.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "Group 21.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Session/Meta/Images.xcassets/Session/icon_leave.imageset/Group 21.pdf b/Session/Meta/Images.xcassets/Session/icon_leave.imageset/Group 21.pdf deleted file mode 100644 index ad9dca31b..000000000 --- a/Session/Meta/Images.xcassets/Session/icon_leave.imageset/Group 21.pdf +++ /dev/null @@ -1,115 +0,0 @@ -%PDF-1.7 - -1 0 obj - << >> -endobj - -2 0 obj - << /Length 3 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q --1.000000 0.000000 -0.000000 -1.000000 13.681108 22.054058 cm -1.000000 1.000000 1.000000 scn -0.000000 8.699632 m -0.000000 2.779560 l -0.000000 1.114012 1.164413 0.000002 2.902360 0.000002 c -10.825995 0.000002 l -12.538525 0.000002 13.681101 1.114012 13.681101 2.781368 c -13.681101 19.272701 l -13.681101 20.941874 12.538525 22.054058 10.825995 22.054058 c -2.902360 22.054058 l -1.164413 22.054058 0.000000 20.941874 0.000000 19.274517 c -0.000000 13.337048 l -1.977312 13.337048 l -1.977312 18.819965 l -1.977312 19.588516 2.433078 20.022297 3.241149 20.022297 c -10.451877 20.022297 l -11.249847 20.022297 11.705621 19.584885 11.705621 18.818157 c -11.705621 3.235851 l -11.705621 2.469200 11.249847 2.031755 10.451877 2.031755 c -3.241149 2.031755 l -2.433078 2.031755 1.977312 2.465502 1.977312 3.234045 c -1.977312 8.699632 l -0.000000 8.699632 l -h -f -n -Q -q -1.000000 -0.000000 0.000000 1.000000 6.456984 6.532265 cm -1.000000 1.000000 1.000000 scn -0.854047 3.650497 m -9.973925 3.650497 l -11.921844 3.749533 l -9.937829 1.989250 l -9.383045 1.430826 l -9.235626 1.271473 9.126730 1.047242 9.126730 0.808298 c -9.126730 0.331357 9.478227 0.000003 9.940446 0.000003 c -10.176593 0.000003 10.389956 0.087940 10.547450 0.247207 c -14.110446 3.806581 l -14.335536 4.023411 14.448080 4.265796 14.448080 4.493468 c -14.448080 4.722947 14.335536 4.980132 14.110446 5.190423 c -10.547450 8.741562 l -10.389956 8.900881 10.176593 8.988800 9.940446 8.988800 c -9.478227 8.988800 9.126730 8.657471 9.126730 8.186983 c -9.126730 7.939745 9.231996 7.725583 9.383045 7.566264 c -9.937829 6.997773 l -11.921844 5.245663 l -9.973925 5.346506 l -0.854047 5.346506 l -0.340408 5.346506 0.000000 4.944596 0.000000 4.493468 c -0.000000 4.044147 0.340408 3.650497 0.854047 3.650497 c -h -f -n -Q - -endstream -endobj - -3 0 obj - 1767 -endobj - -4 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 20.905060 22.054062 ] - /Resources 1 0 R - /Contents 2 0 R - /Parent 5 0 R - >> -endobj - -5 0 obj - << /Kids [ 4 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -6 0 obj - << /Pages 5 0 R - /Type /Catalog - >> -endobj - -xref -0 7 -0000000000 65535 f -0000000010 00000 n -0000000034 00000 n -0000001857 00000 n -0000001880 00000 n -0000002053 00000 n -0000002127 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -2186 -%%EOF \ No newline at end of file diff --git a/Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Contents.json deleted file mode 100644 index c6f97a05d..000000000 --- a/Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "Vector.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Vector.pdf b/Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Vector.pdf deleted file mode 100644 index 1c44b148b..000000000 --- a/Session/Meta/Images.xcassets/Session/icon_mark_read.imageset/Vector.pdf +++ /dev/null @@ -1,115 +0,0 @@ -%PDF-1.7 - -1 0 obj - << >> -endobj - -2 0 obj - << /Length 3 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm -1.000000 1.000000 1.000000 scn -2.855198 -0.000004 m -16.669914 -0.000004 l -18.550127 -0.000004 19.526665 0.969404 19.526665 2.826668 c -19.526665 11.389789 l -19.526665 12.870333 19.235811 13.360014 18.252293 14.098968 c -11.707531 19.132406 l -10.997782 19.677958 10.466211 20.000000 9.762552 20.000000 c -9.060527 20.000000 8.530442 19.677958 7.819207 19.132406 c -1.274408 14.098968 l -0.295581 13.363148 0.000000 12.870333 0.000000 11.389789 c -0.000000 2.826668 l -0.000000 0.962275 0.976567 -0.000004 2.855198 -0.000004 c -h -2.851544 1.613646 m -2.040694 1.613646 1.599581 2.032692 1.599581 2.881479 c -1.599581 11.580967 l -1.599581 12.240508 1.779054 12.556168 2.225032 12.890715 c -8.729047 17.882366 l -9.139924 18.197447 9.379602 18.366127 9.762552 18.366127 c -10.139932 18.366127 10.388373 18.195879 10.797616 17.882366 c -17.298483 12.890715 l -17.744492 12.552974 17.927126 12.240508 17.927126 11.580967 c -17.927126 2.881479 l -17.927126 2.032692 17.471687 1.613646 16.673553 1.613646 c -2.851544 1.613646 l -h -1.064996 1.914450 m -2.115197 0.869879 l -8.758162 7.423330 l -9.115859 7.786597 9.427136 7.942571 9.754902 7.942571 c -10.075537 7.942571 10.388373 7.786597 10.751641 7.423330 c -17.396152 0.869879 l -18.437677 1.914450 l -11.638903 8.596021 l -11.013972 9.219392 10.398623 9.481946 9.754902 9.481946 c -9.104050 9.481946 8.495831 9.221025 7.869340 8.596021 c -1.064996 1.914450 l -h -6.495846 6.892206 m -7.547591 7.929720 l -2.146882 13.280460 l -1.103819 12.235829 l -6.495846 6.892206 l -h -11.962213 7.929720 m -13.006858 6.892206 l -18.400393 12.235829 l -17.355822 13.280460 l -11.962213 7.929720 l -h -f -n -Q - -endstream -endobj - -3 0 obj - 1685 -endobj - -4 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 19.526665 20.000000 ] - /Resources 1 0 R - /Contents 2 0 R - /Parent 5 0 R - >> -endobj - -5 0 obj - << /Kids [ 4 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -6 0 obj - << /Pages 5 0 R - /Type /Catalog - >> -endobj - -xref -0 7 -0000000000 65535 f -0000000010 00000 n -0000000034 00000 n -0000001775 00000 n -0000001798 00000 n -0000001971 00000 n -0000002045 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -2104 -%%EOF \ No newline at end of file diff --git a/Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Contents.json deleted file mode 100644 index 15f04e720..000000000 --- a/Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "Group 1.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Group 1.pdf b/Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Group 1.pdf deleted file mode 100644 index ee5803cc0..000000000 --- a/Session/Meta/Images.xcassets/Session/icon_mark_unread.imageset/Group 1.pdf +++ /dev/null @@ -1,119 +0,0 @@ -%PDF-1.7 - -1 0 obj - << >> -endobj - -2 0 obj - << /Length 3 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm -1.000000 1.000000 1.000000 scn -2.787199 -0.000020 m -16.486496 -0.000020 l -18.115294 -0.000020 19.061613 0.946370 19.061613 2.759328 c -19.061613 9.586817 l -18.574244 9.380354 18.049170 9.293177 17.500172 9.318328 c -17.500172 2.805877 l -17.500172 1.982740 17.055578 1.575270 16.276453 1.575270 c -2.783631 1.575270 l -1.992093 1.575270 1.561486 1.982742 1.561486 2.812838 c -1.561486 12.095173 l -1.561486 12.916785 1.992093 13.325809 2.783631 13.325809 c -13.469756 13.325809 l -13.425384 13.865679 13.517972 14.419136 13.721417 14.901062 c -2.573595 14.901062 l -0.946341 14.901062 0.000000 13.961681 0.000000 12.148694 c -0.000000 2.759328 l -0.000000 0.939410 0.953309 -0.000020 2.787199 -0.000020 c -h -9.543965 5.139557 m -10.172357 5.139557 10.773123 5.402818 11.383170 6.002787 c -15.382624 9.937387 l -14.974646 10.187351 14.615897 10.528234 14.331102 10.912272 c -10.517039 7.147622 l -10.162351 6.794528 9.856965 6.640747 9.543965 6.640747 c -9.224007 6.640747 8.927103 6.794528 8.570965 7.147622 c -1.860897 13.775782 l -0.852536 12.740739 l -7.703311 6.002787 l -8.314881 5.401222 8.908615 5.139557 9.543965 5.139557 c -h -17.196671 1.166564 m -18.221004 2.188725 l -12.303679 8.048771 l -11.291525 7.022915 l -17.196671 1.166564 l -h -1.986481 1.267200 m -7.645381 6.878778 l -6.625601 7.895498 l -0.966048 2.286241 l -1.986481 1.267200 l -h -f -n -Q -q -1.000000 0.000000 -0.000000 1.000000 14.652039 10.501404 cm -1.000000 1.000000 1.000000 scn -2.929153 0.000005 m -4.535837 0.000005 5.865195 1.329370 5.865195 2.936068 c -5.865195 4.542760 4.535837 5.872131 2.929153 5.872131 c -1.322396 5.872131 0.000000 4.542760 0.000000 2.936068 c -0.000000 1.329370 1.322396 0.000005 2.929153 0.000005 c -h -f -n -Q - -endstream -endobj - -3 0 obj - 1758 -endobj - -4 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 20.517242 16.373535 ] - /Resources 1 0 R - /Contents 2 0 R - /Parent 5 0 R - >> -endobj - -5 0 obj - << /Kids [ 4 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -6 0 obj - << /Pages 5 0 R - /Type /Catalog - >> -endobj - -xref -0 7 -0000000000 65535 f -0000000010 00000 n -0000000034 00000 n -0000001848 00000 n -0000001871 00000 n -0000002044 00000 n -0000002118 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -2177 -%%EOF \ No newline at end of file diff --git a/Session/Meta/Images.xcassets/Session/icon_mute.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/icon_mute.imageset/Contents.json deleted file mode 100644 index 103f38787..000000000 --- a/Session/Meta/Images.xcassets/Session/icon_mute.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "Group (1).pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Session/Meta/Images.xcassets/Session/icon_mute.imageset/Group (1).pdf b/Session/Meta/Images.xcassets/Session/icon_mute.imageset/Group (1).pdf deleted file mode 100644 index 82f2ccb5f..000000000 --- a/Session/Meta/Images.xcassets/Session/icon_mute.imageset/Group (1).pdf +++ /dev/null @@ -1,108 +0,0 @@ -%PDF-1.7 - -1 0 obj - << >> -endobj - -2 0 obj - << /Length 3 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 1.777191 1.065613 cm -1.000000 1.000000 1.000000 scn -1.965486 4.165290 m -4.480973 4.165290 l -4.556003 4.165290 4.618963 4.140318 4.676248 4.090298 c -8.573530 0.603346 l -9.041570 0.191758 9.389591 0.000002 9.855134 0.000002 c -10.269597 0.000002 10.612472 0.202731 10.824432 0.550527 c -9.383916 1.983778 l -5.464605 5.521886 l -5.282459 5.686324 5.161677 5.726583 4.919939 5.726583 c -2.115349 5.726583 l -1.813488 5.726583 1.672305 5.869378 1.672305 6.162385 c -1.672305 9.702625 l -0.387879 10.985455 l -0.140821 10.674543 0.000000 10.221214 0.000000 9.624583 c -0.000000 6.215356 l -0.000000 4.840144 0.665267 4.165290 1.965486 4.165290 c -h -10.992882 5.767370 m -10.994472 14.682869 l -10.994472 15.337503 10.509784 15.863373 9.840604 15.863373 c -9.381418 15.863373 9.070704 15.660295 8.568763 15.214769 c -4.854671 11.916056 l -5.977557 10.789121 l -9.057764 13.588398 l -9.100519 13.631145 9.152128 13.654552 9.203737 13.654552 c -9.268968 13.654552 9.322166 13.608618 9.322166 13.527208 c -9.322166 7.441264 l -10.992882 5.767370 l -h -f -n -Q -q -1.000000 0.000000 -0.000000 1.000000 0.000107 -0.138275 cm -1.000000 1.000000 1.000000 scn -15.717578 0.344515 m -15.993180 0.070501 16.450928 0.068913 16.716087 0.344515 c -16.990101 0.625868 16.991690 1.067497 16.716087 1.341510 c -1.213316 16.844282 l -0.937698 17.119900 0.479934 17.119900 0.204318 16.844282 c --0.068106 16.577534 -0.068106 16.112497 0.204318 15.845750 c -15.717578 0.344515 l -h -f -n -Q - -endstream -endobj - -3 0 obj - 1493 -endobj - -4 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 16.922302 18.003113 ] - /Resources 1 0 R - /Contents 2 0 R - /Parent 5 0 R - >> -endobj - -5 0 obj - << /Kids [ 4 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -6 0 obj - << /Pages 5 0 R - /Type /Catalog - >> -endobj - -xref -0 7 -0000000000 65535 f -0000000010 00000 n -0000000034 00000 n -0000001583 00000 n -0000001606 00000 n -0000001779 00000 n -0000001853 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -1912 -%%EOF \ No newline at end of file diff --git a/Session/Meta/Images.xcassets/Session/icon_pin.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/icon_pin.imageset/Contents.json deleted file mode 100644 index 93044cb41..000000000 --- a/Session/Meta/Images.xcassets/Session/icon_pin.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "Group.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Session/Meta/Images.xcassets/Session/icon_pin.imageset/Group.pdf b/Session/Meta/Images.xcassets/Session/icon_pin.imageset/Group.pdf deleted file mode 100644 index 401f1ec61..000000000 --- a/Session/Meta/Images.xcassets/Session/icon_pin.imageset/Group.pdf +++ /dev/null @@ -1,108 +0,0 @@ -%PDF-1.7 - -1 0 obj - << >> -endobj - -2 0 obj - << /Length 3 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 0.000061 0.000000 cm -1.000000 1.000000 1.000000 scn -5.862790 0.000008 m -6.062284 0.000008 6.593354 1.049471 6.593354 2.096780 c -6.593354 6.267460 l -5.127457 6.267460 l -5.127457 2.096780 l -5.127457 1.049471 5.658547 0.000008 5.862790 0.000008 c -h -1.157771 5.602798 m -10.563084 5.602798 l -11.267075 5.602798 11.720842 6.047764 11.720842 6.720025 c -11.720842 8.963408 9.209062 11.171642 5.862790 11.171642 c -2.511775 11.171642 0.000000 8.963408 0.000000 6.720025 c -0.000000 6.047764 0.453757 5.602798 1.157771 5.602798 c -h -1.497385 6.857010 m -1.346727 6.857010 1.281856 6.944154 1.308873 7.119138 c -1.488177 8.448398 3.233897 9.955872 5.862790 9.955872 c -8.486959 9.955872 10.232621 8.448398 10.411976 7.119138 c -10.438954 6.944154 10.374103 6.857010 10.223438 6.857010 c -1.497385 6.857010 l -h -0.942546 16.760296 m -0.942546 16.527699 1.038284 16.258003 1.240602 15.997648 c -1.617765 15.500992 2.499754 14.807369 3.452244 14.178015 c -3.174973 10.149855 l -4.498692 10.149855 l -4.777298 14.771296 l -4.784721 14.895235 4.761865 14.951048 4.667609 14.998844 c -3.659894 15.519547 2.877798 16.120106 2.762320 16.281898 c -2.701610 16.369028 2.752972 16.432411 2.831940 16.432411 c -8.888859 16.432411 l -8.967833 16.432411 9.019195 16.369028 8.958523 16.281898 c -8.843007 16.120106 8.060929 15.519547 7.053202 14.998844 c -6.965045 14.951048 6.936103 14.895235 6.949593 14.771296 c -7.222106 10.149855 l -8.545856 10.149855 l -8.268592 14.178015 l -9.227174 14.807369 10.103045 15.500992 10.480247 15.997648 c -10.688606 16.258003 10.784363 16.527699 10.784363 16.760296 c -10.784363 17.250416 10.407479 17.609772 9.853267 17.609772 c -1.873662 17.609772 l -1.313332 17.609772 0.942546 17.250416 0.942546 16.760296 c -h -f -n -Q - -endstream -endobj - -3 0 obj - 1770 -endobj - -4 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 11.720917 18.003113 ] - /Resources 1 0 R - /Contents 2 0 R - /Parent 5 0 R - >> -endobj - -5 0 obj - << /Kids [ 4 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -6 0 obj - << /Pages 5 0 R - /Type /Catalog - >> -endobj - -xref -0 7 -0000000000 65535 f -0000000010 00000 n -0000000034 00000 n -0000001860 00000 n -0000001883 00000 n -0000002056 00000 n -0000002130 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -2189 -%%EOF \ No newline at end of file diff --git a/SessionUIKit/Utilities/UIContextualAction+Theming.swift b/SessionUIKit/Utilities/UIContextualAction+Theming.swift index 7ac0ae0fb..d16fdd9da 100644 --- a/SessionUIKit/Utilities/UIContextualAction+Theming.swift +++ b/SessionUIKit/Utilities/UIContextualAction+Theming.swift @@ -69,16 +69,10 @@ public extension UIContextualAction { stackView.spacing = 4 if let icon: UIImage = icon { + let scale: Double = iconHeight / icon.size.height let aspectRatio: CGFloat = (icon.size.width / icon.size.height) - let imageView: UIImageView = UIImageView( - image: icon.resizedImage( - to: CGSize( - width: iconHeight * aspectRatio, - height: iconHeight - ) - ) - ) - imageView.frame = CGRect(x: 0, y: 0, width: (iconHeight * aspectRatio), height: iconHeight) + let imageView: UIImageView = UIImageView(image: icon) + imageView.frame = CGRect(x: 0, y: 0, width: iconHeight * aspectRatio, height: iconHeight) imageView.contentMode = .scaleAspectFit imageView.themeTintColor = themeTintColor stackView.addArrangedSubview(imageView) From 36e753366d1b751ee2001a00cc8fe8a8d3f586c4 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 7 Mar 2023 15:07:24 +1100 Subject: [PATCH 05/32] WIP: add leaving status for leaving groups --- .../Context Menu/ContextMenuVC+Action.swift | 3 ++- .../ConversationVC+Interaction.swift | 3 ++- .../Message Cells/MessageCell.swift | 3 ++- Session/Home/HomeViewModel.swift | 17 +++++++++++++---- .../Translations/de.lproj/Localizable.strings | 3 +++ .../Translations/en.lproj/Localizable.strings | 3 +++ .../Translations/es.lproj/Localizable.strings | 3 +++ .../Translations/fa.lproj/Localizable.strings | 3 +++ .../Translations/fi.lproj/Localizable.strings | 3 +++ .../Translations/fr.lproj/Localizable.strings | 3 +++ .../Translations/hi.lproj/Localizable.strings | 3 +++ .../Translations/hr.lproj/Localizable.strings | 3 +++ .../id-ID.lproj/Localizable.strings | 3 +++ .../Translations/it.lproj/Localizable.strings | 3 +++ .../Translations/ja.lproj/Localizable.strings | 3 +++ .../Translations/nl.lproj/Localizable.strings | 3 +++ .../Translations/pl.lproj/Localizable.strings | 3 +++ .../pt_BR.lproj/Localizable.strings | 3 +++ .../Translations/ru.lproj/Localizable.strings | 3 +++ .../Translations/si.lproj/Localizable.strings | 3 +++ .../Translations/sk.lproj/Localizable.strings | 3 +++ .../Translations/sv.lproj/Localizable.strings | 3 +++ .../Translations/th.lproj/Localizable.strings | 3 +++ .../vi-VN.lproj/Localizable.strings | 3 +++ .../zh-Hant.lproj/Localizable.strings | 3 +++ .../zh_CN.lproj/Localizable.strings | 3 +++ .../Models/ControlMessageProcessRecord.swift | 3 ++- .../Database/Models/Interaction.swift | 8 ++++++-- .../MessageSender+ClosedGroups.swift | 3 ++- 29 files changed, 95 insertions(+), 11 deletions(-) diff --git a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift index 04e652f8f..a66dcfef3 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift @@ -136,7 +136,8 @@ extension ContextMenuVC { switch cellViewModel.variant { case .standardIncomingDeleted, .infoCall, .infoScreenshotNotification, .infoMediaSavedNotification, - .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, + .infoClosedGroupCreated, .infoClosedGroupUpdated, + .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, .infoMessageRequestAccepted, .infoDisappearingMessagesUpdate: // Let the user delete info messages and unsent messages return [ Action.delete(cellViewModel, delegate) ] diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index a8ca98c6d..980c0eb0c 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -1694,7 +1694,8 @@ extension ConversationVC: switch cellViewModel.variant { case .standardIncomingDeleted, .infoCall, .infoScreenshotNotification, .infoMediaSavedNotification, - .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, + .infoClosedGroupCreated, .infoClosedGroupUpdated, + .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, .infoMessageRequestAccepted, .infoDisappearingMessagesUpdate: // Info messages and unsent messages should just trigger a local // deletion (they are created as side effects so we wouldn't be diff --git a/Session/Conversations/Message Cells/MessageCell.swift b/Session/Conversations/Message Cells/MessageCell.swift index 1f7356bc2..44886ba9c 100644 --- a/Session/Conversations/Message Cells/MessageCell.swift +++ b/Session/Conversations/Message Cells/MessageCell.swift @@ -70,7 +70,8 @@ public class MessageCell: UITableViewCell { case .standardOutgoing, .standardIncoming, .standardIncomingDeleted: return VisibleMessageCell.self - case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, + case .infoClosedGroupCreated, .infoClosedGroupUpdated, + .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, .infoDisappearingMessagesUpdate, .infoScreenshotNotification, .infoMediaSavedNotification, .infoMessageRequestAccepted: return InfoMessageCell.self diff --git a/Session/Home/HomeViewModel.swift b/Session/Home/HomeViewModel.swift index 30f44b6d5..73d899a94 100644 --- a/Session/Home/HomeViewModel.swift +++ b/Session/Home/HomeViewModel.swift @@ -307,17 +307,26 @@ public class HomeViewModel { case .closedGroup: try MessageSender .leave(db, groupPublicKey: threadId) + .done { + Storage.shared.writeAsync { db in + _ = try SessionThread + .filter(id: threadId) + .deleteAll(db) + } + } + .catch { _ in + + } .retainUntilComplete() case .openGroup: OpenGroupManager.shared.delete(db, openGroupId: threadId) + _ = try SessionThread + .filter(id: threadId) + .deleteAll(db) default: break } - - _ = try SessionThread - .filter(id: threadId) - .deleteAll(db) } } } diff --git a/Session/Meta/Translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings index 6be84d9be..4329dadc7 100644 --- a/Session/Meta/Translations/de.lproj/Localizable.strings +++ b/Session/Meta/Translations/de.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index 7b4de01eb..3b4ec22ee 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings index 531c4cd22..4bf349817 100644 --- a/Session/Meta/Translations/es.lproj/Localizable.strings +++ b/Session/Meta/Translations/es.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings index 2a0170dc3..db8d61359 100644 --- a/Session/Meta/Translations/fa.lproj/Localizable.strings +++ b/Session/Meta/Translations/fa.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/fi.lproj/Localizable.strings b/Session/Meta/Translations/fi.lproj/Localizable.strings index d24651d21..d8b4a14b1 100644 --- a/Session/Meta/Translations/fi.lproj/Localizable.strings +++ b/Session/Meta/Translations/fi.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings index beea8bef7..485829208 100644 --- a/Session/Meta/Translations/fr.lproj/Localizable.strings +++ b/Session/Meta/Translations/fr.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/hi.lproj/Localizable.strings b/Session/Meta/Translations/hi.lproj/Localizable.strings index 79f708099..954e74054 100644 --- a/Session/Meta/Translations/hi.lproj/Localizable.strings +++ b/Session/Meta/Translations/hi.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/hr.lproj/Localizable.strings b/Session/Meta/Translations/hr.lproj/Localizable.strings index f76e43cf6..59fe0f037 100644 --- a/Session/Meta/Translations/hr.lproj/Localizable.strings +++ b/Session/Meta/Translations/hr.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings index 1f32b9335..d82fd6014 100644 --- a/Session/Meta/Translations/id-ID.lproj/Localizable.strings +++ b/Session/Meta/Translations/id-ID.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings index 7d34972cf..32b1bfc72 100644 --- a/Session/Meta/Translations/it.lproj/Localizable.strings +++ b/Session/Meta/Translations/it.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings index d548174c1..b2d5cf714 100644 --- a/Session/Meta/Translations/ja.lproj/Localizable.strings +++ b/Session/Meta/Translations/ja.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/nl.lproj/Localizable.strings b/Session/Meta/Translations/nl.lproj/Localizable.strings index c3acfc996..36a4ecf8d 100644 --- a/Session/Meta/Translations/nl.lproj/Localizable.strings +++ b/Session/Meta/Translations/nl.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings index f9b3a16fe..9505b5df1 100644 --- a/Session/Meta/Translations/pl.lproj/Localizable.strings +++ b/Session/Meta/Translations/pl.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings index 658cc1d23..2977aad75 100644 --- a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings +++ b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings index f650c8c4c..1f8cca0be 100644 --- a/Session/Meta/Translations/ru.lproj/Localizable.strings +++ b/Session/Meta/Translations/ru.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/si.lproj/Localizable.strings b/Session/Meta/Translations/si.lproj/Localizable.strings index 7af7c5365..76c4e66a8 100644 --- a/Session/Meta/Translations/si.lproj/Localizable.strings +++ b/Session/Meta/Translations/si.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/sk.lproj/Localizable.strings b/Session/Meta/Translations/sk.lproj/Localizable.strings index 2f6dc0039..582dd4281 100644 --- a/Session/Meta/Translations/sk.lproj/Localizable.strings +++ b/Session/Meta/Translations/sk.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/sv.lproj/Localizable.strings b/Session/Meta/Translations/sv.lproj/Localizable.strings index 481256826..e94364dcc 100644 --- a/Session/Meta/Translations/sv.lproj/Localizable.strings +++ b/Session/Meta/Translations/sv.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/th.lproj/Localizable.strings b/Session/Meta/Translations/th.lproj/Localizable.strings index 67f3f233e..1df1f2254 100644 --- a/Session/Meta/Translations/th.lproj/Localizable.strings +++ b/Session/Meta/Translations/th.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings index f6d6d5f3e..47c54b0bd 100644 --- a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings +++ b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings index 06a310228..43063bfee 100644 --- a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings index 9a14a5c83..815f05f54 100644 --- a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings @@ -616,3 +616,6 @@ "leave_group_confirmation_alert_title" = "Leave Group"; "leave_community_confirmation_alert_title" = "Leave Community"; "leave_community_confirmation_alert_message" = "Are you sure you want to leave %@?"; +"group_you_leaving" = "Leaving..."; +"group_leave_error" = "Failed to leave Group!"; +"group_unable_to_leave" = "Unable to leave the Group, please try again"; diff --git a/SessionMessagingKit/Database/Models/ControlMessageProcessRecord.swift b/SessionMessagingKit/Database/Models/ControlMessageProcessRecord.swift index c7cd38636..7540e35cc 100644 --- a/SessionMessagingKit/Database/Models/ControlMessageProcessRecord.swift +++ b/SessionMessagingKit/Database/Models/ControlMessageProcessRecord.swift @@ -151,7 +151,8 @@ internal extension ControlMessageProcessRecord { .infoClosedGroupCreated: return nil - case .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft: + case .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, + .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving: self.variant = .closedGroupControlMessage case .infoDisappearingMessagesUpdate: diff --git a/SessionMessagingKit/Database/Models/Interaction.swift b/SessionMessagingKit/Database/Models/Interaction.swift index fe244b8f0..2dcb64a82 100644 --- a/SessionMessagingKit/Database/Models/Interaction.swift +++ b/SessionMessagingKit/Database/Models/Interaction.swift @@ -73,6 +73,8 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu case infoClosedGroupCreated = 1000 case infoClosedGroupUpdated case infoClosedGroupCurrentUserLeft + case infoClosedGroupCurrentUserLeaving + case infoClosedGroupCurrentUserErrorLeaving case infoDisappearingMessagesUpdate = 2000 @@ -87,7 +89,7 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu public var isInfoMessage: Bool { switch self { - case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, + case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, .infoDisappearingMessagesUpdate, .infoScreenshotNotification, .infoMediaSavedNotification, .infoMessageRequestAccepted, .infoCall: return true @@ -106,7 +108,7 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu case .standardOutgoing, .standardIncomingDeleted: return false - case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, + case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, .infoDisappearingMessagesUpdate, .infoScreenshotNotification, .infoMediaSavedNotification, .infoMessageRequestAccepted: return false @@ -846,6 +848,8 @@ public extension Interaction { case .infoClosedGroupCreated: return "GROUP_CREATED".localized() case .infoClosedGroupCurrentUserLeft: return "GROUP_YOU_LEFT".localized() + case .infoClosedGroupCurrentUserLeaving: return "group_you_leaving".localized() + case .infoClosedGroupCurrentUserErrorLeaving: return "group_leave_error".localized() case .infoClosedGroupUpdated: return (body ?? "GROUP_UPDATED".localized()) case .infoMessageRequestAccepted: return (body ?? "MESSAGE_REQUESTS_ACCEPTED".localized()) diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift index 0d219b5b2..e565eaca0 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift @@ -493,7 +493,7 @@ extension MessageSender { let interaction: Interaction = try Interaction( threadId: thread.id, authorId: userPublicKey, - variant: .infoClosedGroupCurrentUserLeft, + variant: .infoClosedGroupCurrentUserLeaving, body: ClosedGroupControlMessage.Kind .memberLeft .infoMessage(db, sender: userPublicKey), @@ -529,6 +529,7 @@ extension MessageSender { publicKey: userPublicKey ) } + interaction.with() } .map { _ in } From 975812db95354ccd4a630aef65e6bf6fe16803aa Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 8 Mar 2023 11:13:37 +1100 Subject: [PATCH 06/32] WIP: update info message for user leaving a group --- .../Context Menu/ContextMenuVC+Action.swift | 3 +-- .../ConversationVC+Interaction.swift | 3 +-- .../Message Cells/MessageCell.swift | 3 +-- Session/Home/HomeViewModel.swift | 5 +---- .../Models/ControlMessageProcessRecord.swift | 3 +-- .../Database/Models/Interaction.swift | 8 ++----- .../MessageSender+ClosedGroups.swift | 21 ++++++++++++------- 7 files changed, 21 insertions(+), 25 deletions(-) diff --git a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift index a66dcfef3..04e652f8f 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift @@ -136,8 +136,7 @@ extension ContextMenuVC { switch cellViewModel.variant { case .standardIncomingDeleted, .infoCall, .infoScreenshotNotification, .infoMediaSavedNotification, - .infoClosedGroupCreated, .infoClosedGroupUpdated, - .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, + .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, .infoMessageRequestAccepted, .infoDisappearingMessagesUpdate: // Let the user delete info messages and unsent messages return [ Action.delete(cellViewModel, delegate) ] diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 980c0eb0c..a8ca98c6d 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -1694,8 +1694,7 @@ extension ConversationVC: switch cellViewModel.variant { case .standardIncomingDeleted, .infoCall, .infoScreenshotNotification, .infoMediaSavedNotification, - .infoClosedGroupCreated, .infoClosedGroupUpdated, - .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, + .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, .infoMessageRequestAccepted, .infoDisappearingMessagesUpdate: // Info messages and unsent messages should just trigger a local // deletion (they are created as side effects so we wouldn't be diff --git a/Session/Conversations/Message Cells/MessageCell.swift b/Session/Conversations/Message Cells/MessageCell.swift index 44886ba9c..1f7356bc2 100644 --- a/Session/Conversations/Message Cells/MessageCell.swift +++ b/Session/Conversations/Message Cells/MessageCell.swift @@ -70,8 +70,7 @@ public class MessageCell: UITableViewCell { case .standardOutgoing, .standardIncoming, .standardIncomingDeleted: return VisibleMessageCell.self - case .infoClosedGroupCreated, .infoClosedGroupUpdated, - .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, + case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, .infoDisappearingMessagesUpdate, .infoScreenshotNotification, .infoMediaSavedNotification, .infoMessageRequestAccepted: return InfoMessageCell.self diff --git a/Session/Home/HomeViewModel.swift b/Session/Home/HomeViewModel.swift index 73d899a94..5466ccb72 100644 --- a/Session/Home/HomeViewModel.swift +++ b/Session/Home/HomeViewModel.swift @@ -307,15 +307,12 @@ public class HomeViewModel { case .closedGroup: try MessageSender .leave(db, groupPublicKey: threadId) - .done { + .done { _ in Storage.shared.writeAsync { db in _ = try SessionThread .filter(id: threadId) .deleteAll(db) } - } - .catch { _ in - } .retainUntilComplete() diff --git a/SessionMessagingKit/Database/Models/ControlMessageProcessRecord.swift b/SessionMessagingKit/Database/Models/ControlMessageProcessRecord.swift index 7540e35cc..c7cd38636 100644 --- a/SessionMessagingKit/Database/Models/ControlMessageProcessRecord.swift +++ b/SessionMessagingKit/Database/Models/ControlMessageProcessRecord.swift @@ -151,8 +151,7 @@ internal extension ControlMessageProcessRecord { .infoClosedGroupCreated: return nil - case .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, - .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving: + case .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft: self.variant = .closedGroupControlMessage case .infoDisappearingMessagesUpdate: diff --git a/SessionMessagingKit/Database/Models/Interaction.swift b/SessionMessagingKit/Database/Models/Interaction.swift index 2dcb64a82..ad89bc463 100644 --- a/SessionMessagingKit/Database/Models/Interaction.swift +++ b/SessionMessagingKit/Database/Models/Interaction.swift @@ -73,8 +73,6 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu case infoClosedGroupCreated = 1000 case infoClosedGroupUpdated case infoClosedGroupCurrentUserLeft - case infoClosedGroupCurrentUserLeaving - case infoClosedGroupCurrentUserErrorLeaving case infoDisappearingMessagesUpdate = 2000 @@ -89,7 +87,7 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu public var isInfoMessage: Bool { switch self { - case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, + case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, .infoDisappearingMessagesUpdate, .infoScreenshotNotification, .infoMediaSavedNotification, .infoMessageRequestAccepted, .infoCall: return true @@ -108,7 +106,7 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu case .standardOutgoing, .standardIncomingDeleted: return false - case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, + case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, .infoDisappearingMessagesUpdate, .infoScreenshotNotification, .infoMediaSavedNotification, .infoMessageRequestAccepted: return false @@ -848,8 +846,6 @@ public extension Interaction { case .infoClosedGroupCreated: return "GROUP_CREATED".localized() case .infoClosedGroupCurrentUserLeft: return "GROUP_YOU_LEFT".localized() - case .infoClosedGroupCurrentUserLeaving: return "group_you_leaving".localized() - case .infoClosedGroupCurrentUserErrorLeaving: return "group_leave_error".localized() case .infoClosedGroupUpdated: return (body ?? "GROUP_UPDATED".localized()) case .infoMessageRequestAccepted: return (body ?? "MESSAGE_REQUESTS_ACCEPTED".localized()) diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift index e565eaca0..7456aea2c 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift @@ -478,7 +478,7 @@ extension MessageSender { /// unregisters from push notifications. /// /// The returned promise is fulfilled when the `MEMBER_LEFT` message has been sent to the group. - public static func leave(_ db: Database, groupPublicKey: String) throws -> Promise { + public static func leave(_ db: Database, groupPublicKey: String) throws -> Promise { guard let thread: SessionThread = try? SessionThread.fetchOne(db, id: groupPublicKey) else { SNLog("Can't leave nonexistent closed group.") return Promise(error: MessageSenderError.noThread) @@ -493,10 +493,8 @@ extension MessageSender { let interaction: Interaction = try Interaction( threadId: thread.id, authorId: userPublicKey, - variant: .infoClosedGroupCurrentUserLeaving, - body: ClosedGroupControlMessage.Kind - .memberLeft - .infoMessage(db, sender: userPublicKey), + variant: .infoClosedGroupCurrentUserLeft, + body: "group_you_leaving".localized(), timestampMs: SnodeAPI.currentOffsetTimestampMs() ).inserted(db) @@ -528,10 +526,19 @@ extension MessageSender { for: groupPublicKey, publicKey: userPublicKey ) + + try interaction.with( + body: ClosedGroupControlMessage.Kind + .memberLeft + .infoMessage(db, sender: userPublicKey) + ).update(db) } - interaction.with() + } - .map { _ in } + .map { _ in + return interactionId + } + // Update the group (if the admin leaves the group is disbanded) let wasAdminUser: Bool = try GroupMember From e37756ccf430eeef1b234b856550dfeaf97b92f9 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 8 Mar 2023 14:10:41 +1100 Subject: [PATCH 07/32] add leaving status for leaving groups --- Session/Home/HomeViewModel.swift | 14 +++- .../MessageSender+ClosedGroups.swift | 75 ++++++++++--------- 2 files changed, 50 insertions(+), 39 deletions(-) diff --git a/Session/Home/HomeViewModel.swift b/Session/Home/HomeViewModel.swift index 5466ccb72..888af3141 100644 --- a/Session/Home/HomeViewModel.swift +++ b/Session/Home/HomeViewModel.swift @@ -307,11 +307,17 @@ public class HomeViewModel { case .closedGroup: try MessageSender .leave(db, groupPublicKey: threadId) - .done { _ in + .done { (interactionId, error) in Storage.shared.writeAsync { db in - _ = try SessionThread - .filter(id: threadId) - .deleteAll(db) + if let _ = error { + try Interaction + .filter(id: interactionId) + .updateAll(db, Interaction.Columns.body.set(to: "group_leave_error".localized())) + } else { + _ = try SessionThread + .filter(id: threadId) + .deleteAll(db) + } } } .retainUntilComplete() diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift index 7456aea2c..a083885a5 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift @@ -478,7 +478,7 @@ extension MessageSender { /// unregisters from push notifications. /// /// The returned promise is fulfilled when the `MEMBER_LEFT` message has been sent to the group. - public static func leave(_ db: Database, groupPublicKey: String) throws -> Promise { + public static func leave(_ db: Database, groupPublicKey: String) throws -> Promise<(Int64, Error?)> { guard let thread: SessionThread = try? SessionThread.fetchOne(db, id: groupPublicKey) else { SNLog("Can't leave nonexistent closed group.") return Promise(error: MessageSenderError.noThread) @@ -503,42 +503,47 @@ extension MessageSender { } // Send the update to the group - let promise = try MessageSender - .sendNonDurably( - db, - message: ClosedGroupControlMessage( - kind: .memberLeft - ), - interactionId: interactionId, - in: thread - ) - .done { - // Remove the group from the database and unsubscribe from PNs - ClosedGroupPoller.shared.stopPolling(for: groupPublicKey) - - Storage.shared.write { db in - try closedGroup - .keyPairs - .deleteAll(db) - - let _ = PushNotificationAPI.performOperation( - .unsubscribe, - for: groupPublicKey, - publicKey: userPublicKey - ) + let (promise, seal) = Promise<(Int64, Error?)>.pending() + do { + try MessageSender + .sendNonDurably( + db, + message: ClosedGroupControlMessage( + kind: .memberLeft + ), + interactionId: interactionId, + in: thread + ) + .done { + // Remove the group from the database and unsubscribe from PNs + ClosedGroupPoller.shared.stopPolling(for: groupPublicKey) - try interaction.with( - body: ClosedGroupControlMessage.Kind - .memberLeft - .infoMessage(db, sender: userPublicKey) - ).update(db) + Storage.shared.write { db in + try closedGroup + .keyPairs + .deleteAll(db) + + let _ = PushNotificationAPI.performOperation( + .unsubscribe, + for: groupPublicKey, + publicKey: userPublicKey + ) + + try interaction.with( + body: ClosedGroupControlMessage.Kind + .memberLeft + .infoMessage(db, sender: userPublicKey) + ).update(db) + } + seal.fulfill((interactionId, nil)) } - - } - .map { _ in - return interactionId - } - + .catch { error in + seal.fulfill((interactionId, error)) + } + } + catch { + seal.fulfill((interactionId, error)) + } // Update the group (if the admin leaves the group is disbanded) let wasAdminUser: Bool = try GroupMember From f14982ed7bec35f93712171b25d68092a782d1b4 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 8 Mar 2023 14:17:19 +1100 Subject: [PATCH 08/32] minor fix --- Session/Closed Groups/EditClosedGroupVC.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Session/Closed Groups/EditClosedGroupVC.swift b/Session/Closed Groups/EditClosedGroupVC.swift index 1c67c9e25..5cbfd735a 100644 --- a/Session/Closed Groups/EditClosedGroupVC.swift +++ b/Session/Closed Groups/EditClosedGroupVC.swift @@ -451,7 +451,11 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat Storage.shared .writeAsync { db in if !updatedMemberIds.contains(userPublicKey) { - return try MessageSender.leave(db, groupPublicKey: threadId) + return try MessageSender + .leave(db, groupPublicKey: threadId) + .map { (_, error) in + if let error: Error = error { throw error } + } } return try MessageSender.update( From 102b4a67ad77f396ad90088d506a1df98523f418 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 8 Mar 2023 17:00:17 +1100 Subject: [PATCH 09/32] update UI and copy for group leaving status --- .../Context Menu/ContextMenuVC+Action.swift | 3 +- .../ConversationVC+Interaction.swift | 3 +- .../Message Cells/MessageCell.swift | 3 +- Session/Home/HomeViewModel.swift | 8 ++- Session/Shared/FullConversationCell.swift | 60 ++++++++++++++----- .../Models/ControlMessageProcessRecord.swift | 2 +- .../Database/Models/Interaction.swift | 13 +++- .../MessageSender+ClosedGroups.swift | 7 +-- 8 files changed, 71 insertions(+), 28 deletions(-) diff --git a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift index 04e652f8f..a66dcfef3 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift @@ -136,7 +136,8 @@ extension ContextMenuVC { switch cellViewModel.variant { case .standardIncomingDeleted, .infoCall, .infoScreenshotNotification, .infoMediaSavedNotification, - .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, + .infoClosedGroupCreated, .infoClosedGroupUpdated, + .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, .infoMessageRequestAccepted, .infoDisappearingMessagesUpdate: // Let the user delete info messages and unsent messages return [ Action.delete(cellViewModel, delegate) ] diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 037e39647..03e300e67 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -1706,7 +1706,8 @@ extension ConversationVC: switch cellViewModel.variant { case .standardIncomingDeleted, .infoCall, .infoScreenshotNotification, .infoMediaSavedNotification, - .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, + .infoClosedGroupCreated, .infoClosedGroupUpdated, + .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, .infoMessageRequestAccepted, .infoDisappearingMessagesUpdate: // Info messages and unsent messages should just trigger a local // deletion (they are created as side effects so we wouldn't be diff --git a/Session/Conversations/Message Cells/MessageCell.swift b/Session/Conversations/Message Cells/MessageCell.swift index 1f7356bc2..44886ba9c 100644 --- a/Session/Conversations/Message Cells/MessageCell.swift +++ b/Session/Conversations/Message Cells/MessageCell.swift @@ -70,7 +70,8 @@ public class MessageCell: UITableViewCell { case .standardOutgoing, .standardIncoming, .standardIncomingDeleted: return VisibleMessageCell.self - case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, + case .infoClosedGroupCreated, .infoClosedGroupUpdated, + .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, .infoDisappearingMessagesUpdate, .infoScreenshotNotification, .infoMediaSavedNotification, .infoMessageRequestAccepted: return InfoMessageCell.self diff --git a/Session/Home/HomeViewModel.swift b/Session/Home/HomeViewModel.swift index 888af3141..9b1d7f0cc 100644 --- a/Session/Home/HomeViewModel.swift +++ b/Session/Home/HomeViewModel.swift @@ -312,7 +312,13 @@ public class HomeViewModel { if let _ = error { try Interaction .filter(id: interactionId) - .updateAll(db, Interaction.Columns.body.set(to: "group_leave_error".localized())) + .updateAll( + db, + [ + Interaction.Columns.variant.set(to: Interaction.Variant.infoClosedGroupCurrentUserErrorLeaving), + Interaction.Columns.body.set(to: "group_unable_to_leave".localized()) + ] + ) } else { _ = try SessionThread .filter(id: threadId) diff --git a/Session/Shared/FullConversationCell.swift b/Session/Shared/FullConversationCell.swift index 9ab4b39fa..0b9ce6e9f 100644 --- a/Session/Shared/FullConversationCell.swift +++ b/Session/Shared/FullConversationCell.swift @@ -384,12 +384,32 @@ public final class FullConversationCell: UITableViewCell { typingIndicatorView.stopAnimation() ThemeManager.onThemeChange(observer: snippetLabel) { [weak self, weak snippetLabel] theme, _ in - guard let textColor: UIColor = theme.color(for: .textPrimary) else { return } - - snippetLabel?.attributedText = self?.getSnippet( - cellViewModel: cellViewModel, - textColor: textColor - ) + if cellViewModel.interactionVariant == .infoClosedGroupCurrentUserLeaving { + guard let textColor: UIColor = theme.color(for: .textSecondary) else { return } + + self?.displayNameLabel.themeTextColor = .textSecondary + + snippetLabel?.attributedText = self?.getSnippet( + cellViewModel: cellViewModel, + textColor: textColor + ) + } else if cellViewModel.interactionVariant == .infoClosedGroupCurrentUserErrorLeaving { + guard let textColor: UIColor = theme.color(for: .danger) else { return } + + snippetLabel?.attributedText = self?.getSnippet( + cellViewModel: cellViewModel, + textColor: textColor + ) + } else { + guard let textColor: UIColor = theme.color(for: .textPrimary) else { return } + + self?.displayNameLabel.themeTextColor = .textPrimary + + snippetLabel?.attributedText = self?.getSnippet( + cellViewModel: cellViewModel, + textColor: textColor + ) + } } } @@ -471,7 +491,10 @@ public final class FullConversationCell: UITableViewCell { )) } - if cellViewModel.threadVariant == .closedGroup || cellViewModel.threadVariant == .openGroup { + if + (cellViewModel.threadVariant == .closedGroup || cellViewModel.threadVariant == .openGroup) && + (![Interaction.Variant.infoClosedGroupCurrentUserErrorLeaving, Interaction.Variant.infoClosedGroupCurrentUserLeaving].contains(cellViewModel.interactionVariant)) + { let authorName: String = cellViewModel.authorName(for: cellViewModel.threadVariant) result.append(NSAttributedString( @@ -480,17 +503,22 @@ public final class FullConversationCell: UITableViewCell { )) } + let previewText: String = { + if cellViewModel.interactionVariant == .infoClosedGroupCurrentUserErrorLeaving { return "group_leave_error".localized() } + return Interaction.previewText( + variant: (cellViewModel.interactionVariant ?? .standardIncoming), + body: cellViewModel.interactionBody, + threadContactDisplayName: cellViewModel.threadContactName(), + authorDisplayName: cellViewModel.authorName(for: cellViewModel.threadVariant), + attachmentDescriptionInfo: cellViewModel.interactionAttachmentDescriptionInfo, + attachmentCount: cellViewModel.interactionAttachmentCount, + isOpenGroupInvitation: (cellViewModel.interactionIsOpenGroupInvitation == true) + ) + }() + result.append(NSAttributedString( string: MentionUtilities.highlightMentionsNoAttributes( - in: Interaction.previewText( - variant: (cellViewModel.interactionVariant ?? .standardIncoming), - body: cellViewModel.interactionBody, - threadContactDisplayName: cellViewModel.threadContactName(), - authorDisplayName: cellViewModel.authorName(for: cellViewModel.threadVariant), - attachmentDescriptionInfo: cellViewModel.interactionAttachmentDescriptionInfo, - attachmentCount: cellViewModel.interactionAttachmentCount, - isOpenGroupInvitation: (cellViewModel.interactionIsOpenGroupInvitation == true) - ), + in: previewText, threadVariant: cellViewModel.threadVariant, currentUserPublicKey: cellViewModel.currentUserPublicKey, currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey diff --git a/SessionMessagingKit/Database/Models/ControlMessageProcessRecord.swift b/SessionMessagingKit/Database/Models/ControlMessageProcessRecord.swift index c7cd38636..bc01ef67c 100644 --- a/SessionMessagingKit/Database/Models/ControlMessageProcessRecord.swift +++ b/SessionMessagingKit/Database/Models/ControlMessageProcessRecord.swift @@ -151,7 +151,7 @@ internal extension ControlMessageProcessRecord { .infoClosedGroupCreated: return nil - case .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft: + case .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving: self.variant = .closedGroupControlMessage case .infoDisappearingMessagesUpdate: diff --git a/SessionMessagingKit/Database/Models/Interaction.swift b/SessionMessagingKit/Database/Models/Interaction.swift index ad89bc463..f12b5af46 100644 --- a/SessionMessagingKit/Database/Models/Interaction.swift +++ b/SessionMessagingKit/Database/Models/Interaction.swift @@ -73,6 +73,8 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu case infoClosedGroupCreated = 1000 case infoClosedGroupUpdated case infoClosedGroupCurrentUserLeft + case infoClosedGroupCurrentUserErrorLeaving + case infoClosedGroupCurrentUserLeaving case infoDisappearingMessagesUpdate = 2000 @@ -87,7 +89,8 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu public var isInfoMessage: Bool { switch self { - case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, + case .infoClosedGroupCreated, .infoClosedGroupUpdated, + .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, .infoDisappearingMessagesUpdate, .infoScreenshotNotification, .infoMediaSavedNotification, .infoMessageRequestAccepted, .infoCall: return true @@ -106,7 +109,8 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu case .standardOutgoing, .standardIncomingDeleted: return false - case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, + case .infoClosedGroupCreated, .infoClosedGroupUpdated, + .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, .infoDisappearingMessagesUpdate, .infoScreenshotNotification, .infoMediaSavedNotification, .infoMessageRequestAccepted: return false @@ -399,6 +403,7 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu public extension Interaction { func with( + variant: Variant? = nil, serverHash: String? = nil, authorId: String? = nil, body: String? = nil, @@ -415,7 +420,7 @@ public extension Interaction { messageUuid: self.messageUuid, threadId: self.threadId, authorId: (authorId ?? self.authorId), - variant: self.variant, + variant: (variant ?? self.variant), body: (body ?? self.body), timestampMs: (timestampMs ?? self.timestampMs), receivedAtTimestampMs: self.receivedAtTimestampMs, @@ -846,6 +851,8 @@ public extension Interaction { case .infoClosedGroupCreated: return "GROUP_CREATED".localized() case .infoClosedGroupCurrentUserLeft: return "GROUP_YOU_LEFT".localized() + case .infoClosedGroupCurrentUserLeaving: return "group_you_leaving".localized() + case .infoClosedGroupCurrentUserErrorLeaving: return "group_unable_to_leave".localized() case .infoClosedGroupUpdated: return (body ?? "GROUP_UPDATED".localized()) case .infoMessageRequestAccepted: return (body ?? "MESSAGE_REQUESTS_ACCEPTED".localized()) diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift index a083885a5..61cc4dc99 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift @@ -493,7 +493,7 @@ extension MessageSender { let interaction: Interaction = try Interaction( threadId: thread.id, authorId: userPublicKey, - variant: .infoClosedGroupCurrentUserLeft, + variant: .infoClosedGroupCurrentUserLeaving, body: "group_you_leaving".localized(), timestampMs: SnodeAPI.currentOffsetTimestampMs() ).inserted(db) @@ -530,9 +530,8 @@ extension MessageSender { ) try interaction.with( - body: ClosedGroupControlMessage.Kind - .memberLeft - .infoMessage(db, sender: userPublicKey) + variant: .infoClosedGroupCurrentUserLeft, + body: "GROUP_YOU_LEFT".localized() ).update(db) } seal.fulfill((interactionId, nil)) From 282230c87a6e921fd97f3ea4bfcfda1cccac006c Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 8 Mar 2023 17:10:21 +1100 Subject: [PATCH 10/32] minor refactor --- .../Message Cells/InfoMessageCell.swift | 1 + Session/Shared/FullConversationCell.swift | 2 +- .../Database/Models/Interaction.swift | 12 +++++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Session/Conversations/Message Cells/InfoMessageCell.swift b/Session/Conversations/Message Cells/InfoMessageCell.swift index 7c4a90248..c1f7e63a1 100644 --- a/Session/Conversations/Message Cells/InfoMessageCell.swift +++ b/Session/Conversations/Message Cells/InfoMessageCell.swift @@ -97,6 +97,7 @@ final class InfoMessageCell: MessageCell { iconImageViewHeightConstraint.constant = (icon != nil) ? InfoMessageCell.iconSize : 0 self.label.text = cellViewModel.body + self.label.themeTextColor = (cellViewModel.variant == .infoClosedGroupCurrentUserErrorLeaving) ? .danger : .textPrimary } override func dynamicUpdate(with cellViewModel: MessageViewModel, playbackInfo: ConversationViewModel.PlaybackInfo?) { diff --git a/Session/Shared/FullConversationCell.swift b/Session/Shared/FullConversationCell.swift index 0b9ce6e9f..9d23bf031 100644 --- a/Session/Shared/FullConversationCell.swift +++ b/Session/Shared/FullConversationCell.swift @@ -493,7 +493,7 @@ public final class FullConversationCell: UITableViewCell { if (cellViewModel.threadVariant == .closedGroup || cellViewModel.threadVariant == .openGroup) && - (![Interaction.Variant.infoClosedGroupCurrentUserErrorLeaving, Interaction.Variant.infoClosedGroupCurrentUserLeaving].contains(cellViewModel.interactionVariant)) + (cellViewModel.interactionVariant?.isGroupControlMessage == false) { let authorName: String = cellViewModel.authorName(for: cellViewModel.threadVariant) diff --git a/SessionMessagingKit/Database/Models/Interaction.swift b/SessionMessagingKit/Database/Models/Interaction.swift index f12b5af46..6ec1f1542 100644 --- a/SessionMessagingKit/Database/Models/Interaction.swift +++ b/SessionMessagingKit/Database/Models/Interaction.swift @@ -89,7 +89,7 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu public var isInfoMessage: Bool { switch self { - case .infoClosedGroupCreated, .infoClosedGroupUpdated, + case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving, .infoDisappearingMessagesUpdate, .infoScreenshotNotification, .infoMediaSavedNotification, .infoMessageRequestAccepted, .infoCall: @@ -100,6 +100,16 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu } } + public var isGroupControlMessage: Bool { + switch self { + case .infoClosedGroupCreated, .infoClosedGroupUpdated, + .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving: + return true + default: + return false + } + } + /// This flag controls whether the `wasRead` flag is automatically set to true based on the message variant (as a result it they will /// or won't affect the unread count) fileprivate var canBeUnread: Bool { From 5ec51a99c67038092c452b7d486ca1239678c463 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 10 Mar 2023 11:20:36 +1100 Subject: [PATCH 11/32] move removing group member record logic after the leaving message is successfully sent --- .../MessageSender+ClosedGroups.swift | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift index 61cc4dc99..f0bc407ed 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift @@ -533,6 +533,25 @@ extension MessageSender { variant: .infoClosedGroupCurrentUserLeft, body: "GROUP_YOU_LEFT".localized() ).update(db) + + // Update the group (if the admin leaves the group is disbanded) + let wasAdminUser: Bool = try GroupMember + .filter(GroupMember.Columns.groupId == thread.id) + .filter(GroupMember.Columns.profileId == userPublicKey) + .filter(GroupMember.Columns.role == GroupMember.Role.admin) + .isNotEmpty(db) + + if wasAdminUser { + try GroupMember + .filter(GroupMember.Columns.groupId == thread.id) + .deleteAll(db) + } + else { + try GroupMember + .filter(GroupMember.Columns.groupId == thread.id) + .filter(GroupMember.Columns.profileId == userPublicKey) + .deleteAll(db) + } } seal.fulfill((interactionId, nil)) } @@ -544,25 +563,6 @@ extension MessageSender { seal.fulfill((interactionId, error)) } - // Update the group (if the admin leaves the group is disbanded) - let wasAdminUser: Bool = try GroupMember - .filter(GroupMember.Columns.groupId == thread.id) - .filter(GroupMember.Columns.profileId == userPublicKey) - .filter(GroupMember.Columns.role == GroupMember.Role.admin) - .isNotEmpty(db) - - if wasAdminUser { - try GroupMember - .filter(GroupMember.Columns.groupId == thread.id) - .deleteAll(db) - } - else { - try GroupMember - .filter(GroupMember.Columns.groupId == thread.id) - .filter(GroupMember.Columns.profileId == userPublicKey) - .deleteAll(db) - } - // Return return promise } From bf08394ebddd255371ae7b6dde4bb9bb3336c1cb Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 10 Mar 2023 13:25:42 +1100 Subject: [PATCH 12/32] change the title back to text primary colour when failed to leave a group --- Session/Shared/FullConversationCell.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Session/Shared/FullConversationCell.swift b/Session/Shared/FullConversationCell.swift index 9d23bf031..61f61e2a0 100644 --- a/Session/Shared/FullConversationCell.swift +++ b/Session/Shared/FullConversationCell.swift @@ -396,6 +396,8 @@ public final class FullConversationCell: UITableViewCell { } else if cellViewModel.interactionVariant == .infoClosedGroupCurrentUserErrorLeaving { guard let textColor: UIColor = theme.color(for: .danger) else { return } + self?.displayNameLabel.themeTextColor = .textPrimary + snippetLabel?.attributedText = self?.getSnippet( cellViewModel: cellViewModel, textColor: textColor From 079d6f8c9f14c70605764a66441c48f0cc44bc7f Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 10 Mar 2023 14:04:29 +1100 Subject: [PATCH 13/32] disable the swipe actions when in the "leaving" state --- Session/Home/HomeVC.swift | 2 ++ SessionMessagingKit/Database/Models/Interaction.swift | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index d95c76515..736a16d86 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -627,6 +627,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi return nil case .threads: let threadViewModel: SessionThreadViewModel = section.elements[indexPath.row] + if threadViewModel.interactionVariant?.isGroupLeavingStatus == true { return nil } let hasUnread: Bool = (threadViewModel.threadUnreadCount ?? 0) > 0 let mark: UIContextualAction = UIContextualAction( title: ((hasUnread) ? "mark_read_button_text".localized() : "mark_unread_button_text".localized()), @@ -686,6 +687,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi case .threads: let threadViewModel: SessionThreadViewModel = section.elements[indexPath.row] + if threadViewModel.interactionVariant?.isGroupLeavingStatus == true { return nil } let pin: UIContextualAction = UIContextualAction( title: (threadViewModel.threadIsPinned ? "UNPIN_BUTTON_TEXT".localized() : "PIN_BUTTON_TEXT".localized()), diff --git a/SessionMessagingKit/Database/Models/Interaction.swift b/SessionMessagingKit/Database/Models/Interaction.swift index 6ec1f1542..4bd0da58c 100644 --- a/SessionMessagingKit/Database/Models/Interaction.swift +++ b/SessionMessagingKit/Database/Models/Interaction.swift @@ -110,6 +110,15 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu } } + public var isGroupLeavingStatus: Bool { + switch self { + case .infoClosedGroupCurrentUserLeft, .infoClosedGroupCurrentUserLeaving, .infoClosedGroupCurrentUserErrorLeaving: + return true + default: + return false + } + } + /// This flag controls whether the `wasRead` flag is automatically set to true based on the message variant (as a result it they will /// or won't affect the unread count) fileprivate var canBeUnread: Bool { From 034b67d6a3f783dcaed4295e50716810e223714e Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 10 Mar 2023 15:35:42 +1100 Subject: [PATCH 14/32] fix an issue where the group won't be deleted --- .../Database/Models/Interaction.swift | 3 +-- .../MessageSender+ClosedGroups.swift | 13 +++++++++---- .../Shared Models/SessionThreadViewModel.swift | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/SessionMessagingKit/Database/Models/Interaction.swift b/SessionMessagingKit/Database/Models/Interaction.swift index 4bd0da58c..0fd032333 100644 --- a/SessionMessagingKit/Database/Models/Interaction.swift +++ b/SessionMessagingKit/Database/Models/Interaction.swift @@ -422,7 +422,6 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu public extension Interaction { func with( - variant: Variant? = nil, serverHash: String? = nil, authorId: String? = nil, body: String? = nil, @@ -439,7 +438,7 @@ public extension Interaction { messageUuid: self.messageUuid, threadId: self.threadId, authorId: (authorId ?? self.authorId), - variant: (variant ?? self.variant), + variant: self.variant, body: (body ?? self.body), timestampMs: (timestampMs ?? self.timestampMs), receivedAtTimestampMs: self.receivedAtTimestampMs, diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift index f0bc407ed..6fc0b8dd7 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift @@ -529,10 +529,15 @@ extension MessageSender { publicKey: userPublicKey ) - try interaction.with( - variant: .infoClosedGroupCurrentUserLeft, - body: "GROUP_YOU_LEFT".localized() - ).update(db) + try Interaction + .filter(id: interactionId) + .updateAll( + db, + [ + Interaction.Columns.variant.set(to: Interaction.Variant.infoClosedGroupCurrentUserLeft), + Interaction.Columns.body.set(to: "GROUP_YOU_LEFT".localized()) + ] + ) // Update the group (if the admin leaves the group is disbanded) let wasAdminUser: Bool = try GroupMember diff --git a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift index 02e614aeb..0b66cd78f 100644 --- a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift +++ b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift @@ -100,7 +100,7 @@ public struct SessionThreadViewModel: FetchableRecordWithRowId, Decodable, Equat public var canWrite: Bool { switch threadVariant { case .contact: return true - case .closedGroup: return currentUserIsClosedGroupMember == true + case .closedGroup: return (currentUserIsClosedGroupMember == true) && (interactionVariant?.isGroupLeavingStatus != true) case .openGroup: return openGroupPermissions?.contains(.write) ?? false } } From 51d8eea68cf915b3328b23ab9faa2ac7018e40d3 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 10 Mar 2023 15:50:17 +1100 Subject: [PATCH 15/32] clean --- Session/Home/HomeVC.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index 736a16d86..34c85d664 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -627,7 +627,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi return nil case .threads: let threadViewModel: SessionThreadViewModel = section.elements[indexPath.row] - if threadViewModel.interactionVariant?.isGroupLeavingStatus == true { return nil } + guard threadViewModel.interactionVariant?.isGroupLeavingStatus != true else { return nil } let hasUnread: Bool = (threadViewModel.threadUnreadCount ?? 0) > 0 let mark: UIContextualAction = UIContextualAction( title: ((hasUnread) ? "mark_read_button_text".localized() : "mark_unread_button_text".localized()), @@ -687,7 +687,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi case .threads: let threadViewModel: SessionThreadViewModel = section.elements[indexPath.row] - if threadViewModel.interactionVariant?.isGroupLeavingStatus == true { return nil } + guard threadViewModel.interactionVariant != .infoClosedGroupCurrentUserLeaving else { return nil } let pin: UIContextualAction = UIContextualAction( title: (threadViewModel.threadIsPinned ? "UNPIN_BUTTON_TEXT".localized() : "PIN_BUTTON_TEXT".localized()), From 6f5052c0da27ff270aeef48cf33e1fe6737e073e Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 14 Mar 2023 13:04:03 +1100 Subject: [PATCH 16/32] WIP: make group leaving a job --- Session.xcodeproj/project.pbxproj | 4 + .../Jobs/Types/GroupLeavingJob.swift | 74 +++++++++++++++++++ SessionUtilitiesKit/Database/Models/Job.swift | 4 + 3 files changed, 82 insertions(+) create mode 100644 SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 5c951a648..15be4fe34 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -114,6 +114,7 @@ 7B4C75CB26B37E0F0000AC89 /* UnsendRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4C75CA26B37E0F0000AC89 /* UnsendRequest.swift */; }; 7B4C75CD26BB92060000AC89 /* DeletedMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */; }; 7B50D64D28AC7CF80086CCEC /* silence.aiff in Resources */ = {isa = PBXBuildFile; fileRef = 7B50D64C28AC7CF80086CCEC /* silence.aiff */; }; + 7B521E0A29BFF84400C3C36A /* GroupLeavingJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B521E0929BFF84400C3C36A /* GroupLeavingJob.swift */; }; 7B7037432834B81F000DCF35 /* ReactionContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7037422834B81F000DCF35 /* ReactionContainerView.swift */; }; 7B7037452834BCC0000DCF35 /* ReactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7037442834BCC0000DCF35 /* ReactionView.swift */; }; 7B7CB18E270D066F0079FF93 /* IncomingCallBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7CB18D270D066F0079FF93 /* IncomingCallBanner.swift */; }; @@ -1183,6 +1184,7 @@ 7B4C75CA26B37E0F0000AC89 /* UnsendRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsendRequest.swift; sourceTree = ""; }; 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedMessageView.swift; sourceTree = ""; }; 7B50D64C28AC7CF80086CCEC /* silence.aiff */ = {isa = PBXFileReference; lastKnownFileType = audio.aiff; path = silence.aiff; sourceTree = ""; }; + 7B521E0929BFF84400C3C36A /* GroupLeavingJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupLeavingJob.swift; sourceTree = ""; }; 7B7037422834B81F000DCF35 /* ReactionContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionContainerView.swift; sourceTree = ""; }; 7B7037442834BCC0000DCF35 /* ReactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionView.swift; sourceTree = ""; }; 7B7CB18D270D066F0079FF93 /* IncomingCallBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncomingCallBanner.swift; sourceTree = ""; }; @@ -4136,6 +4138,7 @@ FDF0B74E28079E5E004C14C5 /* SendReadReceiptsJob.swift */, C352A348255781F400338F3E /* AttachmentDownloadJob.swift */, C352A35A2557824E00338F3E /* AttachmentUploadJob.swift */, + 7B521E0929BFF84400C3C36A /* GroupLeavingJob.swift */, ); path = Types; sourceTree = ""; @@ -5406,6 +5409,7 @@ C3471F4C25553AB000297E91 /* MessageReceiver+Decryption.swift in Sources */, FD245C672850665E00B966DD /* AttachmentDownloadJob.swift in Sources */, C300A5D32554B05A00555489 /* TypingIndicator.swift in Sources */, + 7B521E0A29BFF84400C3C36A /* GroupLeavingJob.swift in Sources */, FD09799927FFC1A300936362 /* Attachment.swift in Sources */, FD245C5F2850662200B966DD /* OWSWindowManager.m in Sources */, C3471ECB2555356A00297E91 /* MessageSender+Encryption.swift in Sources */, diff --git a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift new file mode 100644 index 000000000..422d46b49 --- /dev/null +++ b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift @@ -0,0 +1,74 @@ +// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. + +import Foundation +import GRDB +import PromiseKit +import SignalCoreKit +import SessionUtilitiesKit +import SessionSnodeKit + +public enum GroupLeavingJob: JobExecutor { + public static var maxFailureCount: Int = -1 + public static var requiresThreadId: Bool = true + public static var requiresInteractionId: Bool = true + + public static func run( + _ job: SessionUtilitiesKit.Job, + queue: DispatchQueue, + success: @escaping (SessionUtilitiesKit.Job, Bool) -> (), + failure: @escaping (SessionUtilitiesKit.Job, Error?, Bool) -> (), + deferred: @escaping (SessionUtilitiesKit.Job) -> ()) + { + guard + let detailsData: Data = job.details, + let details: Details = try? JSONDecoder().decode(Details.self, from: detailsData) + else { + failure(job, JobRunnerError.missingRequiredDetails, false) + return + } + + } +} + +// MARK: - GroupLeavingJob.Details + +extension GroupLeavingJob { + public struct Details: Codable { + private enum CodingKeys: String, CodingKey { + case infoMessageInteractionId + case groupPublicKey + } + + public let infoMessageInteractionId: Int64 + public let groupPublicKey: String + + // MARK: - Initialization + + public init( + infoMessageInteractionId: Int64, + groupPublicKey: String + ) { + self.infoMessageInteractionId = infoMessageInteractionId + self.groupPublicKey = groupPublicKey + } + + // MARK: - Codable + + public init(from decoder: Decoder) throws { + let container: KeyedDecodingContainer = try decoder.container(keyedBy: CodingKeys.self) + + self = Details( + infoMessageInteractionId: try container.decode(Int64.self, forKey: .infoMessageInteractionId), + groupPublicKey: try container.decode(String.self, forKey: .groupPublicKey) + ) + } + + public func encode(to encoder: Encoder) throws { + var container: KeyedEncodingContainer = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(infoMessageInteractionId, forKey: .infoMessageInteractionId) + try container.encode(groupPublicKey, forKey: .groupPublicKey) + } + } +} + diff --git a/SessionUtilitiesKit/Database/Models/Job.swift b/SessionUtilitiesKit/Database/Models/Job.swift index 037d83fc3..eb494d3e1 100644 --- a/SessionUtilitiesKit/Database/Models/Job.swift +++ b/SessionUtilitiesKit/Database/Models/Job.swift @@ -102,6 +102,10 @@ public struct Job: Codable, Equatable, Identifiable, FetchableRecord, MutablePer /// This is a job that runs once whenever an attachment is downloaded to attempt to decode and properly /// download the attachment case attachmentDownload + + /// This is a job that runs once whenever the user leaves a group to send a group leaving message, remove group + /// record and group member record + case groupLeaving } public enum Behaviour: Int, Codable, DatabaseValueConvertible, CaseIterable { From 2e7325ce9ac55b14fcd664274858d1587c39d2bf Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 14 Mar 2023 13:46:52 +1100 Subject: [PATCH 17/32] minor fix --- Session.xcodeproj/project.pbxproj | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index b34b5c5fb..3fe233afe 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -124,6 +124,7 @@ 7B81682828B310D50069F315 /* _007_HomeQueryOptimisationIndexes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81682728B310D50069F315 /* _007_HomeQueryOptimisationIndexes.swift */; }; 7B81682A28B6F1420069F315 /* ReactionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81682928B6F1420069F315 /* ReactionResponse.swift */; }; 7B81682C28B72F480069F315 /* PendingChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81682B28B72F480069F315 /* PendingChange.swift */; }; + 7B89FF4629C016E300C4C708 /* _012_AddFTSIfNeeded.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B89FF4529C016E300C4C708 /* _012_AddFTSIfNeeded.swift */; }; 7B8C44C528B49DDA00FBE25F /* NewConversationVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8C44C428B49DDA00FBE25F /* NewConversationVC.swift */; }; 7B8D5FC428332600008324D9 /* VisibleMessage+Reaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8D5FC328332600008324D9 /* VisibleMessage+Reaction.swift */; }; 7B93D06A27CF173D00811CB6 /* MessageRequestsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B93D06927CF173D00811CB6 /* MessageRequestsViewController.swift */; }; @@ -1185,7 +1186,6 @@ 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedMessageView.swift; sourceTree = ""; }; 7B50D64C28AC7CF80086CCEC /* silence.aiff */ = {isa = PBXFileReference; lastKnownFileType = audio.aiff; path = silence.aiff; sourceTree = ""; }; 7B521E0929BFF84400C3C36A /* GroupLeavingJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupLeavingJob.swift; sourceTree = ""; }; - 7B521E0729BFEAFF00C3C36A /* _012_AddFTSIfNeeded.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _012_AddFTSIfNeeded.swift; sourceTree = ""; }; 7B7037422834B81F000DCF35 /* ReactionContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionContainerView.swift; sourceTree = ""; }; 7B7037442834BCC0000DCF35 /* ReactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionView.swift; sourceTree = ""; }; 7B7CB18D270D066F0079FF93 /* IncomingCallBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncomingCallBanner.swift; sourceTree = ""; }; @@ -1195,6 +1195,7 @@ 7B81682728B310D50069F315 /* _007_HomeQueryOptimisationIndexes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = _007_HomeQueryOptimisationIndexes.swift; sourceTree = ""; }; 7B81682928B6F1420069F315 /* ReactionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionResponse.swift; sourceTree = ""; }; 7B81682B28B72F480069F315 /* PendingChange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PendingChange.swift; sourceTree = ""; }; + 7B89FF4529C016E300C4C708 /* _012_AddFTSIfNeeded.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = _012_AddFTSIfNeeded.swift; sourceTree = ""; }; 7B8C44C428B49DDA00FBE25F /* NewConversationVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationVC.swift; sourceTree = ""; }; 7B8D5FC328332600008324D9 /* VisibleMessage+Reaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+Reaction.swift"; sourceTree = ""; }; 7B93D06927CF173D00811CB6 /* MessageRequestsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRequestsViewController.swift; sourceTree = ""; }; @@ -3553,7 +3554,7 @@ 7BAA7B6528D2DE4700AE1489 /* _009_OpenGroupPermission.swift */, FD7115F128C6CB3900B47552 /* _010_AddThreadIdToFTS.swift */, FD432431299C6933008A0213 /* _011_AddPendingReadReceipts.swift */, - 7B521E0729BFEAFF00C3C36A /* _012_AddFTSIfNeeded.swift */, + 7B89FF4529C016E300C4C708 /* _012_AddFTSIfNeeded.swift */, ); path = Migrations; sourceTree = ""; @@ -5406,6 +5407,7 @@ buildActionMask = 2147483647; files = ( 7B81682828B310D50069F315 /* _007_HomeQueryOptimisationIndexes.swift in Sources */, + 7B89FF4629C016E300C4C708 /* _012_AddFTSIfNeeded.swift in Sources */, FD245C52285065D500B966DD /* SignalAttachment.swift in Sources */, B8856D08256F10F1001CE70E /* DeviceSleepManager.swift in Sources */, C3471F4C25553AB000297E91 /* MessageReceiver+Decryption.swift in Sources */, @@ -5442,7 +5444,6 @@ FD09797527FAB64300936362 /* ProfileManager.swift in Sources */, FD245C57285065F100B966DD /* Poller.swift in Sources */, FDA8EAFE280E8B78002B68E5 /* FailedMessageSendsJob.swift in Sources */, - 7B521E0829BFEAFF00C3C36A /* _012_AddFTSIfNeeded.swift in Sources */, FD245C6A2850666F00B966DD /* FileServerAPI.swift in Sources */, FDC4386927B4E6B800C60D73 /* String+Utlities.swift in Sources */, FD716E6628502EE200C96BF4 /* CurrentCallProtocol.swift in Sources */, From f8fecaca0b8a6931a508cbaeb10b3d5b653590cd Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 14 Mar 2023 15:06:57 +1100 Subject: [PATCH 18/32] make group leaving a job --- .../Jobs/Types/GroupLeavingJob.swift | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift index 422d46b49..73e83aef7 100644 --- a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift +++ b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift @@ -27,6 +27,90 @@ public enum GroupLeavingJob: JobExecutor { return } + guard let thread: SessionThread = Storage.shared.read({ db in try? SessionThread.fetchOne(db, id: details.groupPublicKey)}) else { + SNLog("Can't leave nonexistent closed group.") + failure(job, MessageSenderError.noThread, false) + return + } + + guard let closedGroup: ClosedGroup = Storage.shared.read({ db in try? thread.closedGroup.fetchOne(db)}) else { + failure(job, MessageSenderError.invalidClosedGroupUpdate, false) + return + } + + Storage.shared.writeAsync { db -> Promise in + try MessageSender.sendNonDurably( + db, + message: ClosedGroupControlMessage( + kind: .memberLeft + ), + interactionId: details.infoMessageInteractionId, + in: thread + ) + } + .done(on: queue) { _ in + // Remove the group from the database and unsubscribe from PNs + ClosedGroupPoller.shared.stopPolling(for: details.groupPublicKey) + + Storage.shared.write { db in + let userPublicKey: String = getUserHexEncodedPublicKey(db) + + try closedGroup + .keyPairs + .deleteAll(db) + + let _ = PushNotificationAPI.performOperation( + .unsubscribe, + for: details.groupPublicKey, + publicKey: userPublicKey + ) + + try Interaction + .filter(id: details.infoMessageInteractionId) + .updateAll( + db, + [ + Interaction.Columns.variant.set(to: Interaction.Variant.infoClosedGroupCurrentUserLeft), + Interaction.Columns.body.set(to: "GROUP_YOU_LEFT".localized()) + ] + ) + + // Update the group (if the admin leaves the group is disbanded) + let wasAdminUser: Bool = try GroupMember + .filter(GroupMember.Columns.groupId == thread.id) + .filter(GroupMember.Columns.profileId == userPublicKey) + .filter(GroupMember.Columns.role == GroupMember.Role.admin) + .isNotEmpty(db) + + if wasAdminUser { + try GroupMember + .filter(GroupMember.Columns.groupId == thread.id) + .deleteAll(db) + } + else { + try GroupMember + .filter(GroupMember.Columns.groupId == thread.id) + .filter(GroupMember.Columns.profileId == userPublicKey) + .deleteAll(db) + } + } + success(job, false) + } + .catch(on: queue) { error in + Storage.shared.write { db in + try Interaction + .filter(id: details.infoMessageInteractionId) + .updateAll( + db, + [ + Interaction.Columns.variant.set(to: Interaction.Variant.infoClosedGroupCurrentUserErrorLeaving), + Interaction.Columns.body.set(to: "group_unable_to_leave".localized()) + ] + ) + } + } + .retainUntilComplete() + } } From eed8b1dfcbdd7bc96c3ddde5036fe7fc8d979c17 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 14 Mar 2023 15:25:12 +1100 Subject: [PATCH 19/32] delete thread after leaving group succeeds --- .../Jobs/Types/GroupLeavingJob.swift | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift index 73e83aef7..dd8068b3f 100644 --- a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift +++ b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift @@ -93,6 +93,12 @@ public enum GroupLeavingJob: JobExecutor { .filter(GroupMember.Columns.profileId == userPublicKey) .deleteAll(db) } + + if details.deleteThreadAfterSuccess { + _ = try SessionThread + .filter(id: thread.id) + .deleteAll(db) + } } success(job, false) } @@ -121,19 +127,23 @@ extension GroupLeavingJob { private enum CodingKeys: String, CodingKey { case infoMessageInteractionId case groupPublicKey + case deleteThreadAfterSuccess } public let infoMessageInteractionId: Int64 public let groupPublicKey: String + public let deleteThreadAfterSuccess: Bool // MARK: - Initialization public init( infoMessageInteractionId: Int64, - groupPublicKey: String + groupPublicKey: String, + deleteThreadAfterSuccess: Bool ) { self.infoMessageInteractionId = infoMessageInteractionId self.groupPublicKey = groupPublicKey + self.deleteThreadAfterSuccess = deleteThreadAfterSuccess } // MARK: - Codable @@ -143,7 +153,8 @@ extension GroupLeavingJob { self = Details( infoMessageInteractionId: try container.decode(Int64.self, forKey: .infoMessageInteractionId), - groupPublicKey: try container.decode(String.self, forKey: .groupPublicKey) + groupPublicKey: try container.decode(String.self, forKey: .groupPublicKey), + deleteThreadAfterSuccess: try container.decode(Bool.self, forKey: .deleteThreadAfterSuccess) ) } @@ -152,6 +163,7 @@ extension GroupLeavingJob { try container.encode(infoMessageInteractionId, forKey: .infoMessageInteractionId) try container.encode(groupPublicKey, forKey: .groupPublicKey) + try container.encode(deleteThreadAfterSuccess, forKey: .deleteThreadAfterSuccess) } } } From cea2e1522dbbe69c2c2099b8a5e1811646e3ce9e Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 14 Mar 2023 17:08:38 +1100 Subject: [PATCH 20/32] WIP: make group leaving a job --- Session/Closed Groups/EditClosedGroupVC.swift | 11 +-- .../Settings/ThreadSettingsViewModel.swift | 2 +- Session/Home/HomeViewModel.swift | 27 ++---- SessionMessagingKit/Configuration.swift | 1 + .../Jobs/Types/GroupLeavingJob.swift | 29 +++--- .../MessageSender+ClosedGroups.swift | 90 +++---------------- .../Sending & Receiving/MessageSender.swift | 23 ----- SessionUtilitiesKit/JobRunner/JobRunner.swift | 3 +- 8 files changed, 40 insertions(+), 146 deletions(-) diff --git a/Session/Closed Groups/EditClosedGroupVC.swift b/Session/Closed Groups/EditClosedGroupVC.swift index 5cbfd735a..2a04c703f 100644 --- a/Session/Closed Groups/EditClosedGroupVC.swift +++ b/Session/Closed Groups/EditClosedGroupVC.swift @@ -451,11 +451,12 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat Storage.shared .writeAsync { db in if !updatedMemberIds.contains(userPublicKey) { - return try MessageSender - .leave(db, groupPublicKey: threadId) - .map { (_, error) in - if let error: Error = error { throw error } - } + try MessageSender.leave( + db, + groupPublicKey: threadId, + deleteThread: false + ) + return Promise.value(()) } return try MessageSender.update( diff --git a/Session/Conversations/Settings/ThreadSettingsViewModel.swift b/Session/Conversations/Settings/ThreadSettingsViewModel.swift index 21732ffda..bc99c9f00 100644 --- a/Session/Conversations/Settings/ThreadSettingsViewModel.swift +++ b/Session/Conversations/Settings/ThreadSettingsViewModel.swift @@ -405,7 +405,7 @@ class ThreadSettingsViewModel: SessionTableViewModel = try decoder.container(keyedBy: CodingKeys.self) self = Details( - infoMessageInteractionId: try container.decode(Int64.self, forKey: .infoMessageInteractionId), groupPublicKey: try container.decode(String.self, forKey: .groupPublicKey), - deleteThreadAfterSuccess: try container.decode(Bool.self, forKey: .deleteThreadAfterSuccess) + deleteThread: try container.decode(Bool.self, forKey: .deleteThread) ) } public func encode(to encoder: Encoder) throws { var container: KeyedEncodingContainer = encoder.container(keyedBy: CodingKeys.self) - try container.encode(infoMessageInteractionId, forKey: .infoMessageInteractionId) try container.encode(groupPublicKey, forKey: .groupPublicKey) - try container.encode(deleteThreadAfterSuccess, forKey: .deleteThreadAfterSuccess) + try container.encode(deleteThread, forKey: .deleteThread) } } } diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift index 6fc0b8dd7..2c39666cb 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift @@ -478,13 +478,9 @@ extension MessageSender { /// unregisters from push notifications. /// /// The returned promise is fulfilled when the `MEMBER_LEFT` message has been sent to the group. - public static func leave(_ db: Database, groupPublicKey: String) throws -> Promise<(Int64, Error?)> { + public static func leave(_ db: Database, groupPublicKey: String, deleteThread: Bool) throws { guard let thread: SessionThread = try? SessionThread.fetchOne(db, id: groupPublicKey) else { - SNLog("Can't leave nonexistent closed group.") - return Promise(error: MessageSenderError.noThread) - } - guard let closedGroup: ClosedGroup = try? thread.closedGroup.fetchOne(db) else { - return Promise(error: MessageSenderError.invalidClosedGroupUpdate) + return } let userPublicKey: String = getUserHexEncodedPublicKey(db) @@ -498,78 +494,18 @@ extension MessageSender { timestampMs: SnodeAPI.currentOffsetTimestampMs() ).inserted(db) - guard let interactionId: Int64 = interaction.id else { - throw StorageError.objectNotSaved - } - - // Send the update to the group - let (promise, seal) = Promise<(Int64, Error?)>.pending() - do { - try MessageSender - .sendNonDurably( - db, - message: ClosedGroupControlMessage( - kind: .memberLeft - ), - interactionId: interactionId, - in: thread + JobRunner.add( + db, + job: Job( + variant: .groupLeaving, + threadId: thread.id, + interactionId: interaction.id, + details: GroupLeavingJob.Details( + groupPublicKey: groupPublicKey, + deleteThread: deleteThread ) - .done { - // Remove the group from the database and unsubscribe from PNs - ClosedGroupPoller.shared.stopPolling(for: groupPublicKey) - - Storage.shared.write { db in - try closedGroup - .keyPairs - .deleteAll(db) - - let _ = PushNotificationAPI.performOperation( - .unsubscribe, - for: groupPublicKey, - publicKey: userPublicKey - ) - - try Interaction - .filter(id: interactionId) - .updateAll( - db, - [ - Interaction.Columns.variant.set(to: Interaction.Variant.infoClosedGroupCurrentUserLeft), - Interaction.Columns.body.set(to: "GROUP_YOU_LEFT".localized()) - ] - ) - - // Update the group (if the admin leaves the group is disbanded) - let wasAdminUser: Bool = try GroupMember - .filter(GroupMember.Columns.groupId == thread.id) - .filter(GroupMember.Columns.profileId == userPublicKey) - .filter(GroupMember.Columns.role == GroupMember.Role.admin) - .isNotEmpty(db) - - if wasAdminUser { - try GroupMember - .filter(GroupMember.Columns.groupId == thread.id) - .deleteAll(db) - } - else { - try GroupMember - .filter(GroupMember.Columns.groupId == thread.id) - .filter(GroupMember.Columns.profileId == userPublicKey) - .deleteAll(db) - } - } - seal.fulfill((interactionId, nil)) - } - .catch { error in - seal.fulfill((interactionId, error)) - } - } - catch { - seal.fulfill((interactionId, error)) - } - - // Return - return promise + ) + ) } /* diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 32bb8cbc5..8c1211f2e 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -763,26 +763,3 @@ public final class MessageSender { } } } - -// MARK: - Objective-C Support - -// FIXME: Remove when possible - -@objc(SMKMessageSender) -public class SMKMessageSender: NSObject { - @objc(leaveClosedGroupWithPublicKey:) - public static func objc_leave(_ groupPublicKey: String) -> AnyPromise { - let promise = Storage.shared.writeAsync { db in - try MessageSender.leave(db, groupPublicKey: groupPublicKey) - } - - return AnyPromise.from(promise) - } - - @objc(forceSyncConfigurationNow) - public static func objc_forceSyncConfigurationNow() { - Storage.shared.write { db in - try MessageSender.syncConfiguration(db, forceSyncNow: true).retainUntilComplete() - } - } -} diff --git a/SessionUtilitiesKit/JobRunner/JobRunner.swift b/SessionUtilitiesKit/JobRunner/JobRunner.swift index 7d604f0ba..408904cc5 100644 --- a/SessionUtilitiesKit/JobRunner/JobRunner.swift +++ b/SessionUtilitiesKit/JobRunner/JobRunner.swift @@ -66,7 +66,8 @@ public final class JobRunner { jobVariants.remove(.attachmentUpload), jobVariants.remove(.messageSend), jobVariants.remove(.notifyPushServer), - jobVariants.remove(.sendReadReceipts) + jobVariants.remove(.sendReadReceipts), + jobVariants.remove(.groupLeaving) ].compactMap { $0 } ) let messageReceiveQueue: JobQueue = JobQueue( From 0958a15b2da055671b1f0eb7ec57bfbca79cda0c Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Thu, 16 Mar 2023 14:26:52 +1100 Subject: [PATCH 21/32] fix group leaving job blocking message send job queue --- SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift | 8 +++++--- .../Message Handling/MessageSender+ClosedGroups.swift | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift index b7ffca956..c63a0bcd9 100644 --- a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift +++ b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift @@ -8,7 +8,7 @@ import SessionUtilitiesKit import SessionSnodeKit public enum GroupLeavingJob: JobExecutor { - public static var maxFailureCount: Int = -1 + public static var maxFailureCount: Int = 0 public static var requiresThreadId: Bool = true public static var requiresInteractionId: Bool = true @@ -19,6 +19,7 @@ public enum GroupLeavingJob: JobExecutor { failure: @escaping (SessionUtilitiesKit.Job, Error?, Bool) -> (), deferred: @escaping (SessionUtilitiesKit.Job) -> ()) { + print("Ryan Test: Group leaving job running") guard let detailsData: Data = job.details, let details: Details = try? JSONDecoder().decode(Details.self, from: detailsData), @@ -53,7 +54,7 @@ public enum GroupLeavingJob: JobExecutor { // Remove the group from the database and unsubscribe from PNs ClosedGroupPoller.shared.stopPolling(for: details.groupPublicKey) - Storage.shared.write { db in + Storage.shared.writeAsync { db in let userPublicKey: String = getUserHexEncodedPublicKey(db) try closedGroup @@ -104,7 +105,7 @@ public enum GroupLeavingJob: JobExecutor { success(job, false) } .catch(on: queue) { error in - Storage.shared.write { db in + Storage.shared.writeAsync { db in try Interaction .filter(id: job.interactionId) .updateAll( @@ -115,6 +116,7 @@ public enum GroupLeavingJob: JobExecutor { ] ) } + success(job, false) } .retainUntilComplete() diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift index 2c39666cb..20f1c8574 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift @@ -494,7 +494,7 @@ extension MessageSender { timestampMs: SnodeAPI.currentOffsetTimestampMs() ).inserted(db) - JobRunner.add( + JobRunner.upsert( db, job: Job( variant: .groupLeaving, From 57289158e28fe8f85513706b0d86b5ecfc6fa991 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 17 Mar 2023 14:49:27 +1100 Subject: [PATCH 22/32] clean & merge dev --- SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift index c63a0bcd9..b255dc783 100644 --- a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift +++ b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift @@ -19,7 +19,6 @@ public enum GroupLeavingJob: JobExecutor { failure: @escaping (SessionUtilitiesKit.Job, Error?, Bool) -> (), deferred: @escaping (SessionUtilitiesKit.Job) -> ()) { - print("Ryan Test: Group leaving job running") guard let detailsData: Data = job.details, let details: Details = try? JSONDecoder().decode(Details.self, from: detailsData), From 3a7517ec640bea366dcc0bce4e59c6cd8b8a2fb7 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 17 Mar 2023 15:10:55 +1100 Subject: [PATCH 23/32] fail the group leaving job permanently if there is no thread or closed group record --- SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift index b255dc783..349938f3e 100644 --- a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift +++ b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift @@ -30,12 +30,12 @@ public enum GroupLeavingJob: JobExecutor { guard let thread: SessionThread = Storage.shared.read({ db in try? SessionThread.fetchOne(db, id: details.groupPublicKey)}) else { SNLog("Can't leave nonexistent closed group.") - failure(job, MessageSenderError.noThread, false) + failure(job, MessageSenderError.noThread, true) return } guard let closedGroup: ClosedGroup = Storage.shared.read({ db in try? thread.closedGroup.fetchOne(db)}) else { - failure(job, MessageSenderError.invalidClosedGroupUpdate, false) + failure(job, MessageSenderError.invalidClosedGroupUpdate, true) return } From e278c205babfa24603859afca6844c9c24536170 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 17 Mar 2023 15:42:40 +1100 Subject: [PATCH 24/32] make the job permanent fail if missing required details --- SessionMessagingKit/Jobs/Types/AttachmentDownloadJob.swift | 2 +- SessionMessagingKit/Jobs/Types/AttachmentUploadJob.swift | 2 +- SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift | 2 +- SessionMessagingKit/Jobs/Types/MessageReceiveJob.swift | 2 +- SessionMessagingKit/Jobs/Types/MessageSendJob.swift | 4 ++-- SessionMessagingKit/Jobs/Types/NotifyPushServerJob.swift | 2 +- SessionMessagingKit/Jobs/Types/SendReadReceiptsJob.swift | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SessionMessagingKit/Jobs/Types/AttachmentDownloadJob.swift b/SessionMessagingKit/Jobs/Types/AttachmentDownloadJob.swift index a3588e511..8db5a634d 100644 --- a/SessionMessagingKit/Jobs/Types/AttachmentDownloadJob.swift +++ b/SessionMessagingKit/Jobs/Types/AttachmentDownloadJob.swift @@ -25,7 +25,7 @@ public enum AttachmentDownloadJob: JobExecutor { let attachment: Attachment = Storage.shared .read({ db in try Attachment.fetchOne(db, id: details.attachmentId) }) else { - failure(job, JobRunnerError.missingRequiredDetails, false) + failure(job, JobRunnerError.missingRequiredDetails, true) return } diff --git a/SessionMessagingKit/Jobs/Types/AttachmentUploadJob.swift b/SessionMessagingKit/Jobs/Types/AttachmentUploadJob.swift index 88e72891f..9c9f6190e 100644 --- a/SessionMessagingKit/Jobs/Types/AttachmentUploadJob.swift +++ b/SessionMessagingKit/Jobs/Types/AttachmentUploadJob.swift @@ -31,7 +31,7 @@ public enum AttachmentUploadJob: JobExecutor { return (attachment, try OpenGroup.fetchOne(db, id: threadId)) }) else { - failure(job, JobRunnerError.missingRequiredDetails, false) + failure(job, JobRunnerError.missingRequiredDetails, true) return } diff --git a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift index 349938f3e..5ebe5a9cd 100644 --- a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift +++ b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift @@ -24,7 +24,7 @@ public enum GroupLeavingJob: JobExecutor { let details: Details = try? JSONDecoder().decode(Details.self, from: detailsData), let interactionId: Int64 = job.interactionId else { - failure(job, JobRunnerError.missingRequiredDetails, false) + failure(job, JobRunnerError.missingRequiredDetails, true) return } diff --git a/SessionMessagingKit/Jobs/Types/MessageReceiveJob.swift b/SessionMessagingKit/Jobs/Types/MessageReceiveJob.swift index 907f6af8d..9b1061336 100644 --- a/SessionMessagingKit/Jobs/Types/MessageReceiveJob.swift +++ b/SessionMessagingKit/Jobs/Types/MessageReceiveJob.swift @@ -21,7 +21,7 @@ public enum MessageReceiveJob: JobExecutor { let detailsData: Data = job.details, let details: Details = try? JSONDecoder().decode(Details.self, from: detailsData) else { - failure(job, JobRunnerError.missingRequiredDetails, false) + failure(job, JobRunnerError.missingRequiredDetails, true) return } diff --git a/SessionMessagingKit/Jobs/Types/MessageSendJob.swift b/SessionMessagingKit/Jobs/Types/MessageSendJob.swift index bae02f89c..b835cbca5 100644 --- a/SessionMessagingKit/Jobs/Types/MessageSendJob.swift +++ b/SessionMessagingKit/Jobs/Types/MessageSendJob.swift @@ -23,7 +23,7 @@ public enum MessageSendJob: JobExecutor { let detailsData: Data = job.details, let details: Details = try? JSONDecoder().decode(Details.self, from: detailsData) else { - failure(job, JobRunnerError.missingRequiredDetails, false) + failure(job, JobRunnerError.missingRequiredDetails, true) return } @@ -36,7 +36,7 @@ public enum MessageSendJob: JobExecutor { let jobId: Int64 = job.id, let interactionId: Int64 = job.interactionId else { - failure(job, JobRunnerError.missingRequiredDetails, false) + failure(job, JobRunnerError.missingRequiredDetails, true) return } diff --git a/SessionMessagingKit/Jobs/Types/NotifyPushServerJob.swift b/SessionMessagingKit/Jobs/Types/NotifyPushServerJob.swift index 63885541a..24efda1b5 100644 --- a/SessionMessagingKit/Jobs/Types/NotifyPushServerJob.swift +++ b/SessionMessagingKit/Jobs/Types/NotifyPushServerJob.swift @@ -21,7 +21,7 @@ public enum NotifyPushServerJob: JobExecutor { let detailsData: Data = job.details, let details: Details = try? JSONDecoder().decode(Details.self, from: detailsData) else { - failure(job, JobRunnerError.missingRequiredDetails, false) + failure(job, JobRunnerError.missingRequiredDetails, true) return } diff --git a/SessionMessagingKit/Jobs/Types/SendReadReceiptsJob.swift b/SessionMessagingKit/Jobs/Types/SendReadReceiptsJob.swift index bdb684869..12da68fe9 100644 --- a/SessionMessagingKit/Jobs/Types/SendReadReceiptsJob.swift +++ b/SessionMessagingKit/Jobs/Types/SendReadReceiptsJob.swift @@ -23,7 +23,7 @@ public enum SendReadReceiptsJob: JobExecutor { let detailsData: Data = job.details, let details: Details = try? JSONDecoder().decode(Details.self, from: detailsData) else { - failure(job, JobRunnerError.missingRequiredDetails, false) + failure(job, JobRunnerError.missingRequiredDetails, true) return } From 27cfe6b8b81a7e07c67c7d8e703f7e7fd4570251 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Mon, 3 Apr 2023 15:22:36 +0800 Subject: [PATCH 25/32] make the swipe actions always right & correct the copy for delete a covnersation --- Session/Home/HomeVC.swift | 32 +++++++++++++------ .../Translations/de.lproj/Localizable.strings | 10 ++---- .../Translations/en.lproj/Localizable.strings | 10 ++---- .../Translations/es.lproj/Localizable.strings | 10 ++---- .../Translations/fa.lproj/Localizable.strings | 10 ++---- .../Translations/fi.lproj/Localizable.strings | 10 ++---- .../Translations/fr.lproj/Localizable.strings | 10 ++---- .../Translations/hi.lproj/Localizable.strings | 10 ++---- .../Translations/hr.lproj/Localizable.strings | 10 ++---- .../id-ID.lproj/Localizable.strings | 10 ++---- .../Translations/it.lproj/Localizable.strings | 10 ++---- .../Translations/ja.lproj/Localizable.strings | 10 ++---- .../Translations/nl.lproj/Localizable.strings | 10 ++---- .../Translations/pl.lproj/Localizable.strings | 10 ++---- .../pt_BR.lproj/Localizable.strings | 10 ++---- .../Translations/ru.lproj/Localizable.strings | 10 ++---- .../Translations/si.lproj/Localizable.strings | 10 ++---- .../Translations/sk.lproj/Localizable.strings | 10 ++---- .../Translations/sv.lproj/Localizable.strings | 10 ++---- .../Translations/th.lproj/Localizable.strings | 10 ++---- .../vi-VN.lproj/Localizable.strings | 10 ++---- .../zh-Hant.lproj/Localizable.strings | 10 ++---- .../zh_CN.lproj/Localizable.strings | 10 ++---- .../UIContextualAction+Theming.swift | 2 +- 24 files changed, 67 insertions(+), 187 deletions(-) diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index 34c85d664..2261704fc 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -633,7 +633,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi title: ((hasUnread) ? "mark_read_button_text".localized() : "mark_unread_button_text".localized()), icon: ((hasUnread) ? UIImage(systemName: "envelope.open") : UIImage(systemName: "envelope.badge")), iconHeight: Values.smallFontSize, - themeTintColor: .textPrimary, + themeTintColor: .white, themeBackgroundColor: .conversationButton_swipeDestructive, side: .trailing, actionIndex: 0, @@ -693,7 +693,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi title: (threadViewModel.threadIsPinned ? "UNPIN_BUTTON_TEXT".localized() : "PIN_BUTTON_TEXT".localized()), icon: UIImage(systemName: "pin"), iconHeight: Values.mediumFontSize, - themeTintColor: .textPrimary, + themeTintColor: .white, themeBackgroundColor: .conversationButton_swipeDestructive, side: .trailing, actionIndex: 0, @@ -720,7 +720,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi title: ((threadViewModel.threadMutedUntilTimestamp != nil) ? "unmute_button_text".localized() : "mute_button_text".localized()), icon: UIImage(systemName: "speaker.slash"), iconHeight: Values.mediumFontSize, - themeTintColor: .textPrimary, + themeTintColor: .white, themeBackgroundColor: .conversationButton_swipeDestructive, side: .trailing, actionIndex: 1, @@ -763,20 +763,32 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi title: "TXT_DELETE_TITLE".localized(), icon: UIImage(named: "icon_bin")?.resizedImage(to: CGSize(width: Values.mediumFontSize, height: Values.mediumFontSize)), iconHeight: Values.mediumFontSize, - themeTintColor: .textPrimary, + themeTintColor: .white, themeBackgroundColor: .conversationButton_swipeDestructive, side: .trailing, actionIndex: 2, indexPath: indexPath, tableView: tableView ) { [weak self] _, _, completionHandler in + let confirmationModalExplanation: NSAttributedString = { + let mutableAttributedString = NSMutableAttributedString( + string: String( + format: "delete_conversation_confirmation_alert_message".localized(), + threadViewModel.displayName + ) + ) + mutableAttributedString.addAttribute( + .font, + value: UIFont.boldSystemFont(ofSize: Values.smallFontSize), + range: (mutableAttributedString.string as NSString).range(of: threadViewModel.displayName) + ) + return mutableAttributedString + }() + let confirmationModal: ConfirmationModal = ConfirmationModal( info: ConfirmationModal.Info( - title: "CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE".localized(), - explanation: (threadViewModel.currentUserIsClosedGroupAdmin == true ? - "admin_group_leave_warning".localized() : - "CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE".localized() - ), + title: "delete_conversation_confirmation_alert_title".localized(), + attributedExplanation: confirmationModalExplanation, confirmTitle: "TXT_DELETE_TITLE".localized(), confirmStyle: .danger, cancelStyle: .alert_text, @@ -805,7 +817,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi title: "LEAVE_BUTTON_TITLE".localized(), icon: UIImage(systemName: "rectangle.portrait.and.arrow.right"), iconHeight: Values.mediumFontSize, - themeTintColor: .textPrimary, + themeTintColor: .white, themeBackgroundColor: .conversationButton_swipeDestructive, side: .trailing, actionIndex: 2, diff --git a/Session/Meta/Translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings index 4329dadc7..f5007fbe3 100644 --- a/Session/Meta/Translations/de.lproj/Localizable.strings +++ b/Session/Meta/Translations/de.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Fertig"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Auswählen"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "Du wirst in dieser Gruppe keine Nachrichten mehr versenden oder empfangen können."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Wollen Sie die Gruppe wirklich verlassen?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Dies kann nicht rückgängig gemacht werden."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Unterhaltung löschen?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index 3b4ec22ee..da74d3933 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Done"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Select"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "You will no longer be able to send or receive messages in this group."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Do you really want to leave?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "This cannot be undone."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Delete Conversation?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings index 4bf349817..46107d2bc 100644 --- a/Session/Meta/Translations/es.lproj/Localizable.strings +++ b/Session/Meta/Translations/es.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Hecho"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Seleccionar"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "No podrás enviar o recibir más mensajes en este grupo."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "¿De verdad quieres abandonar el grupo?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Este paso no se puede deshacer."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "¿Eliminar conversación?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings index db8d61359..b5cc4f0f8 100644 --- a/Session/Meta/Translations/fa.lproj/Localizable.strings +++ b/Session/Meta/Translations/fa.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "انجام شد"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "انتخاب"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "شما دیگر قادر به ارسال یا دریافت پیام از این گروه نخواهید بود"; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "آیا واقعا قصد ترک کردن دارید؟"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "این نمیتواند انجام نشود."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "گفتگو حذف شود؟"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "درحال جستجو..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/fi.lproj/Localizable.strings b/Session/Meta/Translations/fi.lproj/Localizable.strings index d8b4a14b1..666585405 100644 --- a/Session/Meta/Translations/fi.lproj/Localizable.strings +++ b/Session/Meta/Translations/fi.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Valmis"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Valitse"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "Et pysty enään lähettämään tai vastaanottamaan viestejä tässä ryhmässä."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Haluatko varmasti poistua ryhmästä?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Tätä ei voida perua."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Poistetaanko keskustelu?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings index 485829208..6625f503b 100644 --- a/Session/Meta/Translations/fr.lproj/Localizable.strings +++ b/Session/Meta/Translations/fr.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Terminé"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Sélectionner"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "Vous ne pourrez plus recevoir ni envoyer de messages dans ce groupe."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Voulez-vous vraiment quitter ce groupe ?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Cette action est irréversible."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Supprimer la conversation ?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/hi.lproj/Localizable.strings b/Session/Meta/Translations/hi.lproj/Localizable.strings index 954e74054..e1cdaac55 100644 --- a/Session/Meta/Translations/hi.lproj/Localizable.strings +++ b/Session/Meta/Translations/hi.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "पूरा हुआ"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "चुनें"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "अब आप इस समूह में संदेश भेजने या प्राप्त करने में सक्षम नहीं होंगे।"; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "क्या आप वाकई छोड़ना चाहते हैं?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "This cannot be undone."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Delete Conversation?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/hr.lproj/Localizable.strings b/Session/Meta/Translations/hr.lproj/Localizable.strings index 59fe0f037..77cafa902 100644 --- a/Session/Meta/Translations/hr.lproj/Localizable.strings +++ b/Session/Meta/Translations/hr.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Gotovo"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Odaberi"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "Više nećete moći slati niti primati poruke u ovoj grupi."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Da li zaista želite izaći?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Ovaj je postupak nepovratan."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Obriši razgovor?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings index d82fd6014..1f23902a3 100644 --- a/Session/Meta/Translations/id-ID.lproj/Localizable.strings +++ b/Session/Meta/Translations/id-ID.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Selesai"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Pilih"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "Anda tidak dapat lagi mengirim atau menerima pesan dari grup ini."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Apakah Anda benar-benar ingin keluar?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Tindakan ini tidak dapat dibatalkan."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Hapus Percakapan?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings index 32b1bfc72..c824b802c 100644 --- a/Session/Meta/Translations/it.lproj/Localizable.strings +++ b/Session/Meta/Translations/it.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Fatto"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Seleziona"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "Non sarei più in grado di inviare o ricevere messaggi in questo gruppo."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Vuoi davvero lasciare?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Non potrà essere annullato."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Elimina conversazione?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings index b2d5cf714..75cb1e6bf 100644 --- a/Session/Meta/Translations/ja.lproj/Localizable.strings +++ b/Session/Meta/Translations/ja.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "完了"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "選択"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "このグループとの会話が出来なくなりますがよろしいでしょうか。"; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "離脱してよろしいですか?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "消去すると元に戻せません"; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "消去しますか?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/nl.lproj/Localizable.strings b/Session/Meta/Translations/nl.lproj/Localizable.strings index 36a4ecf8d..4c9b31f6e 100644 --- a/Session/Meta/Translations/nl.lproj/Localizable.strings +++ b/Session/Meta/Translations/nl.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Ok"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Selecteer"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "Je kunt geen berichten meer versturen of ontvangen in deze groep."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Wilt u echt deze groep verlaten?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Dit kan niet ongedaan worden gemaakt."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Gesprek verwijderen?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings index 9505b5df1..35d1f7a04 100644 --- a/Session/Meta/Translations/pl.lproj/Localizable.strings +++ b/Session/Meta/Translations/pl.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Gotowe"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Zaznacz"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "Nie będziesz już móc odbierać lub wysyłać wiadomości w tej grupie."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Czy na pewno chcesz wyjść?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Tego nie można cofnąć."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Usunąć konwersację?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings index 2977aad75..c351ad411 100644 --- a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings +++ b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Pronto"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Selecionar"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "Você não poderá mais enviar nem receber mensagens neste grupo."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Você tem certeza que deseja sair?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Isso não pode ser desfeito."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Excluir conversa?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings index 1f8cca0be..26a64e4a4 100644 --- a/Session/Meta/Translations/ru.lproj/Localizable.strings +++ b/Session/Meta/Translations/ru.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Готово"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Выбор"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "Вы больше не сможете отправлять и получать сообщения в этой группе."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Вы хотите покинуть группу?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Это не может быть отменено."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Удалить разговор?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/si.lproj/Localizable.strings b/Session/Meta/Translations/si.lproj/Localizable.strings index 76c4e66a8..349867b2c 100644 --- a/Session/Meta/Translations/si.lproj/Localizable.strings +++ b/Session/Meta/Translations/si.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Done"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Select"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "You will no longer be able to send or receive messages in this group."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Do you really want to leave?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "This cannot be undone."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Delete Conversation?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/sk.lproj/Localizable.strings b/Session/Meta/Translations/sk.lproj/Localizable.strings index 582dd4281..71cbe0cd5 100644 --- a/Session/Meta/Translations/sk.lproj/Localizable.strings +++ b/Session/Meta/Translations/sk.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Hotovo"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Vybrať"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "Už nebudete môcť posielať a prijímať správy v tejto skupine."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Ste si istý/á, že chcete odísť?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Táto akcia sa nedá vrátiť."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Zmazať konverzáciu?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/sv.lproj/Localizable.strings b/Session/Meta/Translations/sv.lproj/Localizable.strings index e94364dcc..f0a1f421a 100644 --- a/Session/Meta/Translations/sv.lproj/Localizable.strings +++ b/Session/Meta/Translations/sv.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Klart"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Välj"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "Du kommer inte längre att kunna skicka eller ta emot meddelanden i denna grupp."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Vill du verkligen lämna?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Detta kan inte ångras."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Radera konversation?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/th.lproj/Localizable.strings b/Session/Meta/Translations/th.lproj/Localizable.strings index 1df1f2254..e32ffabad 100644 --- a/Session/Meta/Translations/th.lproj/Localizable.strings +++ b/Session/Meta/Translations/th.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "เสร็จ"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "เลือก"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "คุณจะไม่สามารถส่งและรับข้อความในกลุ่มนี้ได้อีกต่อไป"; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "แน่ใจออกจากไหม"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "การกระทำนี้ไม่สามารถยกเลิกได้"; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "ลบการสนทนาไหม"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings index 47c54b0bd..049e0782d 100644 --- a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings +++ b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "Xong"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "Chọn"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "Bạn sẽ không thể gửi hoặc nhận tin nhắn trong nhóm này nữa."; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "Bạn thực sự muốn rời khỏi nhóm?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "Tác vụ này không thể hoàn tất."; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "Xóa cuộc hội thoại?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings index 43063bfee..2eb03bd1a 100644 --- a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "完成"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "選擇"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "您已經無法再於此群組傳送或接收訊息。"; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "確定要離開嗎?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "此操作無法復原。"; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "刪除對話?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings index 815f05f54..9e1b96ac2 100644 --- a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings @@ -60,14 +60,6 @@ "BUTTON_DONE" = "完成"; /* Button text to enable batch selection mode */ "BUTTON_SELECT" = "选择"; -/* Alert body */ -"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "您将无法在此群组中继续发送或接收消息。"; -/* Alert title */ -"CONFIRM_LEAVE_GROUP_TITLE" = "确定离开群聊?"; -/* Message for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE" = "该操作无法撤销。"; -/* Title for the 'conversation delete confirmation' alert. */ -"CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE" = "删除会话?"; /* keyboard toolbar label when starting to search with no current results */ "CONVERSATION_SEARCH_SEARCHING" = "Searching..."; /* keyboard toolbar label when no messages match the search string */ @@ -619,3 +611,5 @@ "group_you_leaving" = "Leaving..."; "group_leave_error" = "Failed to leave Group!"; "group_unable_to_leave" = "Unable to leave the Group, please try again"; +"delete_conversation_confirmation_alert_message" = "Are you sure you want to delete your conversation with %@?"; +"delete_conversation_confirmation_alert_title" = "Delete Conversation"; diff --git a/SessionUIKit/Utilities/UIContextualAction+Theming.swift b/SessionUIKit/Utilities/UIContextualAction+Theming.swift index d16fdd9da..4e4396c1e 100644 --- a/SessionUIKit/Utilities/UIContextualAction+Theming.swift +++ b/SessionUIKit/Utilities/UIContextualAction+Theming.swift @@ -28,7 +28,7 @@ public extension UIContextualAction { title: String? = nil, icon: UIImage? = nil, iconHeight: CGFloat = Values.mediumFontSize, - themeTintColor: ThemeValue = .textPrimary, + themeTintColor: ThemeValue = .white, themeBackgroundColor: ThemeValue, side: Side, actionIndex: Int, From 6302170e4dde1e7c605a9910513bdf4058026e19 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Mon, 3 Apr 2023 15:26:40 +0800 Subject: [PATCH 26/32] remove mark as read/unread action --- Session/Home/HomeVC.swift | 51 +-------------------------------------- 1 file changed, 1 insertion(+), 50 deletions(-) diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index 2261704fc..526082fbf 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -619,56 +619,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi } func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { - let section: HomeViewModel.SectionModel = self.viewModel.threadData[indexPath.section] - let unswipeAnimationDelay: DispatchTimeInterval = .milliseconds(500) - - switch section.model { - case .messageRequests: - return nil - case .threads: - let threadViewModel: SessionThreadViewModel = section.elements[indexPath.row] - guard threadViewModel.interactionVariant?.isGroupLeavingStatus != true else { return nil } - let hasUnread: Bool = (threadViewModel.threadUnreadCount ?? 0) > 0 - let mark: UIContextualAction = UIContextualAction( - title: ((hasUnread) ? "mark_read_button_text".localized() : "mark_unread_button_text".localized()), - icon: ((hasUnread) ? UIImage(systemName: "envelope.open") : UIImage(systemName: "envelope.badge")), - iconHeight: Values.smallFontSize, - themeTintColor: .white, - themeBackgroundColor: .conversationButton_swipeDestructive, - side: .trailing, - actionIndex: 0, - indexPath: indexPath, - tableView: tableView - ) { _, _, completionHandler in - (tableView.cellForRow(at: indexPath) as? FullConversationCell)?.optimisticUpdate( - hasUnread: !hasUnread - ) - completionHandler(true) - - // Delay the change to give the cell "unswipe" animation some time to complete - DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + unswipeAnimationDelay) { - Storage.shared.writeAsync { db in - if hasUnread { - try Interaction.markAsRead( - db, - interactionId: threadViewModel.interactionId, - threadId: threadViewModel.threadId, - threadVariant: threadViewModel.threadVariant, - includingOlder: true, - trySendReadReceipt: true - ) - } else { - try Interaction - .filter(id: threadViewModel.interactionId) - .updateAll(db, Interaction.Columns.wasRead.set(to: false)) - } - } - } - } - mark.themeBackgroundColor = .conversationButton_swipeSecondary - return UISwipeActionsConfiguration(actions: [ mark ]) - default: return nil - } + return nil } func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { From 7f2409734384275fd0bc23b23c3e73c14308a232 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Mon, 3 Apr 2023 15:41:17 +0800 Subject: [PATCH 27/32] update leave group copy in conversation settings view --- .../Settings/ThreadSettingsViewModel.swift | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/Session/Conversations/Settings/ThreadSettingsViewModel.swift b/Session/Conversations/Settings/ThreadSettingsViewModel.swift index bc99c9f00..447732eeb 100644 --- a/Session/Conversations/Settings/ThreadSettingsViewModel.swift +++ b/Session/Conversations/Settings/ThreadSettingsViewModel.swift @@ -394,11 +394,25 @@ class ThreadSettingsViewModel: SessionTableViewModel Date: Tue, 4 Apr 2023 11:38:04 +0800 Subject: [PATCH 28/32] use delete action for group that current user is no longer in --- Session/Home/HomeVC.swift | 24 ++++++++++++ Session/Home/HomeViewModel.swift | 39 ++++++++++++++----- .../Jobs/Types/GroupLeavingJob.swift | 34 +--------------- .../MessageSender+ClosedGroups.swift | 36 +++++++++++++++++ .../SessionThreadViewModel.swift | 21 +++++++--- 5 files changed, 105 insertions(+), 49 deletions(-) diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index 526082fbf..a2ce32596 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -764,6 +764,30 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi return UISwipeActionsConfiguration(actions: [ delete, mute, pin ]) case .openGroup, .closedGroup: + if threadViewModel.currentUserIsClosedGroupMember == false { + let delete: UIContextualAction = UIContextualAction( + title: "TXT_DELETE_TITLE".localized(), + icon: UIImage(named: "icon_bin")?.resizedImage(to: CGSize(width: Values.mediumFontSize, height: Values.mediumFontSize)), + iconHeight: Values.mediumFontSize, + themeTintColor: .white, + themeBackgroundColor: .conversationButton_swipeDestructive, + side: .trailing, + actionIndex: 2, + indexPath: indexPath, + tableView: tableView + ) { [weak self] _, _, completionHandler in + self?.viewModel.delete( + threadId: threadViewModel.threadId, + threadVariant: threadViewModel.threadVariant, + force: true + ) + + completionHandler(true) + } + + return UISwipeActionsConfiguration(actions: [ delete, mute, pin ]) + } + let leave: UIContextualAction = UIContextualAction( title: "LEAVE_BUTTON_TITLE".localized(), icon: UIImage(systemName: "rectangle.portrait.and.arrow.right"), diff --git a/Session/Home/HomeViewModel.swift b/Session/Home/HomeViewModel.swift index 33aed908b..f515444f3 100644 --- a/Session/Home/HomeViewModel.swift +++ b/Session/Home/HomeViewModel.swift @@ -301,23 +301,42 @@ public class HomeViewModel { // MARK: - Functions - public func delete(threadId: String, threadVariant: SessionThread.Variant) { + public func delete(threadId: String, threadVariant: SessionThread.Variant, force: Bool = false) { + + func delete(_ db: Database, threadId: String) throws { + _ = try SessionThread + .filter(id: threadId) + .deleteAll(db) + } + Storage.shared.writeAsync { db in switch threadVariant { case .closedGroup: - try MessageSender.leave( - db, - groupPublicKey: threadId, - deleteThread: true - ) + if force { + if let thread: SessionThread = try? SessionThread.fetchOne(db, id: threadId), + let closedGroup: ClosedGroup = try? thread.closedGroup.fetchOne(db) + { + try MessageSender.performClosedGroupCleanUp( + db, + for: closedGroup, + in: thread + ) + } + try delete(db, threadId: threadId) + } else { + try MessageSender.leave( + db, + groupPublicKey: threadId, + deleteThread: true + ) + } case .openGroup: OpenGroupManager.shared.delete(db, openGroupId: threadId) - _ = try SessionThread - .filter(id: threadId) - .deleteAll(db) + try delete(db, threadId: threadId) - default: break + default: + try delete(db, threadId: threadId) } } } diff --git a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift index 5ebe5a9cd..bf6360a26 100644 --- a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift +++ b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift @@ -50,21 +50,8 @@ public enum GroupLeavingJob: JobExecutor { ) } .done(on: queue) { _ in - // Remove the group from the database and unsubscribe from PNs - ClosedGroupPoller.shared.stopPolling(for: details.groupPublicKey) - Storage.shared.writeAsync { db in - let userPublicKey: String = getUserHexEncodedPublicKey(db) - - try closedGroup - .keyPairs - .deleteAll(db) - - let _ = PushNotificationAPI.performOperation( - .unsubscribe, - for: details.groupPublicKey, - publicKey: userPublicKey - ) + try MessageSender.performClosedGroupCleanUp(db, for: closedGroup, in: thread) try Interaction .filter(id: interactionId) @@ -76,25 +63,6 @@ public enum GroupLeavingJob: JobExecutor { ] ) - // Update the group (if the admin leaves the group is disbanded) - let wasAdminUser: Bool = try GroupMember - .filter(GroupMember.Columns.groupId == thread.id) - .filter(GroupMember.Columns.profileId == userPublicKey) - .filter(GroupMember.Columns.role == GroupMember.Role.admin) - .isNotEmpty(db) - - if wasAdminUser { - try GroupMember - .filter(GroupMember.Columns.groupId == thread.id) - .deleteAll(db) - } - else { - try GroupMember - .filter(GroupMember.Columns.groupId == thread.id) - .filter(GroupMember.Columns.profileId == userPublicKey) - .deleteAll(db) - } - if details.deleteThread { _ = try SessionThread .filter(id: thread.id) diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift index 20f1c8574..415e99275 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift @@ -582,4 +582,40 @@ extension MessageSender { } catch {} } + + /// Remove the group from the database and unsubscribe from PNs + public static func performClosedGroupCleanUp(_ db: Database, for closedGroup: ClosedGroup, in thread: SessionThread) throws { + ClosedGroupPoller.shared.stopPolling(for: closedGroup.publicKey) + + let userPublicKey: String = getUserHexEncodedPublicKey(db) + + try closedGroup + .keyPairs + .deleteAll(db) + + let _ = PushNotificationAPI.performOperation( + .unsubscribe, + for: closedGroup.publicKey, + publicKey: userPublicKey + ) + + // Update the group (if the admin leaves the group is disbanded) + let wasAdminUser: Bool = try GroupMember + .filter(GroupMember.Columns.groupId == thread.id) + .filter(GroupMember.Columns.profileId == userPublicKey) + .filter(GroupMember.Columns.role == GroupMember.Role.admin) + .isNotEmpty(db) + + if wasAdminUser { + try GroupMember + .filter(GroupMember.Columns.groupId == thread.id) + .deleteAll(db) + } + else { + try GroupMember + .filter(GroupMember.Columns.groupId == thread.id) + .filter(GroupMember.Columns.profileId == userPublicKey) + .deleteAll(db) + } + } } diff --git a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift index 0b66cd78f..491d43747 100644 --- a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift +++ b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift @@ -457,6 +457,9 @@ public extension SessionThreadViewModel { let interactionAttachmentAttachmentIdColumnLiteral: SQL = SQL(stringLiteral: InteractionAttachment.Columns.attachmentId.name) let interactionAttachmentInteractionIdColumnLiteral: SQL = SQL(stringLiteral: InteractionAttachment.Columns.interactionId.name) let interactionAttachmentAlbumIndexColumnLiteral: SQL = SQL(stringLiteral: InteractionAttachment.Columns.albumIndex.name) + let groupMemberProfileIdColumnLiteral: SQL = SQL(stringLiteral: GroupMember.Columns.profileId.name) + let groupMemberRoleColumnLiteral: SQL = SQL(stringLiteral: GroupMember.Columns.role.name) + let groupMemberGroupIdColumnLiteral: SQL = SQL(stringLiteral: GroupMember.Columns.groupId.name) /// **Note:** The `numColumnsBeforeProfiles` value **MUST** match the number of fields before /// the `ViewModel.contactProfileKey` entry below otherwise the query will fail to @@ -464,7 +467,7 @@ public extension SessionThreadViewModel { /// /// Explicitly set default values for the fields ignored for search results let numColumnsBeforeProfiles: Int = 12 - let numColumnsBetweenProfilesAndAttachmentInfo: Int = 11 // The attachment info columns will be combined + let numColumnsBetweenProfilesAndAttachmentInfo: Int = 12 // The attachment info columns will be combined let request: SQLRequest = """ SELECT @@ -488,7 +491,8 @@ public extension SessionThreadViewModel { \(ViewModel.closedGroupProfileBackKey).*, \(ViewModel.closedGroupProfileBackFallbackKey).*, \(closedGroup[.name]) AS \(ViewModel.closedGroupNameKey), - (\(groupMember[.profileId]) IS NOT NULL) AS \(ViewModel.currentUserIsClosedGroupAdminKey), + (\(ViewModel.currentUserIsClosedGroupMemberKey).profileId IS NOT NULL) AS \(ViewModel.currentUserIsClosedGroupMemberKey), + (\(ViewModel.currentUserIsClosedGroupAdminKey).profileId IS NOT NULL) AS \(ViewModel.currentUserIsClosedGroupAdminKey), \(openGroup[.name]) AS \(ViewModel.openGroupNameKey), \(openGroup[.imageData]) AS \(ViewModel.openGroupProfilePictureDataKey), @@ -563,10 +567,15 @@ public extension SessionThreadViewModel { LEFT JOIN \(Profile.self) AS \(ViewModel.contactProfileKey) ON \(ViewModel.contactProfileKey).\(profileIdColumnLiteral) = \(thread[.id]) LEFT JOIN \(OpenGroup.self) ON \(openGroup[.threadId]) = \(thread[.id]) LEFT JOIN \(ClosedGroup.self) ON \(closedGroup[.threadId]) = \(thread[.id]) - LEFT JOIN \(GroupMember.self) ON ( - \(SQL("\(groupMember[.role]) = \(GroupMember.Role.admin)")) AND - \(groupMember[.groupId]) = \(closedGroup[.threadId]) AND - \(SQL("\(groupMember[.profileId]) = \(userPublicKey)")) + LEFT JOIN \(GroupMember.self) AS \(ViewModel.currentUserIsClosedGroupMemberKey) ON ( + \(SQL("\(ViewModel.currentUserIsClosedGroupMemberKey).\(groupMemberRoleColumnLiteral) != \(GroupMember.Role.zombie)")) AND + \(ViewModel.currentUserIsClosedGroupMemberKey).\(groupMemberGroupIdColumnLiteral) = \(closedGroup[.threadId]) AND + \(SQL("\(ViewModel.currentUserIsClosedGroupMemberKey).\(groupMemberProfileIdColumnLiteral) = \(userPublicKey)")) + ) + LEFT JOIN \(GroupMember.self) AS \(ViewModel.currentUserIsClosedGroupAdminKey) ON ( + \(SQL("\(ViewModel.currentUserIsClosedGroupAdminKey).\(groupMemberRoleColumnLiteral) = \(GroupMember.Role.admin)")) AND + \(ViewModel.currentUserIsClosedGroupAdminKey).\(groupMemberGroupIdColumnLiteral) = \(closedGroup[.threadId]) AND + \(SQL("\(ViewModel.currentUserIsClosedGroupAdminKey).\(groupMemberProfileIdColumnLiteral) = \(userPublicKey)")) ) LEFT JOIN \(Profile.self) AS \(ViewModel.closedGroupProfileFrontKey) ON ( From d2dbace848308b54343d940d5ca8d49a5a6510fd Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 4 Apr 2023 12:00:02 +0800 Subject: [PATCH 29/32] clean --- Session/Home/HomeViewModel.swift | 9 ----- .../Jobs/Types/GroupLeavingJob.swift | 34 +++++++++++++++++- .../MessageSender+ClosedGroups.swift | 36 ------------------- 3 files changed, 33 insertions(+), 46 deletions(-) diff --git a/Session/Home/HomeViewModel.swift b/Session/Home/HomeViewModel.swift index f515444f3..822a025e6 100644 --- a/Session/Home/HomeViewModel.swift +++ b/Session/Home/HomeViewModel.swift @@ -313,15 +313,6 @@ public class HomeViewModel { switch threadVariant { case .closedGroup: if force { - if let thread: SessionThread = try? SessionThread.fetchOne(db, id: threadId), - let closedGroup: ClosedGroup = try? thread.closedGroup.fetchOne(db) - { - try MessageSender.performClosedGroupCleanUp( - db, - for: closedGroup, - in: thread - ) - } try delete(db, threadId: threadId) } else { try MessageSender.leave( diff --git a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift index bf6360a26..5ebe5a9cd 100644 --- a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift +++ b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift @@ -50,8 +50,21 @@ public enum GroupLeavingJob: JobExecutor { ) } .done(on: queue) { _ in + // Remove the group from the database and unsubscribe from PNs + ClosedGroupPoller.shared.stopPolling(for: details.groupPublicKey) + Storage.shared.writeAsync { db in - try MessageSender.performClosedGroupCleanUp(db, for: closedGroup, in: thread) + let userPublicKey: String = getUserHexEncodedPublicKey(db) + + try closedGroup + .keyPairs + .deleteAll(db) + + let _ = PushNotificationAPI.performOperation( + .unsubscribe, + for: details.groupPublicKey, + publicKey: userPublicKey + ) try Interaction .filter(id: interactionId) @@ -63,6 +76,25 @@ public enum GroupLeavingJob: JobExecutor { ] ) + // Update the group (if the admin leaves the group is disbanded) + let wasAdminUser: Bool = try GroupMember + .filter(GroupMember.Columns.groupId == thread.id) + .filter(GroupMember.Columns.profileId == userPublicKey) + .filter(GroupMember.Columns.role == GroupMember.Role.admin) + .isNotEmpty(db) + + if wasAdminUser { + try GroupMember + .filter(GroupMember.Columns.groupId == thread.id) + .deleteAll(db) + } + else { + try GroupMember + .filter(GroupMember.Columns.groupId == thread.id) + .filter(GroupMember.Columns.profileId == userPublicKey) + .deleteAll(db) + } + if details.deleteThread { _ = try SessionThread .filter(id: thread.id) diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift index 415e99275..20f1c8574 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift @@ -582,40 +582,4 @@ extension MessageSender { } catch {} } - - /// Remove the group from the database and unsubscribe from PNs - public static func performClosedGroupCleanUp(_ db: Database, for closedGroup: ClosedGroup, in thread: SessionThread) throws { - ClosedGroupPoller.shared.stopPolling(for: closedGroup.publicKey) - - let userPublicKey: String = getUserHexEncodedPublicKey(db) - - try closedGroup - .keyPairs - .deleteAll(db) - - let _ = PushNotificationAPI.performOperation( - .unsubscribe, - for: closedGroup.publicKey, - publicKey: userPublicKey - ) - - // Update the group (if the admin leaves the group is disbanded) - let wasAdminUser: Bool = try GroupMember - .filter(GroupMember.Columns.groupId == thread.id) - .filter(GroupMember.Columns.profileId == userPublicKey) - .filter(GroupMember.Columns.role == GroupMember.Role.admin) - .isNotEmpty(db) - - if wasAdminUser { - try GroupMember - .filter(GroupMember.Columns.groupId == thread.id) - .deleteAll(db) - } - else { - try GroupMember - .filter(GroupMember.Columns.groupId == thread.id) - .filter(GroupMember.Columns.profileId == userPublicKey) - .deleteAll(db) - } - } } From 60b931b32ac279a276d54d7f5c78e9e95d49bdf3 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 4 Apr 2023 12:27:39 +0800 Subject: [PATCH 30/32] pod update --- Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Podfile.lock b/Podfile.lock index 0239f9c29..9cd0a2706 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -242,6 +242,6 @@ SPEC CHECKSUMS: YYImage: f1ddd15ac032a58b78bbed1e012b50302d318331 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 2bf7639359fecebe56e9757d88f4eb48864652d2 +PODFILE CHECKSUM: 97324ae5888b01db2f2adc4dcc239e2e7d6867f7 COCOAPODS: 1.11.3 From c101f61473544bed009cf5d1c40d427b663c4c1f Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 4 Apr 2023 13:53:39 +0800 Subject: [PATCH 31/32] clean --- Session/Home/HomeVC.swift | 47 ++++++++++++++++---------------- Session/Home/HomeViewModel.swift | 21 ++++++-------- 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index a2ce32596..1b15da4bb 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -708,8 +708,8 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi } mute.themeBackgroundColor = .conversationButton_swipeSecondary - switch threadViewModel.threadVariant { - case .contact: + switch (threadViewModel.threadVariant, threadViewModel.currentUserIsClosedGroupMember) { + case (.contact, _): let delete: UIContextualAction = UIContextualAction( title: "TXT_DELETE_TITLE".localized(), icon: UIImage(named: "icon_bin")?.resizedImage(to: CGSize(width: Values.mediumFontSize, height: Values.mediumFontSize)), @@ -763,31 +763,30 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi return UISwipeActionsConfiguration(actions: [ delete, mute, pin ]) - case .openGroup, .closedGroup: - if threadViewModel.currentUserIsClosedGroupMember == false { - let delete: UIContextualAction = UIContextualAction( - title: "TXT_DELETE_TITLE".localized(), - icon: UIImage(named: "icon_bin")?.resizedImage(to: CGSize(width: Values.mediumFontSize, height: Values.mediumFontSize)), - iconHeight: Values.mediumFontSize, - themeTintColor: .white, - themeBackgroundColor: .conversationButton_swipeDestructive, - side: .trailing, - actionIndex: 2, - indexPath: indexPath, - tableView: tableView - ) { [weak self] _, _, completionHandler in - self?.viewModel.delete( - threadId: threadViewModel.threadId, - threadVariant: threadViewModel.threadVariant, - force: true - ) - - completionHandler(true) - } + case (.closedGroup, false): + let delete: UIContextualAction = UIContextualAction( + title: "TXT_DELETE_TITLE".localized(), + icon: UIImage(named: "icon_bin")?.resizedImage(to: CGSize(width: Values.mediumFontSize, height: Values.mediumFontSize)), + iconHeight: Values.mediumFontSize, + themeTintColor: .white, + themeBackgroundColor: .conversationButton_swipeDestructive, + side: .trailing, + actionIndex: 2, + indexPath: indexPath, + tableView: tableView + ) { [weak self] _, _, completionHandler in + self?.viewModel.delete( + threadId: threadViewModel.threadId, + threadVariant: threadViewModel.threadVariant, + force: true + ) - return UISwipeActionsConfiguration(actions: [ delete, mute, pin ]) + completionHandler(true) } + + return UISwipeActionsConfiguration(actions: [ delete, mute, pin ]) + default: let leave: UIContextualAction = UIContextualAction( title: "LEAVE_BUTTON_TITLE".localized(), icon: UIImage(systemName: "rectangle.portrait.and.arrow.right"), diff --git a/Session/Home/HomeViewModel.swift b/Session/Home/HomeViewModel.swift index 822a025e6..7effafa61 100644 --- a/Session/Home/HomeViewModel.swift +++ b/Session/Home/HomeViewModel.swift @@ -310,21 +310,16 @@ public class HomeViewModel { } Storage.shared.writeAsync { db in - switch threadVariant { - case .closedGroup: - if force { - try delete(db, threadId: threadId) - } else { - try MessageSender.leave( - db, - groupPublicKey: threadId, - deleteThread: true - ) - } + switch (threadVariant, force) { + case (.closedGroup, false): + try MessageSender.leave( + db, + groupPublicKey: threadId, + deleteThread: true + ) - case .openGroup: + case (.openGroup, _): OpenGroupManager.shared.delete(db, openGroupId: threadId) - try delete(db, threadId: threadId) default: try delete(db, threadId: threadId) From 81b63075cb6e890e8c6a976cc777cebd7f26fa67 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Wed, 5 Apr 2023 15:07:45 +1000 Subject: [PATCH 32/32] Updated the seed node certificate validation to use a specific date --- SessionUtilitiesKit/Networking/HTTP.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/SessionUtilitiesKit/Networking/HTTP.swift b/SessionUtilitiesKit/Networking/HTTP.swift index 9e5946735..cbe2ec9de 100644 --- a/SessionUtilitiesKit/Networking/HTTP.swift +++ b/SessionUtilitiesKit/Networking/HTTP.swift @@ -41,8 +41,25 @@ public enum HTTP { guard SecTrustSetAnchorCertificates(trust, certificates as CFArray) == errSecSuccess else { return completionHandler(.cancelAuthenticationChallenge, nil) } + + // We want to make sure that the pinned certification was valid during it's validity + // period (which has now expired) so set the date to validate against to be within the + // valid period + let dateFormatter: DateFormatter = DateFormatter() + dateFormatter.dateFormat = "dd/MM/yyyy HH:mm:ss" + + if let validDate: Date = dateFormatter.date(from: "01/01/2022 12:00:00") { + if SecTrustSetVerifyDate(trust, validDate as CFDate) != errSecSuccess { + SNLog("Unable to set date for seed node certificate validation.") + } + } + else { + SNLog("Unable to set date for seed node certificate validation.") + } + // Check that the presented certificate is one of the seed node certificates var result: SecTrustResultType = .invalid + guard SecTrustEvaluate(trust, &result) == errSecSuccess else { return completionHandler(.cancelAuthenticationChallenge, nil) }