From 58184d6d2765bc4855b6ae15d772acf49f504f3f Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Fri, 7 Oct 2022 15:35:17 +1100 Subject: [PATCH] Fixed issues found during testing Fixed an issue where the user config message wouldn't get sent correctly Fixed an issue where the theme preference migration wasn't working properly Fixed a crash which could occur in some cases when updating the theme Fixed a crash which could occur when opening the new conversation screen with a contact with no name Fixed a minor UI glitch with the 'sessionId' separator border Fixed a minor UI issue where long author names in quotes could cause the message bubble to stretch incorrectly Cleaned up some no-contact UI states Updated the Atomic queue to have a 'userInteractive' priority so it can't be delayed by lower priority queues and block the main thread --- Session/Closed Groups/NewClosedGroupVC.swift | 25 ++----- .../Message Cells/VisibleMessageCell.swift | 1 + Session/Home/HomeVC.swift | 12 +--- .../New Conversation/NewConversationVC.swift | 10 ++- .../NewConversationViewModel.swift | 11 ++-- Session/Meta/AppDelegate.swift | 2 +- .../MessageSender+Convenience.swift | 6 +- SessionUIKit/Components/Separator.swift | 66 +++++++++++-------- .../Migrations/_001_ThemePreferences.swift | 25 +++++-- SessionUIKit/Style Guide/ThemeManager.swift | 17 +++-- SessionUtilitiesKit/General/Atomic.swift | 7 +- 11 files changed, 99 insertions(+), 83 deletions(-) diff --git a/Session/Closed Groups/NewClosedGroupVC.swift b/Session/Closed Groups/NewClosedGroupVC.swift index 006e6935b..42ea3a267 100644 --- a/Session/Closed Groups/NewClosedGroupVC.swift +++ b/Session/Closed Groups/NewClosedGroupVC.swift @@ -161,25 +161,14 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate let explanationLabel: UILabel = UILabel() explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) explanationLabel.text = "vc_create_closed_group_empty_state_message".localized() - explanationLabel.themeTextColor = .textPrimary + explanationLabel.themeTextColor = .textSecondary explanationLabel.textAlignment = .center explanationLabel.lineBreakMode = .byWordWrapping explanationLabel.numberOfLines = 0 - let createNewPrivateChatButton: SessionButton = SessionButton(style: .bordered, size: .medium) - createNewPrivateChatButton.setTitle("vc_create_closed_group_empty_state_button_title".localized(), for: .normal) - createNewPrivateChatButton.addTarget(self, action: #selector(createNewDM), for: .touchUpInside) - createNewPrivateChatButton.set(.width, to: 196) - - let stackView: UIStackView = UIStackView(arrangedSubviews: [ explanationLabel, createNewPrivateChatButton ]) - stackView.axis = .vertical - stackView.spacing = Values.mediumSpacing - stackView.alignment = .center - view.addSubview(stackView) - stackView.center(.horizontal, in: view) - - let verticalCenteringConstraint = stackView.center(.vertical, in: view) - verticalCenteringConstraint.constant = -16 // Makes things appear centered visually + view.addSubview(explanationLabel) + explanationLabel.pin(.top, to: .top, of: view, withInset: Values.largeSpacing) + explanationLabel.center(.horizontal, in: view) return } @@ -348,12 +337,6 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate .retainUntilComplete() } } - - @objc private func createNewDM() { - presentingViewController?.dismiss(animated: true, completion: nil) - - SessionApp.homeViewController.wrappedValue?.createNewDM() - } } extension NewClosedGroupVC: UISearchBarDelegate { diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index 7855e19e6..54ff3b9d8 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -519,6 +519,7 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate { // Constraints bubbleView.addSubview(stackView) stackView.pin(to: bubbleView, withInset: inset) + stackView.widthAnchor.constraint(lessThanOrEqualToConstant: maxWidth).isActive = true snContentView.addArrangedSubview(bubbleBackgroundView) } diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index 4da39cc33..6af6842fb 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -185,7 +185,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi let createNewPrivateChatButton = SessionButton(style: .bordered, size: .large) createNewPrivateChatButton.setTitle("vc_home_empty_state_button_title".localized(), for: .normal) - createNewPrivateChatButton.addTarget(self, action: #selector(createNewDM), for: .touchUpInside) + createNewPrivateChatButton.addTarget(self, action: #selector(createNewConversation), for: .touchUpInside) createNewPrivateChatButton.set(.width, to: Values.iPadButtonWidth) let result = UIStackView(arrangedSubviews: [ explanationLabel, createNewPrivateChatButton ]) @@ -771,16 +771,6 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi present(navigationController, animated: true, completion: nil) } - @objc func createNewDM() { - let newDMVC = NewDMVC(shouldShowBackButton: false) - let navigationController = StyledNavigationController(rootViewController: newDMVC) - if UIDevice.current.isIPad { - navigationController.modalPresentationStyle = .fullScreen - } - navigationController.modalPresentationCapturesStatusBarAppearance = true - present(navigationController, animated: true, completion: nil) - } - func createNewDMFromDeepLink(sessionId: String) { let newDMVC = NewDMVC(sessionId: sessionId, shouldShowBackButton: false) let navigationController = StyledNavigationController(rootViewController: newDMVC) diff --git a/Session/Home/New Conversation/NewConversationVC.swift b/Session/Home/New Conversation/NewConversationVC.swift index 745bc66c7..c9c368191 100644 --- a/Session/Home/New Conversation/NewConversationVC.swift +++ b/Session/Home/New Conversation/NewConversationVC.swift @@ -50,8 +50,14 @@ final class NewConversationVC: BaseVC, ThemedNavigation, UITableViewDelegate, UI private lazy var contactsTitleLabel: UILabel = { let result: UILabel = UILabel() result.font = .systemFont(ofSize: Values.mediumFontSize) - result.text = "Contacts" - result.themeTextColor = .textPrimary + result.text = (newConversationViewModel.sectionData.isEmpty ? + "vc_create_closed_group_empty_state_message".localized() : + "Contacts" + ) + result.themeTextColor = (newConversationViewModel.sectionData.isEmpty ? + .textSecondary : + .textPrimary + ) return result }() diff --git a/Session/Home/New Conversation/NewConversationViewModel.swift b/Session/Home/New Conversation/NewConversationViewModel.swift index db200413f..1e93b9c54 100644 --- a/Session/Home/New Conversation/NewConversationViewModel.swift +++ b/Session/Home/New Conversation/NewConversationViewModel.swift @@ -20,18 +20,21 @@ public class NewConversationViewModel { let displayName = NSMutableString(string: profile.displayName()) CFStringTransform(displayName, nil, kCFStringTransformToLatin, false) CFStringTransform(displayName, nil, kCFStringTransformStripDiacritics, false) - let section: String = displayName.substring(to: 1).capitalized.isSingleAlphabet ? - displayName.substring(to: 1).capitalized : + + let initialCharacter: String = (displayName.length > 0 ? displayName.substring(to: 1) : "") + let section: String = initialCharacter.capitalized.isSingleAlphabet ? + initialCharacter.capitalized : "#" if groupedContacts[section] == nil { groupedContacts[section] = SectionData( sectionName: section, - contacts: []) + contacts: [] + ) } groupedContacts[section]?.contacts.append(profile) } - sectionData = groupedContacts.values.sorted{ $0.sectionName < $1.sectionName } + sectionData = groupedContacts.values.sorted { $0.sectionName < $1.sectionName } } } diff --git a/Session/Meta/AppDelegate.swift b/Session/Meta/AppDelegate.swift index 80b6da91e..01618a22e 100644 --- a/Session/Meta/AppDelegate.swift +++ b/Session/Meta/AppDelegate.swift @@ -481,7 +481,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD AppReadiness.runNowOrWhenAppDidBecomeReady { guard Identity.userExists() else { return } - SessionApp.homeViewController.wrappedValue?.createNewDM() + SessionApp.homeViewController.wrappedValue?.createNewConversation() completionHandler(true) } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender+Convenience.swift b/SessionMessagingKit/Sending & Receiving/MessageSender+Convenience.swift index 9942c3012..4f95ea77c 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender+Convenience.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender+Convenience.swift @@ -193,9 +193,8 @@ extension MessageSender { // fresh install due to the migrations getting run) guard Identity.userExists(db) else { return Promise(error: StorageError.generic) } - let destination: Message.Destination = Message.Destination.contact( - publicKey: getUserHexEncodedPublicKey(db) - ) + let publicKey: String = getUserHexEncodedPublicKey(db) + let destination: Message.Destination = Message.Destination.contact(publicKey: publicKey) let configurationMessage = try ConfigurationMessage.getCurrent(db) let (promise, seal) = Promise.pending() @@ -211,6 +210,7 @@ extension MessageSender { db, job: Job( variant: .messageSend, + threadId: publicKey, details: MessageSendJob.Details( destination: destination, message: configurationMessage diff --git a/SessionUIKit/Components/Separator.swift b/SessionUIKit/Components/Separator.swift index 7fc9b30a3..f4d8957c3 100644 --- a/SessionUIKit/Components/Separator.swift +++ b/SessionUIKit/Components/Separator.swift @@ -7,6 +7,22 @@ public final class Separator: UIView { // MARK: - Components + private let leftLine: UIView = { + let result: UIView = UIView() + result.themeBackgroundColor = .textSecondary + result.set(.height, to: Values.separatorThickness) + + return result + }() + + private let roundedLine: UIView = { + let result: UIView = UIView() + result.themeBorderColor = .textSecondary + result.layer.borderWidth = Values.separatorThickness + + return result + }() + private lazy var titleLabel: UILabel = { let result = UILabel() result.font = .systemFont(ofSize: Values.smallFontSize) @@ -16,11 +32,10 @@ public final class Separator: UIView { return result }() - private lazy var lineLayer: CAShapeLayer = { - let result = CAShapeLayer() - result.lineWidth = Values.separatorThickness - result.themeStrokeColor = .textSecondary - result.themeFillColor = .clear + private let rightLine: UIView = { + let result: UIView = UIView() + result.themeBackgroundColor = .textSecondary + result.set(.height, to: Values.separatorThickness) return result }() @@ -47,40 +62,35 @@ public final class Separator: UIView { private func setUpViewHierarchy(title: String?) { titleLabel.text = title + + addSubview(leftLine) + addSubview(roundedLine) + addSubview(rightLine) addSubview(titleLabel) titleLabel.center(.horizontal, in: self) titleLabel.center(.vertical, in: self) - layer.insertSublayer(lineLayer, at: 0) - - set(.height, to: Separator.height) + roundedLine.pin(.top, to: .top, of: self) + roundedLine.pin(.top, to: .top, of: titleLabel, withInset: -6) + roundedLine.pin(.leading, to: .leading, of: titleLabel, withInset: -10) + roundedLine.pin(.trailing, to: .trailing, of: titleLabel, withInset: 10) + roundedLine.pin(.bottom, to: .bottom, of: titleLabel, withInset: 6) + roundedLine.pin(.bottom, to: .bottom, of: self) + leftLine.pin(.leading, to: .leading, of: self) + leftLine.pin(.trailing, to: .leading, of: roundedLine) + leftLine.center(.vertical, in: self) + rightLine.pin(.leading, to: .trailing, of: roundedLine) + rightLine.pin(.trailing, to: .trailing, of: self) + rightLine.center(.vertical, in: self) } - // MARK: - Updating - public override func layoutSubviews() { super.layoutSubviews() - updateLineLayer() + roundedLine.layer.cornerRadius = (roundedLine.bounds.height / 2) } - private func updateLineLayer() { - let w = bounds.width - let h = bounds.height - let path = UIBezierPath() - path.move(to: CGPoint(x: 0, y: h / 2)) - - let titleLabelFrame = titleLabel.frame.insetBy(dx: -10, dy: -6) - path.addLine(to: CGPoint(x: titleLabelFrame.origin.x, y: h / 2)) - - let oval = UIBezierPath(roundedRect: titleLabelFrame, cornerRadius: Separator.height / 2) - path.append(oval) - path.move(to: CGPoint(x: titleLabelFrame.origin.x + titleLabelFrame.width, y: h / 2)) - path.addLine(to: CGPoint(x: w, y: h / 2)) - path.close() - - lineLayer.path = path.cgPath - } + // MARK: - Updating public func update(title: String?) { titleLabel.text = title diff --git a/SessionUIKit/Database/Migrations/_001_ThemePreferences.swift b/SessionUIKit/Database/Migrations/_001_ThemePreferences.swift index 13ebfc567..39ca24f5e 100644 --- a/SessionUIKit/Database/Migrations/_001_ThemePreferences.swift +++ b/SessionUIKit/Database/Migrations/_001_ThemePreferences.swift @@ -13,21 +13,32 @@ enum _001_ThemePreferences: Migration { static let minExpectedRunDuration: TimeInterval = 0.1 static func migrate(_ db: Database) throws { - // Determine if the user was matching the system setting - let isMatchingSystemSetting: Bool = UserDefaults.standard.dictionaryRepresentation() + // Determine if the user was matching the system setting (previously the absence of this value + // indicated that the app should match the system setting) + let isExistingUser: Bool = Identity.userExists(db) + let hadCustomLegacyThemeSetting: Bool = UserDefaults.standard.dictionaryRepresentation() .keys .contains("appMode") - - // Set the default theme settings sccordingly - db[.themeMatchSystemDayNightCycle] = isMatchingSystemSetting - db[.theme] = (isMatchingSystemSetting ? + let matchSystemNightModeSetting: Bool = (isExistingUser && !hadCustomLegacyThemeSetting) + let targetTheme: Theme = (!hadCustomLegacyThemeSetting ? Theme.classicDark : (UserDefaults.standard.integer(forKey: "appMode") == 0 ? Theme.classicLight : Theme.classicDark ) ) - db[.themePrimaryColor] = Theme.PrimaryColor.green + let targetPrimaryColor: Theme.PrimaryColor = .green + + // Save the settings + db[.themeMatchSystemDayNightCycle] = matchSystemNightModeSetting + db[.theme] = targetTheme + db[.themePrimaryColor] = targetPrimaryColor + + // Looks like the ThemeManager will load it's default values before this migration gets run + // as a result we need to update the ThemeManage to ensure the correct theme is applied + ThemeManager.currentTheme = targetTheme + ThemeManager.primaryColor = targetPrimaryColor + ThemeManager.matchSystemNightModeSetting = matchSystemNightModeSetting Storage.update(progress: 1, for: self, in: target) // In case this is the last migration } diff --git a/SessionUIKit/Style Guide/ThemeManager.swift b/SessionUIKit/Style Guide/ThemeManager.swift index 88e415949..fa165e996 100644 --- a/SessionUIKit/Style Guide/ThemeManager.swift +++ b/SessionUIKit/Style Guide/ThemeManager.swift @@ -85,7 +85,9 @@ public enum ThemeManager { // Note: We need to set this to 'unspecified' to force the UI to properly update as the // 'TraitObservingWindow' won't actually trigger the trait change otherwise - mainWindow?.overrideUserInterfaceStyle = .unspecified + DispatchQueue.main.async { + self.mainWindow?.overrideUserInterfaceStyle = .unspecified + } } } @@ -122,6 +124,10 @@ public enum ThemeManager { } public static func applyNavigationStyling() { + guard Thread.isMainThread else { + return DispatchQueue.main.async { applyNavigationStyling() } + } + let textPrimary: UIColor = (ThemeManager.currentTheme.color(for: .textPrimary) ?? .white) // Set the `mainWindow.tintColor` for system screens to use the right colour for text @@ -244,6 +250,10 @@ public enum ThemeManager { } public static func applyWindowStyling() { + guard Thread.isMainThread else { + return DispatchQueue.main.async { applyWindowStyling() } + } + mainWindow?.overrideUserInterfaceStyle = { guard !ThemeManager.matchSystemNightModeSetting else { return .unspecified } @@ -268,10 +278,7 @@ public enum ThemeManager { private static func updateAllUI() { guard Thread.isMainThread else { - DispatchQueue.main.async { - updateAllUI() - } - return + return DispatchQueue.main.async { updateAllUI() } } ThemeManager.uiRegistry.objectEnumerator()?.forEach { applier in diff --git a/SessionUtilitiesKit/General/Atomic.swift b/SessionUtilitiesKit/General/Atomic.swift index d97f438a1..865745e14 100644 --- a/SessionUtilitiesKit/General/Atomic.swift +++ b/SessionUtilitiesKit/General/Atomic.swift @@ -12,7 +12,12 @@ import Foundation /// a somewhat inconsistent interface between different `Atomic` wrappers @propertyWrapper public class Atomic { - private let queue: DispatchQueue = DispatchQueue(label: "io.oxen.\(UUID().uuidString)") + // Note: Using 'userInteractive' to ensure this can't be blockedby higher priority queues + // which could result in the main thread getting blocked + private let queue: DispatchQueue = DispatchQueue( + label: "io.oxen.\(UUID().uuidString)", + qos: .userInteractive + ) private var value: Value /// In order to change the value you **must** use the `mutate` function