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
pull/672/head
Morgan Pretty 2 years ago
parent 47083cca38
commit 58184d6d27

@ -161,25 +161,14 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate
let explanationLabel: UILabel = UILabel() let explanationLabel: UILabel = UILabel()
explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) explanationLabel.font = .systemFont(ofSize: Values.smallFontSize)
explanationLabel.text = "vc_create_closed_group_empty_state_message".localized() explanationLabel.text = "vc_create_closed_group_empty_state_message".localized()
explanationLabel.themeTextColor = .textPrimary explanationLabel.themeTextColor = .textSecondary
explanationLabel.textAlignment = .center explanationLabel.textAlignment = .center
explanationLabel.lineBreakMode = .byWordWrapping explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.numberOfLines = 0 explanationLabel.numberOfLines = 0
let createNewPrivateChatButton: SessionButton = SessionButton(style: .bordered, size: .medium) view.addSubview(explanationLabel)
createNewPrivateChatButton.setTitle("vc_create_closed_group_empty_state_button_title".localized(), for: .normal) explanationLabel.pin(.top, to: .top, of: view, withInset: Values.largeSpacing)
createNewPrivateChatButton.addTarget(self, action: #selector(createNewDM), for: .touchUpInside) explanationLabel.center(.horizontal, in: view)
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
return return
} }
@ -348,12 +337,6 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate
.retainUntilComplete() .retainUntilComplete()
} }
} }
@objc private func createNewDM() {
presentingViewController?.dismiss(animated: true, completion: nil)
SessionApp.homeViewController.wrappedValue?.createNewDM()
}
} }
extension NewClosedGroupVC: UISearchBarDelegate { extension NewClosedGroupVC: UISearchBarDelegate {

@ -519,6 +519,7 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
// Constraints // Constraints
bubbleView.addSubview(stackView) bubbleView.addSubview(stackView)
stackView.pin(to: bubbleView, withInset: inset) stackView.pin(to: bubbleView, withInset: inset)
stackView.widthAnchor.constraint(lessThanOrEqualToConstant: maxWidth).isActive = true
snContentView.addArrangedSubview(bubbleBackgroundView) snContentView.addArrangedSubview(bubbleBackgroundView)
} }

@ -185,7 +185,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi
let createNewPrivateChatButton = SessionButton(style: .bordered, size: .large) let createNewPrivateChatButton = SessionButton(style: .bordered, size: .large)
createNewPrivateChatButton.setTitle("vc_home_empty_state_button_title".localized(), for: .normal) 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) createNewPrivateChatButton.set(.width, to: Values.iPadButtonWidth)
let result = UIStackView(arrangedSubviews: [ explanationLabel, createNewPrivateChatButton ]) let result = UIStackView(arrangedSubviews: [ explanationLabel, createNewPrivateChatButton ])
@ -771,16 +771,6 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi
present(navigationController, animated: true, completion: nil) 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) { func createNewDMFromDeepLink(sessionId: String) {
let newDMVC = NewDMVC(sessionId: sessionId, shouldShowBackButton: false) let newDMVC = NewDMVC(sessionId: sessionId, shouldShowBackButton: false)
let navigationController = StyledNavigationController(rootViewController: newDMVC) let navigationController = StyledNavigationController(rootViewController: newDMVC)

@ -50,8 +50,14 @@ final class NewConversationVC: BaseVC, ThemedNavigation, UITableViewDelegate, UI
private lazy var contactsTitleLabel: UILabel = { private lazy var contactsTitleLabel: UILabel = {
let result: UILabel = UILabel() let result: UILabel = UILabel()
result.font = .systemFont(ofSize: Values.mediumFontSize) result.font = .systemFont(ofSize: Values.mediumFontSize)
result.text = "Contacts" result.text = (newConversationViewModel.sectionData.isEmpty ?
result.themeTextColor = .textPrimary "vc_create_closed_group_empty_state_message".localized() :
"Contacts"
)
result.themeTextColor = (newConversationViewModel.sectionData.isEmpty ?
.textSecondary :
.textPrimary
)
return result return result
}() }()

@ -20,18 +20,21 @@ public class NewConversationViewModel {
let displayName = NSMutableString(string: profile.displayName()) let displayName = NSMutableString(string: profile.displayName())
CFStringTransform(displayName, nil, kCFStringTransformToLatin, false) CFStringTransform(displayName, nil, kCFStringTransformToLatin, false)
CFStringTransform(displayName, nil, kCFStringTransformStripDiacritics, 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 { if groupedContacts[section] == nil {
groupedContacts[section] = SectionData( groupedContacts[section] = SectionData(
sectionName: section, sectionName: section,
contacts: []) contacts: []
)
} }
groupedContacts[section]?.contacts.append(profile) groupedContacts[section]?.contacts.append(profile)
} }
sectionData = groupedContacts.values.sorted{ $0.sectionName < $1.sectionName } sectionData = groupedContacts.values.sorted { $0.sectionName < $1.sectionName }
} }
} }

@ -481,7 +481,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
AppReadiness.runNowOrWhenAppDidBecomeReady { AppReadiness.runNowOrWhenAppDidBecomeReady {
guard Identity.userExists() else { return } guard Identity.userExists() else { return }
SessionApp.homeViewController.wrappedValue?.createNewDM() SessionApp.homeViewController.wrappedValue?.createNewConversation()
completionHandler(true) completionHandler(true)
} }
} }

@ -193,9 +193,8 @@ extension MessageSender {
// fresh install due to the migrations getting run) // fresh install due to the migrations getting run)
guard Identity.userExists(db) else { return Promise(error: StorageError.generic) } guard Identity.userExists(db) else { return Promise(error: StorageError.generic) }
let destination: Message.Destination = Message.Destination.contact( let publicKey: String = getUserHexEncodedPublicKey(db)
publicKey: getUserHexEncodedPublicKey(db) let destination: Message.Destination = Message.Destination.contact(publicKey: publicKey)
)
let configurationMessage = try ConfigurationMessage.getCurrent(db) let configurationMessage = try ConfigurationMessage.getCurrent(db)
let (promise, seal) = Promise<Void>.pending() let (promise, seal) = Promise<Void>.pending()
@ -211,6 +210,7 @@ extension MessageSender {
db, db,
job: Job( job: Job(
variant: .messageSend, variant: .messageSend,
threadId: publicKey,
details: MessageSendJob.Details( details: MessageSendJob.Details(
destination: destination, destination: destination,
message: configurationMessage message: configurationMessage

@ -7,6 +7,22 @@ public final class Separator: UIView {
// MARK: - Components // 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 = { private lazy var titleLabel: UILabel = {
let result = UILabel() let result = UILabel()
result.font = .systemFont(ofSize: Values.smallFontSize) result.font = .systemFont(ofSize: Values.smallFontSize)
@ -16,11 +32,10 @@ public final class Separator: UIView {
return result return result
}() }()
private lazy var lineLayer: CAShapeLayer = { private let rightLine: UIView = {
let result = CAShapeLayer() let result: UIView = UIView()
result.lineWidth = Values.separatorThickness result.themeBackgroundColor = .textSecondary
result.themeStrokeColor = .textSecondary result.set(.height, to: Values.separatorThickness)
result.themeFillColor = .clear
return result return result
}() }()
@ -47,40 +62,35 @@ public final class Separator: UIView {
private func setUpViewHierarchy(title: String?) { private func setUpViewHierarchy(title: String?) {
titleLabel.text = title titleLabel.text = title
addSubview(leftLine)
addSubview(roundedLine)
addSubview(rightLine)
addSubview(titleLabel) addSubview(titleLabel)
titleLabel.center(.horizontal, in: self) titleLabel.center(.horizontal, in: self)
titleLabel.center(.vertical, in: self) titleLabel.center(.vertical, in: self)
layer.insertSublayer(lineLayer, at: 0) roundedLine.pin(.top, to: .top, of: self)
roundedLine.pin(.top, to: .top, of: titleLabel, withInset: -6)
set(.height, to: Separator.height) 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() { public override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
updateLineLayer() roundedLine.layer.cornerRadius = (roundedLine.bounds.height / 2)
} }
private func updateLineLayer() { // MARK: - Updating
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
}
public func update(title: String?) { public func update(title: String?) {
titleLabel.text = title titleLabel.text = title

@ -13,21 +13,32 @@ enum _001_ThemePreferences: Migration {
static let minExpectedRunDuration: TimeInterval = 0.1 static let minExpectedRunDuration: TimeInterval = 0.1
static func migrate(_ db: Database) throws { static func migrate(_ db: Database) throws {
// Determine if the user was matching the system setting // Determine if the user was matching the system setting (previously the absence of this value
let isMatchingSystemSetting: Bool = UserDefaults.standard.dictionaryRepresentation() // indicated that the app should match the system setting)
let isExistingUser: Bool = Identity.userExists(db)
let hadCustomLegacyThemeSetting: Bool = UserDefaults.standard.dictionaryRepresentation()
.keys .keys
.contains("appMode") .contains("appMode")
let matchSystemNightModeSetting: Bool = (isExistingUser && !hadCustomLegacyThemeSetting)
// Set the default theme settings sccordingly let targetTheme: Theme = (!hadCustomLegacyThemeSetting ?
db[.themeMatchSystemDayNightCycle] = isMatchingSystemSetting
db[.theme] = (isMatchingSystemSetting ?
Theme.classicDark : Theme.classicDark :
(UserDefaults.standard.integer(forKey: "appMode") == 0 ? (UserDefaults.standard.integer(forKey: "appMode") == 0 ?
Theme.classicLight : Theme.classicLight :
Theme.classicDark 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 Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
} }

@ -85,7 +85,9 @@ public enum ThemeManager {
// Note: We need to set this to 'unspecified' to force the UI to properly update as the // 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 // '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() { public static func applyNavigationStyling() {
guard Thread.isMainThread else {
return DispatchQueue.main.async { applyNavigationStyling() }
}
let textPrimary: UIColor = (ThemeManager.currentTheme.color(for: .textPrimary) ?? .white) let textPrimary: UIColor = (ThemeManager.currentTheme.color(for: .textPrimary) ?? .white)
// Set the `mainWindow.tintColor` for system screens to use the right colour for text // 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() { public static func applyWindowStyling() {
guard Thread.isMainThread else {
return DispatchQueue.main.async { applyWindowStyling() }
}
mainWindow?.overrideUserInterfaceStyle = { mainWindow?.overrideUserInterfaceStyle = {
guard !ThemeManager.matchSystemNightModeSetting else { return .unspecified } guard !ThemeManager.matchSystemNightModeSetting else { return .unspecified }
@ -268,10 +278,7 @@ public enum ThemeManager {
private static func updateAllUI() { private static func updateAllUI() {
guard Thread.isMainThread else { guard Thread.isMainThread else {
DispatchQueue.main.async { return DispatchQueue.main.async { updateAllUI() }
updateAllUI()
}
return
} }
ThemeManager.uiRegistry.objectEnumerator()?.forEach { applier in ThemeManager.uiRegistry.objectEnumerator()?.forEach { applier in

@ -12,7 +12,12 @@ import Foundation
/// a somewhat inconsistent interface between different `Atomic` wrappers /// a somewhat inconsistent interface between different `Atomic` wrappers
@propertyWrapper @propertyWrapper
public class Atomic<Value> { public class Atomic<Value> {
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 private var value: Value
/// In order to change the value you **must** use the `mutate` function /// In order to change the value you **must** use the `mutate` function

Loading…
Cancel
Save