diff --git a/Session/Closed Groups/NewClosedGroupVC.swift b/Session/Closed Groups/NewClosedGroupVC.swift index 5dee4878a..356a35c80 100644 --- a/Session/Closed Groups/NewClosedGroupVC.swift +++ b/Session/Closed Groups/NewClosedGroupVC.swift @@ -5,6 +5,7 @@ import GRDB import PromiseKit import SessionUIKit import SessionMessagingKit +import SignalUtilitiesKit private protocol TableViewTouchDelegate { func tableViewWasTouched(_ tableView: TableView) @@ -25,17 +26,18 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate // MARK: - Components - private lazy var nameTextField = TextField(placeholder: "vc_create_closed_group_text_field_hint".localized()) + private lazy var nameTextField = TextField( + placeholder: "vc_create_closed_group_text_field_hint".localized() + ) private lazy var tableView: TableView = { let result: TableView = TableView() + result.separatorStyle = .none + result.themeBackgroundColor = .clear + result.register(view: UserCell.self) + result.touchDelegate = self result.dataSource = self result.delegate = self - result.touchDelegate = self - result.separatorStyle = .none - result.backgroundColor = .clear - result.isScrollEnabled = false - result.register(view: UserCell.self) return result }() @@ -50,11 +52,11 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate // Set up navigation bar buttons let closeButton = UIBarButtonItem(image: #imageLiteral(resourceName: "X"), style: .plain, target: self, action: #selector(close)) - closeButton.tintColor = Colors.text + closeButton.themeTintColor = .textPrimary navigationItem.leftBarButtonItem = closeButton let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(createClosedGroup)) - doneButton.tintColor = Colors.text + doneButton.themeTintColor = .textPrimary navigationItem.rightBarButtonItem = doneButton // Set up content @@ -66,7 +68,7 @@ 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.textColor = Colors.text + explanationLabel.themeTextColor = .textPrimary explanationLabel.textAlignment = .center explanationLabel.lineBreakMode = .byWordWrapping explanationLabel.numberOfLines = 0 @@ -88,33 +90,23 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate return } - let mainStackView: UIStackView = UIStackView() - mainStackView.axis = .vertical - nameTextField.delegate = self - let nameTextFieldContainer: UIView = UIView() + view.addSubview(nameTextFieldContainer) + nameTextFieldContainer.pin(.top, to: .top, of: view) + nameTextFieldContainer.pin(.leading, to: .leading, of: view) + nameTextFieldContainer.pin(.trailing, to: .trailing, of: view) + nameTextFieldContainer.addSubview(nameTextField) - nameTextField.pin(.leading, to: .leading, of: nameTextFieldContainer, withInset: Values.largeSpacing) nameTextField.pin(.top, to: .top, of: nameTextFieldContainer, withInset: Values.mediumSpacing) - nameTextFieldContainer.pin(.trailing, to: .trailing, of: nameTextField, withInset: Values.largeSpacing) - nameTextFieldContainer.pin(.bottom, to: .bottom, of: nameTextField, withInset: Values.largeSpacing) - mainStackView.addArrangedSubview(nameTextFieldContainer) + nameTextField.pin(.leading, to: .leading, of: nameTextFieldContainer, withInset: Values.largeSpacing) + nameTextField.pin(.trailing, to: .trailing, of: nameTextFieldContainer, withInset: -Values.largeSpacing) + nameTextField.pin(.bottom, to: .bottom, of: nameTextFieldContainer, withInset: -Values.largeSpacing) - let separator: UIView = UIView() - separator.backgroundColor = Colors.separator - separator.set(.height, to: Values.separatorThickness) - mainStackView.addArrangedSubview(separator) - tableView.set(.height, to: CGFloat(contactProfiles.count * 65)) // A cell is exactly 65 points high - tableView.set(.width, to: UIScreen.main.bounds.width) - mainStackView.addArrangedSubview(tableView) - - let scrollView: UIScrollView = UIScrollView(wrapping: mainStackView, withInsets: UIEdgeInsets.zero) - scrollView.showsVerticalScrollIndicator = false - scrollView.delegate = self - view.addSubview(scrollView) - - scrollView.set(.width, to: UIScreen.main.bounds.width) - scrollView.pin(to: view) + view.addSubview(tableView) + tableView.pin(.top, to: .bottom, of: nameTextFieldContainer, withInset: Values.mediumSpacing) + tableView.pin(.leading, to: .leading, of: view) + tableView.pin(.trailing, to: .trailing, of: view) + tableView.pin(.bottom, to: .bottom, of: view) } // MARK: - Table View Data Source @@ -135,27 +127,16 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate return cell } - // MARK: - Interaction + // MARK: - UITableViewDelegate - func textFieldDidEndEditing(_ textField: UITextField) { - crossfadeLabel.text = textField.text!.isEmpty ? NSLocalizedString("vc_create_closed_group_title", comment: "") : textField.text! + func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { + return UITableView.automaticDimension } - fileprivate func tableViewWasTouched(_ tableView: TableView) { - if nameTextField.isFirstResponder { - nameTextField.resignFirstResponder() - } + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return UITableView.automaticDimension } - - func scrollViewDidScroll(_ scrollView: UIScrollView) { - let nameTextFieldCenterY = nameTextField.convert(nameTextField.bounds.center, to: scrollView).y - let tableViewOriginY = tableView.convert(tableView.bounds.origin, to: scrollView).y - let titleLabelAlpha = 1 - (scrollView.contentOffset.y - nameTextFieldCenterY) / (tableViewOriginY - nameTextFieldCenterY) - let crossfadeLabelAlpha = 1 - titleLabelAlpha - navBarTitleLabel.alpha = titleLabelAlpha - crossfadeLabel.alpha = crossfadeLabelAlpha - } - + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if !selectedContacts.contains(contactProfiles[indexPath.row].id) { selectedContacts.insert(contactProfiles[indexPath.row].id) @@ -168,6 +149,30 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate tableView.reloadRows(at: [indexPath], with: .none) } + func scrollViewDidScroll(_ scrollView: UIScrollView) { + let nameTextFieldCenterY = nameTextField.convert(nameTextField.bounds.center, to: scrollView).y + let tableViewOriginY = tableView.convert(tableView.bounds.origin, to: scrollView).y + let titleLabelAlpha = 1 - (scrollView.contentOffset.y - nameTextFieldCenterY) / (tableViewOriginY - nameTextFieldCenterY) + let crossfadeLabelAlpha = 1 - titleLabelAlpha + navBarTitleLabel.alpha = titleLabelAlpha + crossfadeLabel.alpha = crossfadeLabelAlpha + } + + // MARK: - Interaction + + func textFieldDidEndEditing(_ textField: UITextField) { + crossfadeLabel.text = (textField.text?.isEmpty == true ? + "vc_create_closed_group_title".localized() : + textField.text + ) + } + + fileprivate func tableViewWasTouched(_ tableView: TableView) { + if nameTextField.isFirstResponder { + nameTextField.resignFirstResponder() + } + } + @objc private func close() { dismiss(animated: true, completion: nil) } @@ -175,20 +180,20 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate @objc private func createClosedGroup() { func showError(title: String, message: String = "") { let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_OK", comment: ""), style: .default, handler: nil)) + alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil)) presentAlert(alert) } guard let name = nameTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines), name.count > 0 else { - return showError(title: NSLocalizedString("vc_create_closed_group_group_name_missing_error", comment: "")) + return showError(title: "vc_create_closed_group_group_name_missing_error".localized()) } guard name.count < 64 else { - return showError(title: NSLocalizedString("vc_create_closed_group_group_name_too_long_error", comment: "")) + return showError(title: "vc_create_closed_group_group_name_too_long_error".localized()) } guard selectedContacts.count >= 1 else { return showError(title: "Please pick at least 1 group member") } guard selectedContacts.count < 100 else { // Minus one because we're going to include self later - return showError(title: NSLocalizedString("vc_create_closed_group_too_many_group_members_error", comment: "")) + return showError(title: "vc_create_closed_group_too_many_group_members_error".localized()) } let selectedContacts = self.selectedContacts let message: String? = (selectedContacts.count > 20) ? "Please wait while the group is created..." : nil @@ -211,7 +216,7 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate let title = "Couldn't Create Group" let message = "Please check your internet connection and try again." let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_OK", comment: ""), style: .default, handler: nil)) + alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil)) self?.presentAlert(alert) } .retainUntilComplete() diff --git a/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift b/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift index b982af6a2..330b9133e 100644 --- a/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift +++ b/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift @@ -33,11 +33,21 @@ final class LinkPreviewView: UIView { return result }() - private lazy var loader: NVActivityIndicatorView = { - // FIXME: This will have issues with theme transitions - let color: UIColor = (isLightMode ? .black : .white) + private let loader: NVActivityIndicatorView = { + let result: NVActivityIndicatorView = NVActivityIndicatorView( + frame: CGRect.zero, + type: .circleStrokeSpin, + color: .black, + padding: nil + ) - return NVActivityIndicatorView(frame: CGRect.zero, type: .circleStrokeSpin, color: color, padding: nil) + ThemeManager.onThemeChange(observer: result) { [weak result] theme, _ in + guard let textPrimary: UIColor = theme.colors[.textPrimary] else { return } + + result?.color = textPrimary + } + + return result }() private lazy var titleLabel: UILabel = { diff --git a/Session/Conversations/Message Cells/Content Views/VoiceMessageView.swift b/Session/Conversations/Message Cells/Content Views/VoiceMessageView.swift index c96625dcb..03468f17d 100644 --- a/Session/Conversations/Message Cells/Content Views/VoiceMessageView.swift +++ b/Session/Conversations/Message Cells/Content Views/VoiceMessageView.swift @@ -30,16 +30,22 @@ public final class VoiceMessageView: UIView { return result }() - private lazy var loader: NVActivityIndicatorView = { + private let loader: NVActivityIndicatorView = { let result: NVActivityIndicatorView = NVActivityIndicatorView( frame: .zero, type: .circleStrokeSpin, - color: Colors.text, + color: .black, padding: nil ) result.set(.width, to: VoiceMessageView.toggleContainerSize + 2) result.set(.height, to: VoiceMessageView.toggleContainerSize + 2) + ThemeManager.onThemeChange(observer: result) { [weak result] theme, _ in + guard let textPrimary: UIColor = theme.colors[.textPrimary] else { return } + + result?.color = textPrimary + } + return result }() diff --git a/Session/DMs/NewDMVC.swift b/Session/DMs/NewDMVC.swift index b34f2ff55..c1ace80c7 100644 --- a/Session/DMs/NewDMVC.swift +++ b/Session/DMs/NewDMVC.swift @@ -7,12 +7,13 @@ import SessionUIKit import SessionMessagingKit import SessionUtilitiesKit -final class NewDMVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControllerDelegate, OWSQRScannerDelegate { +final class NewDMVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControllerDelegate, OWSQRScannerDelegate { private let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil) private var pages: [UIViewController] = [] private var targetVCIndex: Int? - // MARK: Components + // MARK: - Components + private lazy var tabBar: TabBar = { let tabs = [ TabBar.Tab(title: "vc_create_private_chat_enter_session_id_tab_title".localized()) { [weak self] in @@ -24,23 +25,26 @@ final class NewDMVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControll self.pageVC.setViewControllers([ self.pages[1] ], direction: .forward, animated: false, completion: nil) } ] + return TabBar(tabs: tabs) }() private lazy var enterPublicKeyVC: EnterPublicKeyVC = { let result = EnterPublicKeyVC() result.NewDMVC = self + return result }() private lazy var scanQRCodePlaceholderVC: ScanQRCodePlaceholderVC = { let result = ScanQRCodePlaceholderVC() result.NewDMVC = self + return result }() private lazy var scanQRCodeWrapperVC: ScanQRCodeWrapperVC = { - let message = NSLocalizedString("vc_create_private_chat_scan_qr_code_explanation", comment: "") + let message = "vc_create_private_chat_scan_qr_code_explanation".localized() let result = ScanQRCodeWrapperVC(message: message) result.delegate = self return result @@ -59,28 +63,33 @@ final class NewDMVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControll super.init(nibName: nibName, bundle: bundle) } - // MARK: Lifecycle + // MARK: - Lifecycle + override func viewDidLoad() { super.viewDidLoad() setNavBarTitle("vc_create_private_chat_title".localized()) let navigationBar = navigationController!.navigationBar + // Set up navigation bar buttons let closeButton = UIBarButtonItem(image: #imageLiteral(resourceName: "X"), style: .plain, target: self, action: #selector(close)) - closeButton.tintColor = Colors.text + closeButton.themeTintColor = .textPrimary navigationItem.leftBarButtonItem = closeButton + // Set up page VC let hasCameraAccess = (AVCaptureDevice.authorizationStatus(for: .video) == .authorized) pages = [ enterPublicKeyVC, (hasCameraAccess ? scanQRCodeWrapperVC : scanQRCodePlaceholderVC) ] pageVC.dataSource = self pageVC.delegate = self pageVC.setViewControllers([ enterPublicKeyVC ], direction: .forward, animated: false, completion: nil) + // Set up tab bar + let tabBarInset: CGFloat = (UIDevice.current.isIPad ? navigationBar.height() + 20 : navigationBar.height()) view.addSubview(tabBar) tabBar.pin(.leading, to: .leading, of: view) - let tabBarInset: CGFloat = (UIDevice.current.isIPad ? navigationBar.height() + 20 : navigationBar.height()) tabBar.pin(.top, to: .top, of: view, withInset: tabBarInset) view.pin(.trailing, to: .trailing, of: tabBar) + // Set up page VC constraints let pageVCView = pageVC.view! view.addSubview(pageVCView) @@ -88,15 +97,18 @@ final class NewDMVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControll pageVCView.pin(.top, to: .bottom, of: tabBar) view.pin(.trailing, to: .trailing, of: pageVCView) view.pin(.bottom, to: .bottom, of: pageVCView) + let screen = UIScreen.main.bounds - pageVCView.set(.width, to: screen.width) let height: CGFloat = (navigationController!.view.bounds.height - navigationBar.height() - TabBar.snHeight) + pageVCView.set(.width, to: screen.width) pageVCView.set(.height, to: height) + enterPublicKeyVC.constrainHeight(to: height) scanQRCodePlaceholderVC.constrainHeight(to: height) } - // MARK: General + // MARK: - General + func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { guard let index = pages.firstIndex(of: viewController), index != 0 else { return nil } return pages[index - 1] @@ -112,7 +124,8 @@ final class NewDMVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControll pageVC.setViewControllers([ scanQRCodeWrapperVC ], direction: .forward, animated: false, completion: nil) } - // MARK: Updating + // MARK: - Updating + func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) { guard let targetVC = pendingViewControllers.first, let index = pages.firstIndex(of: targetVC) else { return } targetVCIndex = index @@ -123,7 +136,8 @@ final class NewDMVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControll tabBar.selectTab(at: index) } - // MARK: Interaction + // MARK: - Interaction + @objc private func close() { dismiss(animated: true, completion: nil) } @@ -142,36 +156,40 @@ final class NewDMVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControll } // This could be an ONS name - ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self] modalActivityIndicator in - SnodeAPI.getSessionID(for: onsNameOrPublicKey).done { sessionID in - modalActivityIndicator.dismiss { - self?.startNewDM(with: sessionID) - } - }.catch { error in - modalActivityIndicator.dismiss { - var messageOrNil: String? - if let error = error as? SnodeAPIError { - switch error { - case .decryptionFailed, .hashingFailed, .validationFailed: - messageOrNil = error.errorDescription - default: break + ModalActivityIndicatorViewController + .present(fromViewController: navigationController!, canCancel: false) { [weak self] modalActivityIndicator in + SnodeAPI + .getSessionID(for: onsNameOrPublicKey) + .done { sessionID in + modalActivityIndicator.dismiss { + self?.startNewDM(with: sessionID) } } - let message: String = { - if let messageOrNil: String = messageOrNil { - return messageOrNil + .catch { error in + modalActivityIndicator.dismiss { + var messageOrNil: String? + if let error = error as? SnodeAPIError { + switch error { + case .decryptionFailed, .hashingFailed, .validationFailed: + messageOrNil = error.errorDescription + default: break + } + } + let message: String = { + if let messageOrNil: String = messageOrNil { + return messageOrNil + } + + return (maybeSessionId?.prefix == .blinded ? + "You can only send messages to Blinded IDs from within an Open Group" : + "Please check the Session ID or ONS name and try again" + ) + }() + let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil)) + self?.presentAlert(alert) } - - return (maybeSessionId?.prefix == .blinded ? - "You can only send messages to Blinded IDs from within an Open Group" : - "Please check the Session ID or ONS name and try again" - ) - }() - let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil)) - self?.presentAlert(alert) - } - } + } } } @@ -188,51 +206,57 @@ final class NewDMVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControll } } -private final class EnterPublicKeyVC : UIViewController { +// MARK: - EnterPublicKeyVC + +private final class EnterPublicKeyVC: UIViewController { weak var NewDMVC: NewDMVC! private var isKeyboardShowing = false + private var simulatorWillResignFirstResponder = false private var bottomConstraint: NSLayoutConstraint! private let bottomMargin: CGFloat = UIDevice.current.isIPad ? Values.largeSpacing : 0 - // MARK: Components + // MARK: - Components private lazy var publicKeyTextView: TextView = { - let result = TextView(placeholder: NSLocalizedString("vc_enter_public_key_text_field_hint", comment: "")) + let result = TextView(placeholder: "vc_enter_public_key_text_field_hint".localized()) result.autocapitalizationType = .none + return result }() private lazy var copyButton: OutlineButton = { let result = OutlineButton(style: .regular, size: .small) - result.setTitle("copy".lowercased(), for: UIControl.State.normal) - result.addTarget(self, action: #selector(copyPublicKey), for: UIControl.Event.touchUpInside) + result.setTitle("copy".localized(), for: .normal) + result.addTarget(self, action: #selector(copyPublicKey), for: .touchUpInside) return result }() private lazy var shareButton: OutlineButton = { let result = OutlineButton(style: .regular, size: .small) - result.setTitle("share".lowercased(), for: UIControl.State.normal) - result.addTarget(self, action: #selector(sharePublicKey), for: UIControl.Event.touchUpInside) + result.setTitle("share".localized(), for: .normal) + result.addTarget(self, action: #selector(sharePublicKey), for: .touchUpInside) return result }() private lazy var nextButton: OutlineButton = { - let result = OutlineButton(style: .regular, size: .small) - result.setTitle("next".lowercased(), for: UIControl.State.normal) - result.addTarget(self, action: #selector(startNewDMIfPossible), for: UIControl.Event.touchUpInside) + let result = OutlineButton(style: .regular, size: .large) + result.setTitle("next".localized(), for: .normal) + result.addTarget(self, action: #selector(startNewDMIfPossible), for: .touchUpInside) + result.alpha = 0 return result }() private lazy var userPublicKeyLabel: UILabel = { let result = UILabel() - result.textColor = Colors.text result.font = Fonts.spaceMono(ofSize: Values.mediumFontSize) - result.numberOfLines = 0 + result.text = getUserHexEncodedPublicKey() + result.themeTextColor = .textPrimary result.textAlignment = .center result.lineBreakMode = .byCharWrapping - result.text = getUserHexEncodedPublicKey() + result.numberOfLines = 0 + return result }() @@ -240,42 +264,53 @@ private final class EnterPublicKeyVC : UIViewController { private lazy var spacer2 = UIView.spacer(withHeight: Values.largeSpacing) private lazy var spacer3 = UIView.spacer(withHeight: Values.largeSpacing) - private lazy var separator = Separator(title: NSLocalizedString("your_session_id", comment: "")) + private lazy var separator = Separator(title: "your_session_id".localized()) private lazy var buttonContainer: UIStackView = { let result = UIStackView() result.axis = .horizontal result.spacing = UIDevice.current.isIPad ? Values.iPadButtonSpacing : Values.mediumSpacing result.distribution = .fillEqually + if (UIDevice.current.isIPad) { result.layoutMargins = UIEdgeInsets(top: 0, left: Values.iPadButtonContainerMargin, bottom: 0, right: Values.iPadButtonContainerMargin) result.isLayoutMarginsRelativeArrangement = true } + return result }() - // MARK: Lifecycle + // MARK: - Lifecycle + override func viewDidLoad() { // Remove background color - view.backgroundColor = .clear + view.themeBackgroundColor = .clear // User session id container - let userPublicKeyContainer = UIView(wrapping: userPublicKeyLabel, withInsets: .zero, shouldAdaptForIPadWithWidth: Values.iPadUserSessionIdContainerWidth) + let userPublicKeyContainer = UIView( + wrapping: userPublicKeyLabel, + withInsets: .zero, + shouldAdaptForIPadWithWidth: Values.iPadUserSessionIdContainerWidth + ) // Explanation label let explanationLabel = UILabel() - explanationLabel.textColor = Colors.text.withAlphaComponent(Values.mediumOpacity) explanationLabel.font = .systemFont(ofSize: Values.verySmallFontSize) - explanationLabel.text = NSLocalizedString("vc_enter_public_key_explanation", comment: "") - explanationLabel.numberOfLines = 0 + explanationLabel.text = "vc_enter_public_key_explanation".localized() + explanationLabel.themeTextColor = .textSecondary explanationLabel.textAlignment = .center explanationLabel.lineBreakMode = .byWordWrapping + explanationLabel.numberOfLines = 0 // Button container buttonContainer.addArrangedSubview(copyButton) buttonContainer.addArrangedSubview(shareButton) - let nextButtonContainer = UIView(wrapping: nextButton, withInsets: UIEdgeInsets(top: 0, leading: 80, bottom: 0, trailing: 80), shouldAdaptForIPadWithWidth: Values.iPadButtonWidth) + let nextButtonContainer = UIView( + wrapping: nextButton, + withInsets: UIEdgeInsets(top: 0, leading: 80, bottom: 0, trailing: 80), + shouldAdaptForIPadWithWidth: Values.iPadButtonWidth + ) // Main stack view let mainStackView = UIStackView(arrangedSubviews: [ publicKeyTextView, UIView.spacer(withHeight: Values.smallSpacing), explanationLabel, spacer1, separator, spacer2, userPublicKeyContainer, spacer3, buttonContainer, UIView.vStretchingSpacer(), nextButtonContainer ]) @@ -306,7 +341,8 @@ private final class EnterPublicKeyVC : UIViewController { NotificationCenter.default.removeObserver(self) } - // MARK: General + // MARK: - General + func setSessionID(to sessionID: String){ publicKeyTextView.insertText(sessionID) } @@ -316,62 +352,92 @@ private final class EnterPublicKeyVC : UIViewController { } @objc private func dismissKeyboard() { + simulatorWillResignFirstResponder = true publicKeyTextView.resignFirstResponder() + simulatorWillResignFirstResponder = false } @objc private func enableCopyButton() { copyButton.isUserInteractionEnabled = true + UIView.transition(with: copyButton, duration: 0.25, options: .transitionCrossDissolve, animations: { - self.copyButton.setTitle(NSLocalizedString("copy", comment: ""), for: UIControl.State.normal) + self.copyButton.setTitle("copy".localized(), for: .normal) }, completion: nil) } - // MARK: Updating + // MARK: - Updating + @objc private func handleKeyboardWillChangeFrameNotification(_ notification: Notification) { + #if targetEnvironment(simulator) + // Note: See 'handleKeyboardWillHideNotification' for the explanation + guard !simulatorWillResignFirstResponder else { return } + #else guard !isKeyboardShowing else { return } + #endif + isKeyboardShowing = true + guard let newHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size.height else { return } + bottomConstraint.constant = newHeight + bottomMargin + UIView.animate(withDuration: 0.25) { [ self.spacer1, self.separator, self.spacer2, self.userPublicKeyLabel, self.spacer3, self.buttonContainer ].forEach { $0.alpha = 0 $0.isHidden = true } + self.nextButton.alpha = 1 self.view.layoutIfNeeded() } } @objc private func handleKeyboardWillHideNotification(_ notification: Notification) { + #if targetEnvironment(simulator) + // Note: On the simulator the keyboard won't appear by default (unless you enable + // it) this results in the "keyboard will hide" notification incorrectly getting + // triggered immediately - the 'simulatorWillResignFirstResponder' value is a workaround + // to make this behave more like a real device when testing + guard isKeyboardShowing && simulatorWillResignFirstResponder else { return } + #else guard isKeyboardShowing else { return } + #endif + isKeyboardShowing = false bottomConstraint.constant = bottomMargin + UIView.animate(withDuration: 0.25) { [ self.spacer1, self.separator, self.spacer2, self.userPublicKeyLabel, self.spacer3, self.buttonContainer ].forEach { $0.alpha = 1 $0.isHidden = false } + self.nextButton.alpha = (self.publicKeyTextView.text.isEmpty ? 0 : 1) self.view.layoutIfNeeded() } } - // MARK: Interaction + // MARK: - Interaction + @objc private func copyPublicKey() { UIPasteboard.general.string = getUserHexEncodedPublicKey() + copyButton.isUserInteractionEnabled = false + UIView.transition(with: copyButton, duration: 0.25, options: .transitionCrossDissolve, animations: { - self.copyButton.setTitle(NSLocalizedString("copied", comment: ""), for: UIControl.State.normal) + self.copyButton.setTitle("copied".localized(), for: .normal) }, completion: nil) Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(enableCopyButton), userInfo: nil, repeats: false) } @objc private func sharePublicKey() { let shareVC = UIActivityViewController(activityItems: [ getUserHexEncodedPublicKey() ], applicationActivities: nil) + if UIDevice.current.isIPad { shareVC.excludedActivityTypes = [] shareVC.popoverPresentationController?.permittedArrowDirections = [] shareVC.popoverPresentationController?.sourceView = self.view shareVC.popoverPresentationController?.sourceRect = self.view.bounds } + NewDMVC.navigationController!.present(shareVC, animated: true, completion: nil) } @@ -381,36 +447,43 @@ private final class EnterPublicKeyVC : UIViewController { } } -private final class ScanQRCodePlaceholderVC : UIViewController { +// MARK: - ScanQRCodePlaceholderVC + +private final class ScanQRCodePlaceholderVC: UIViewController { weak var NewDMVC: NewDMVC! override func viewDidLoad() { // Remove background color - view.backgroundColor = .clear + view.themeBackgroundColor = .clear + // Set up explanation label let explanationLabel = UILabel() - explanationLabel.textColor = Colors.text explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) - explanationLabel.text = NSLocalizedString("vc_scan_qr_code_camera_access_explanation", comment: "") - explanationLabel.numberOfLines = 0 + explanationLabel.text = "vc_scan_qr_code_camera_access_explanation".localized() + explanationLabel.themeTextColor = .textPrimary explanationLabel.textAlignment = .center explanationLabel.lineBreakMode = .byWordWrapping + explanationLabel.numberOfLines = 0 + // Set up call to action button let callToActionButton = UIButton() - callToActionButton.titleLabel!.font = .boldSystemFont(ofSize: Values.mediumFontSize) - callToActionButton.setTitleColor(Colors.accent, for: UIControl.State.normal) - callToActionButton.setTitle(NSLocalizedString("vc_scan_qr_code_grant_camera_access_button_title", comment: ""), for: UIControl.State.normal) + callToActionButton.titleLabel?.font = .boldSystemFont(ofSize: Values.mediumFontSize) + callToActionButton.setTitle("vc_scan_qr_code_grant_camera_access_button_title".localized(), for: UIControl.State.normal) + callToActionButton.setThemeTitleColor(.primary, for: .normal) callToActionButton.addTarget(self, action: #selector(requestCameraAccess), for: UIControl.Event.touchUpInside) + // Set up stack view let stackView = UIStackView(arrangedSubviews: [ explanationLabel, callToActionButton ]) stackView.axis = .vertical stackView.spacing = Values.mediumSpacing stackView.alignment = .center + // Set up constraints view.set(.width, to: UIScreen.main.bounds.width) view.addSubview(stackView) stackView.pin(.leading, to: .leading, of: view, withInset: Values.massiveSpacing) view.pin(.trailing, to: .trailing, of: stackView, withInset: Values.massiveSpacing) + let verticalCenteringConstraint = stackView.center(.vertical, in: view) verticalCenteringConstraint.constant = -16 // Makes things appear centered visually } diff --git a/Session/Home/GlobalSearch/EmptySearchResultCell.swift b/Session/Home/GlobalSearch/EmptySearchResultCell.swift index 4afac6994..23097b2c6 100644 --- a/Session/Home/GlobalSearch/EmptySearchResultCell.swift +++ b/Session/Home/GlobalSearch/EmptySearchResultCell.swift @@ -17,11 +17,22 @@ class EmptySearchResultCell: UITableViewCell { return result }() - private lazy var spinner: NVActivityIndicatorView = { - let result = NVActivityIndicatorView(frame: CGRect.zero, type: .circleStrokeSpin, color: Colors.text, padding: nil) + private let spinner: NVActivityIndicatorView = { + let result: NVActivityIndicatorView = NVActivityIndicatorView( + frame: CGRect.zero, + type: .circleStrokeSpin, + color: .black, + padding: nil + ) result.set(.width, to: 40) result.set(.height, to: 40) + ThemeManager.onThemeChange(observer: result) { [weak result] theme, _ in + guard let textPrimary: UIColor = theme.colors[.textPrimary] else { return } + + result?.color = textPrimary + } + return result }() diff --git a/Session/Home/GlobalSearch/GlobalSearchViewController.swift b/Session/Home/GlobalSearch/GlobalSearchViewController.swift index 992aca2ce..f71187288 100644 --- a/Session/Home/GlobalSearch/GlobalSearchViewController.swift +++ b/Session/Home/GlobalSearch/GlobalSearchViewController.swift @@ -59,6 +59,7 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo internal lazy var tableView: UITableView = { let result: UITableView = UITableView(frame: .zero, style: .grouped) + result.themeBackgroundColor = .clear result.rowHeight = UITableView.automaticDimension result.estimatedRowHeight = 60 result.separatorStyle = .none diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index 253701eac..3a39ac464 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -73,7 +73,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve private lazy var tableView: UITableView = { let result = UITableView() result.separatorStyle = .none - result.backgroundColor = .clear + result.themeBackgroundColor = .clear result.contentInset = UIEdgeInsets( top: 0, left: 0, diff --git a/Session/Meta/Translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings index b9f6583e3..82682c427 100644 --- a/Session/Meta/Translations/de.lproj/Localizable.strings +++ b/Session/Meta/Translations/de.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index 65a9d4f97..f98719890 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings index f9c6b0577..63ba8d002 100644 --- a/Session/Meta/Translations/es.lproj/Localizable.strings +++ b/Session/Meta/Translations/es.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings index 21ec8c2de..3cdf7839d 100644 --- a/Session/Meta/Translations/fa.lproj/Localizable.strings +++ b/Session/Meta/Translations/fa.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/fi.lproj/Localizable.strings b/Session/Meta/Translations/fi.lproj/Localizable.strings index cae5e433c..0981de09d 100644 --- a/Session/Meta/Translations/fi.lproj/Localizable.strings +++ b/Session/Meta/Translations/fi.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings index dfdfa8a5c..8548d55a1 100644 --- a/Session/Meta/Translations/fr.lproj/Localizable.strings +++ b/Session/Meta/Translations/fr.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/hi.lproj/Localizable.strings b/Session/Meta/Translations/hi.lproj/Localizable.strings index e9da8e268..a0e33c8da 100644 --- a/Session/Meta/Translations/hi.lproj/Localizable.strings +++ b/Session/Meta/Translations/hi.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/hr.lproj/Localizable.strings b/Session/Meta/Translations/hr.lproj/Localizable.strings index a35f6405e..51d94a828 100644 --- a/Session/Meta/Translations/hr.lproj/Localizable.strings +++ b/Session/Meta/Translations/hr.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings index 8b03a2d01..dce5e4ce1 100644 --- a/Session/Meta/Translations/id-ID.lproj/Localizable.strings +++ b/Session/Meta/Translations/id-ID.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings index 127932a90..c2d69d79c 100644 --- a/Session/Meta/Translations/it.lproj/Localizable.strings +++ b/Session/Meta/Translations/it.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings index 41c67b9b0..cd57cf0e8 100644 --- a/Session/Meta/Translations/ja.lproj/Localizable.strings +++ b/Session/Meta/Translations/ja.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/nl.lproj/Localizable.strings b/Session/Meta/Translations/nl.lproj/Localizable.strings index 8c0590d9e..f2b2c2934 100644 --- a/Session/Meta/Translations/nl.lproj/Localizable.strings +++ b/Session/Meta/Translations/nl.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings index 430babaad..761ed611b 100644 --- a/Session/Meta/Translations/pl.lproj/Localizable.strings +++ b/Session/Meta/Translations/pl.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings index a27f93a0f..43ff27e71 100644 --- a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings +++ b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings index ba72fb614..2319faa9b 100644 --- a/Session/Meta/Translations/ru.lproj/Localizable.strings +++ b/Session/Meta/Translations/ru.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/si.lproj/Localizable.strings b/Session/Meta/Translations/si.lproj/Localizable.strings index 38907b476..74ba28c5d 100644 --- a/Session/Meta/Translations/si.lproj/Localizable.strings +++ b/Session/Meta/Translations/si.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/sk.lproj/Localizable.strings b/Session/Meta/Translations/sk.lproj/Localizable.strings index 735e9b319..48542b715 100644 --- a/Session/Meta/Translations/sk.lproj/Localizable.strings +++ b/Session/Meta/Translations/sk.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/sv.lproj/Localizable.strings b/Session/Meta/Translations/sv.lproj/Localizable.strings index 063c1f903..9b9a5d0bf 100644 --- a/Session/Meta/Translations/sv.lproj/Localizable.strings +++ b/Session/Meta/Translations/sv.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/th.lproj/Localizable.strings b/Session/Meta/Translations/th.lproj/Localizable.strings index 101948b47..f2ef7fe84 100644 --- a/Session/Meta/Translations/th.lproj/Localizable.strings +++ b/Session/Meta/Translations/th.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings index 0225096db..7c48d62ba 100644 --- a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings +++ b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings index 6dc2845d2..40eb20452 100644 --- a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings index 1f4f33435..1ed375c64 100644 --- a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings @@ -702,10 +702,10 @@ "PRIVACY_SCREEN_SECURITY_SCREENSHOT_NOTIFICATIONS_DESCRIPTION" = "Receive a notification when a contact takes a screenshot of a one-to-one chat."; "PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts"; "PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts"; -"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one chats."; +"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "See and share read receipts in one-to-one conversations."; "PRIVACY_SECTION_TYPING_INDICATORS" = "Typing Indicators"; "PRIVACY_TYPING_INDICATORS_TITLE" = "Typing Indicators"; -"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one chats."; +"PRIVACY_TYPING_INDICATORS_DESCRIPTION" = "See and share typing indicators in one-to-one conversations."; "PRIVACY_SECTION_LINK_PREVIEWS" = "Link Previews"; "PRIVACY_LINK_PREVIEWS_TITLE" = "Send Link Previews"; "PRIVACY_LINK_PREVIEWS_DESCRIPTION" = "Generate link previews for supported URLs."; diff --git a/Session/Open Groups/JoinOpenGroupVC.swift b/Session/Open Groups/JoinOpenGroupVC.swift index 7b3479ed9..0257c7c63 100644 --- a/Session/Open Groups/JoinOpenGroupVC.swift +++ b/Session/Open Groups/JoinOpenGroupVC.swift @@ -60,7 +60,7 @@ final class JoinOpenGroupVC: BaseVC, UIPageViewControllerDataSource, UIPageViewC // Navigation bar buttons let navBarHeight: CGFloat = (navigationController?.navigationBar.frame.size.height ?? 0) let closeButton = UIBarButtonItem(image: #imageLiteral(resourceName: "X"), style: .plain, target: self, action: #selector(close)) - closeButton.tintColor = Colors.text + closeButton.themeTintColor = .textPrimary navigationItem.leftBarButtonItem = closeButton // Page VC @@ -190,13 +190,20 @@ final class JoinOpenGroupVC: BaseVC, UIPageViewControllerDataSource, UIPageViewC // MARK: - Convenience private func showError(title: String, message: String = "") { - let alert: UIAlertController = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil)) - - presentAlert(alert) + let confirmationModal: ConfirmationModal = ConfirmationModal( + info: ConfirmationModal.Info( + title: title, + explanation: message, + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .textPrimary + ) + ) + self.navigationController?.present(confirmationModal, animated: true, completion: nil) } } +// MARK: - EnterURLVC + private final class EnterURLVC: UIViewController, UIGestureRecognizerDelegate, OpenGroupSuggestionGridDelegate { weak var joinOpenGroupVC: JoinOpenGroupVC? @@ -220,7 +227,7 @@ private final class EnterURLVC: UIViewController, UIGestureRecognizerDelegate, O result.setContentHuggingPriority(.required, for: .vertical) result.font = .boldSystemFont(ofSize: Values.largeFontSize) result.text = "vc_join_open_group_suggestions_title".localized() - result.textColor = Colors.text + result.themeTextColor = .textPrimary result.lineBreakMode = .byWordWrapping result.numberOfLines = 0 @@ -239,7 +246,7 @@ private final class EnterURLVC: UIViewController, UIGestureRecognizerDelegate, O override func viewDidLoad() { // Remove background color - view.backgroundColor = .clear + view.themeBackgroundColor = .clear // Next button let nextButton = OutlineButton(style: .regular, size: .large) @@ -374,23 +381,23 @@ private final class ScanQRCodePlaceholderVC: UIViewController { override func viewDidLoad() { // Remove background color - view.backgroundColor = .clear + view.themeBackgroundColor = .clear // Explanation label let explanationLabel = UILabel() - explanationLabel.textColor = Colors.text explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) - explanationLabel.text = NSLocalizedString("vc_scan_qr_code_camera_access_explanation", comment: "") - explanationLabel.numberOfLines = 0 + explanationLabel.text = "vc_scan_qr_code_camera_access_explanation".localized() + explanationLabel.themeTextColor = .textPrimary explanationLabel.textAlignment = .center explanationLabel.lineBreakMode = .byWordWrapping + explanationLabel.numberOfLines = 0 // Call to action button let callToActionButton = UIButton() - callToActionButton.titleLabel!.font = .boldSystemFont(ofSize: Values.mediumFontSize) - callToActionButton.setTitleColor(Colors.accent, for: UIControl.State.normal) - callToActionButton.setTitle(NSLocalizedString("vc_scan_qr_code_grant_camera_access_button_title", comment: ""), for: UIControl.State.normal) - callToActionButton.addTarget(self, action: #selector(requestCameraAccess), for: UIControl.Event.touchUpInside) + callToActionButton.titleLabel?.font = .boldSystemFont(ofSize: Values.mediumFontSize) + callToActionButton.setTitle("vc_scan_qr_code_grant_camera_access_button_title".localized(), for: .normal) + callToActionButton.setThemeTitleColor(.primary, for: .normal) + callToActionButton.addTarget(self, action: #selector(requestCameraAccess), for: .touchUpInside) // Stack view let stackView = UIStackView(arrangedSubviews: [ explanationLabel, callToActionButton ]) diff --git a/Session/Open Groups/OpenGroupSuggestionGrid.swift b/Session/Open Groups/OpenGroupSuggestionGrid.swift index ee9e83ed7..466e9305b 100644 --- a/Session/Open Groups/OpenGroupSuggestionGrid.swift +++ b/Session/Open Groups/OpenGroupSuggestionGrid.swift @@ -7,34 +7,50 @@ final class OpenGroupSuggestionGrid: UIView, UICollectionViewDataSource, UIColle private let maxWidth: CGFloat private var rooms: [OpenGroupAPI.Room] = [] { didSet { update() } } private var heightConstraint: NSLayoutConstraint! + var delegate: OpenGroupSuggestionGridDelegate? // MARK: - UI private static let cellHeight: CGFloat = 40 - private static let separatorWidth = 1 / UIScreen.main.scale + private static let separatorWidth = Values.separatorThickness + private static let numHorizontalCells: CGFloat = (UIDevice.current.isIPad ? 4 : 2) - private lazy var layout: UICollectionViewFlowLayout = { - let result = UICollectionViewFlowLayout() - result.minimumLineSpacing = 0 - result.minimumInteritemSpacing = 0 + private lazy var layout: LastRowCenteredLayout = { + let result = LastRowCenteredLayout() + result.minimumLineSpacing = Values.mediumSpacing + result.minimumInteritemSpacing = Values.mediumSpacing + return result }() private lazy var collectionView: UICollectionView = { - let result = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout) - result.register(Cell.self, forCellWithReuseIdentifier: Cell.identifier) - result.backgroundColor = .clear + let result = UICollectionView(frame: .zero, collectionViewLayout: layout) + result.themeBackgroundColor = .clear result.isScrollEnabled = false + result.register(view: Cell.self) result.dataSource = self result.delegate = self + return result }() - private lazy var spinner: NVActivityIndicatorView = { - let result = NVActivityIndicatorView(frame: CGRect.zero, type: .circleStrokeSpin, color: Colors.text, padding: nil) + private let spinner: NVActivityIndicatorView = { + let result: NVActivityIndicatorView = NVActivityIndicatorView( + frame: CGRect.zero, + type: .circleStrokeSpin, + color: .black, + padding: nil + ) result.set(.width, to: OpenGroupSuggestionGrid.cellHeight) result.set(.height, to: OpenGroupSuggestionGrid.cellHeight) + + ThemeManager.onThemeChange(observer: result) { [weak result] theme, _ in + guard let textPrimary: UIColor = theme.colors[.textPrimary] else { return } + + result?.color = textPrimary + } + return result }() @@ -47,16 +63,16 @@ final class OpenGroupSuggestionGrid: UIView, UICollectionViewDataSource, UIColle private lazy var errorImageView: UIImageView = { let result: UIImageView = UIImageView(image: #imageLiteral(resourceName: "warning").withRenderingMode(.alwaysTemplate)) - result.tintColor = Colors.destructive + result.themeTintColor = .danger return result }() private lazy var errorTitleLabel: UILabel = { let result: UILabel = UILabel() - result.font = UIFont.systemFont(ofSize: Values.mediumFontSize, weight: .medium) + result.font = .systemFont(ofSize: Values.mediumFontSize, weight: .medium) result.text = "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE".localized() - result.textColor = Colors.text + result.themeTextColor = .textPrimary result.textAlignment = .center result.numberOfLines = 0 @@ -65,9 +81,9 @@ final class OpenGroupSuggestionGrid: UIView, UICollectionViewDataSource, UIColle private lazy var errorSubtitleLabel: UILabel = { let result: UILabel = UILabel() - result.font = UIFont.systemFont(ofSize: Values.smallFontSize, weight: .medium) + result.font = .systemFont(ofSize: Values.smallFontSize, weight: .medium) result.text = "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE".localized() - result.textColor = Colors.text + result.themeTextColor = .textPrimary result.textAlignment = .center result.numberOfLines = 0 @@ -78,7 +94,9 @@ final class OpenGroupSuggestionGrid: UIView, UICollectionViewDataSource, UIColle init(maxWidth: CGFloat) { self.maxWidth = maxWidth + super.init(frame: CGRect.zero) + initialize() } @@ -134,8 +152,10 @@ final class OpenGroupSuggestionGrid: UIView, UICollectionViewDataSource, UIColle private func update() { spinner.stopAnimating() spinner.isHidden = true - let roomCount = min(rooms.count, 8) // Cap to a maximum of 8 (4 rows of 2) - let height = OpenGroupSuggestionGrid.cellHeight * ceil(CGFloat(roomCount) / 2) + + let roomCount: CGFloat = CGFloat(min(rooms.count, 8)) // Cap to a maximum of 8 (4 rows of 2) + let numRows: CGFloat = ceil(roomCount / OpenGroupSuggestionGrid.numHorizontalCells) + let height: CGFloat = ((OpenGroupSuggestionGrid.cellHeight * numRows) + ((numRows - 1) * layout.minimumLineSpacing)) heightConstraint.constant = height collectionView.reloadData() errorView.isHidden = (roomCount > 0) @@ -144,8 +164,20 @@ final class OpenGroupSuggestionGrid: UIView, UICollectionViewDataSource, UIColle // MARK: - Layout func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - let cellWidth = UIDevice.current.isIPad ? maxWidth / 4 : maxWidth / 2 - return CGSize(width: cellWidth, height: OpenGroupSuggestionGrid.cellHeight) + guard + indexPath.item == (collectionView.numberOfItems(inSection: indexPath.section) - 1) && + indexPath.item % 2 == 0 + else { + let cellWidth: CGFloat = ((maxWidth / OpenGroupSuggestionGrid.numHorizontalCells) - ((OpenGroupSuggestionGrid.numHorizontalCells - 1) * layout.minimumInteritemSpacing)) + + return CGSize(width: cellWidth, height: OpenGroupSuggestionGrid.cellHeight) + } + + // If the last item is by itself then we want to make it wider + return CGSize( + width: (Cell.calculatedWith(for: rooms[indexPath.item].name)), + height: OpenGroupSuggestionGrid.cellHeight + ) } // MARK: - Data Source @@ -155,8 +187,9 @@ final class OpenGroupSuggestionGrid: UIView, UICollectionViewDataSource, UIColle } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Cell.identifier, for: indexPath) as! Cell + let cell: Cell = collectionView.dequeue(type: Cell.self, for: indexPath) cell.room = rooms[indexPath.item] + return cell } @@ -171,72 +204,95 @@ final class OpenGroupSuggestionGrid: UIView, UICollectionViewDataSource, UIColle // MARK: - Cell extension OpenGroupSuggestionGrid { - - fileprivate final class Cell : UICollectionViewCell { + fileprivate final class Cell: UICollectionViewCell { + private static let labelFont: UIFont = .systemFont(ofSize: Values.smallFontSize) + private static let imageSize: CGFloat = 30 + private static let itemPadding: CGFloat = Values.smallSpacing + private static let contentLeftPadding: CGFloat = 7 + private static let contentRightPadding: CGFloat = Values.veryLargeSpacing + + fileprivate static func calculatedWith(for title: String) -> CGFloat { + // FIXME: Do the calculations properly in the 'LastRowCenteredLayout' to handle imageless cells + return ( + contentLeftPadding + + imageSize + + itemPadding + + NSAttributedString(string: title, attributes: [ .font: labelFont ]).size().width + + contentRightPadding + ) + } + var room: OpenGroupAPI.Room? { didSet { update() } } - static let identifier = "OpenGroupSuggestionGridCell" - private lazy var snContentView: UIView = { - let result = UIView() - result.backgroundColor = Colors.navigationBarBackground - result.set(.height, to: Cell.contentViewHeight) + let result: UIView = UIView() + result.themeBorderColor = .borderSeparator result.layer.cornerRadius = Cell.contentViewCornerRadius + result.layer.borderWidth = 1 + result.set(.height, to: Cell.contentViewHeight) + return result }() private lazy var imageView: UIImageView = { - let result = UIImageView() - let size: CGFloat = 24 - result.set(.width, to: size) - result.set(.height, to: size) - result.layer.cornerRadius = size / 2 + let result: UIImageView = UIImageView() + result.set(.width, to: Cell.imageSize) + result.set(.height, to: Cell.imageSize) + result.layer.cornerRadius = (Cell.imageSize / 2) result.clipsToBounds = true + return result }() private lazy var label: UILabel = { - let result = UILabel() - result.textColor = Colors.text - result.font = .systemFont(ofSize: Values.smallFontSize) + let result: UILabel = UILabel() + result.font = Cell.labelFont + result.themeTextColor = .textPrimary result.lineBreakMode = .byTruncatingTail + return result }() - private static let contentViewInset: CGFloat = 4 + private static let contentViewInset: CGFloat = 0 private static var contentViewHeight: CGFloat { OpenGroupSuggestionGrid.cellHeight - 2 * contentViewInset } private static var contentViewCornerRadius: CGFloat { contentViewHeight / 2 } override init(frame: CGRect) { super.init(frame: frame) + setUpViewHierarchy() } required init?(coder: NSCoder) { super.init(coder: coder) + setUpViewHierarchy() } private func setUpViewHierarchy() { + themeBackgroundColor = .backgroundPrimary + + selectedBackgroundView = UIView() + selectedBackgroundView?.themeBackgroundColor = .backgroundSecondary + selectedBackgroundView?.layer.cornerRadius = Cell.contentViewCornerRadius + addSubview(snContentView) + let stackView = UIStackView(arrangedSubviews: [ imageView, label ]) stackView.axis = .horizontal - stackView.spacing = Values.smallSpacing + stackView.spacing = Cell.itemPadding snContentView.addSubview(stackView) + stackView.center(.vertical, in: snContentView) - stackView.pin(.leading, to: .leading, of: snContentView, withInset: 4) - snContentView.trailingAnchor.constraint(greaterThanOrEqualTo: stackView.trailingAnchor, constant: Values.smallSpacing).isActive = true - snContentView.pin(to: self, withInset: Cell.contentViewInset) - } - - override func layoutSubviews() { - super.layoutSubviews() - let newPath = UIBezierPath(roundedRect: snContentView.bounds, cornerRadius: Cell.contentViewCornerRadius).cgPath - snContentView.layer.shadowPath = newPath - snContentView.layer.shadowColor = UIColor.black.cgColor - snContentView.layer.shadowOffset = CGSize.zero - snContentView.layer.shadowOpacity = isLightMode ? 0.2 : 0.6 - snContentView.layer.shadowRadius = 2 + stackView.pin(.leading, to: .leading, of: snContentView, withInset: Cell.contentLeftPadding) + + snContentView.trailingAnchor + .constraint( + greaterThanOrEqualTo: stackView.trailingAnchor, + constant: Cell.contentRightPadding + ) + .isActive = true + snContentView.pin(to: self) } private func update() { @@ -277,3 +333,26 @@ extension OpenGroupSuggestionGrid { protocol OpenGroupSuggestionGridDelegate { func join(_ room: OpenGroupAPI.Room) } + +// MARK: - LastRowCenteredLayout + +class LastRowCenteredLayout: UICollectionViewFlowLayout { + override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + // If we have an odd number of items then we want to center the last one horizontally + let elementAttributes: [UICollectionViewLayoutAttributes]? = super.layoutAttributesForElements(in: rect) + + guard + (elementAttributes?.count ?? 0) % 2 == 1, + let lastItemAttributes: UICollectionViewLayoutAttributes = elementAttributes?.last + else { return elementAttributes } + + lastItemAttributes.frame = CGRect( + x: ((rect.width - lastItemAttributes.frame.size.width) / 2), + y: lastItemAttributes.frame.origin.y, + width: lastItemAttributes.frame.size.width, + height: lastItemAttributes.frame.size.height + ) + + return elementAttributes + } +} diff --git a/Session/Path/PathVC.swift b/Session/Path/PathVC.swift index e2fd13de0..c1c0c7367 100644 --- a/Session/Path/PathVC.swift +++ b/Session/Path/PathVC.swift @@ -19,11 +19,22 @@ final class PathVC: BaseVC { return result }() - private lazy var spinner: NVActivityIndicatorView = { - let result = NVActivityIndicatorView(frame: CGRect.zero, type: .circleStrokeSpin, color: Colors.text, padding: nil) + private let spinner: NVActivityIndicatorView = { + let result: NVActivityIndicatorView = NVActivityIndicatorView( + frame: CGRect.zero, + type: .circleStrokeSpin, + color: .black, + padding: nil + ) result.set(.width, to: 64) result.set(.height, to: 64) + ThemeManager.onThemeChange(observer: result) { [weak result] theme, _ in + guard let textPrimary: UIColor = theme.colors[.textPrimary] else { return } + + result?.color = textPrimary + } + return result }() diff --git a/Session/Settings/PrivacySettingsViewModel.swift b/Session/Settings/PrivacySettingsViewModel.swift index 7d30831b2..f9b8af3a4 100644 --- a/Session/Settings/PrivacySettingsViewModel.swift +++ b/Session/Settings/PrivacySettingsViewModel.swift @@ -143,6 +143,7 @@ class PrivacySettingsViewModel: SettingsTableViewModel ()) { + init(info: Info, onConfirm: ((UIViewController) -> ())? = nil) { self.onConfirm = { viewController in - onConfirm(viewController) + onConfirm?(viewController) info.onConfirm?() } @@ -157,6 +157,7 @@ public class ConfirmationModal: Modal { explanationLabel.isHidden = (info.explanation == nil) confirmButton.setTitle(info.confirmTitle, for: .normal) confirmButton.setThemeTitleColor(info.confirmStyle, for: .normal) + confirmButton.isHidden = (info.confirmTitle == nil) cancelButton.setTitle(info.cancelTitle, for: .normal) cancelButton.setThemeTitleColor(info.cancelStyle, for: .normal) } diff --git a/SessionUIKit/Components/Separator.swift b/SessionUIKit/Components/Separator.swift index 51abcdc13..3527cde89 100644 --- a/SessionUIKit/Components/Separator.swift +++ b/SessionUIKit/Components/Separator.swift @@ -10,9 +10,8 @@ public final class Separator: UIView { private lazy var titleLabel: UILabel = { let result = UILabel() result.font = .systemFont(ofSize: Values.smallFontSize) - result.themeTextColor = .textPrimary + result.themeTextColor = .textSecondary result.textAlignment = .center - result.alpha = Values.mediumOpacity return result }() @@ -20,7 +19,7 @@ public final class Separator: UIView { private lazy var lineLayer: CAShapeLayer = { let result = CAShapeLayer() result.lineWidth = Values.separatorThickness - result.themeStrokeColor = .borderSeparator + result.themeStrokeColor = .textSecondary result.themeFillColor = .clear return result diff --git a/SessionUIKit/Components/TextField.swift b/SessionUIKit/Components/TextField.swift index f8eb37270..ef02824f7 100644 --- a/SessionUIKit/Components/TextField.swift +++ b/SessionUIKit/Components/TextField.swift @@ -1,7 +1,9 @@ +// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. + import UIKit @objc(SNTextField) -public final class TextField : UITextField { +public final class TextField: UITextField { private let usesDefaultHeight: Bool private let height: CGFloat private let horizontalInset: CGFloat @@ -20,8 +22,11 @@ public final class TextField : UITextField { self.height = customHeight ?? TextField.height self.horizontalInset = customHorizontalInset ?? (isIPhone5OrSmaller ? Values.mediumSpacing : Values.largeSpacing) self.verticalInset = customVerticalInset ?? (isIPhone5OrSmaller ? Values.smallSpacing : Values.largeSpacing) + super.init(frame: CGRect.zero) + self.placeholder = placeholder + setUpStyle() } @@ -34,26 +39,37 @@ public final class TextField : UITextField { } private func setUpStyle() { - textColor = Colors.text font = .systemFont(ofSize: Values.smallFontSize) - let placeholder = NSMutableAttributedString(string: self.placeholder!) - let placeholderColor = Colors.text.withAlphaComponent(Values.mediumOpacity) - placeholder.addAttribute(.foregroundColor, value: placeholderColor, range: NSRange(location: 0, length: placeholder.length)) - attributedPlaceholder = placeholder - tintColor = Colors.accent - keyboardAppearance = isLightMode ? .light : .dark + themeTextColor = .textPrimary + themeTintColor = .primary + themeBorderColor = .borderSeparator + layer.borderWidth = 1 + layer.cornerRadius = TextField.cornerRadius + if usesDefaultHeight { set(.height, to: height) } - layer.borderColor = isLightMode ? Colors.text.cgColor : Colors.border.withAlphaComponent(Values.lowOpacity).cgColor - layer.borderWidth = 1 - layer.cornerRadius = TextField.cornerRadius + + ThemeManager.onThemeChange(observer: self) { [weak self] theme, _ in + switch theme.interfaceStyle { + case .light: self?.keyboardAppearance = .light + default: self?.keyboardAppearance = .dark + } + + if let textSecondary: UIColor = theme.colors[.textSecondary], let placeholder: String = self?.placeholder { + self?.attributedPlaceholder = NSAttributedString( + string: placeholder, + attributes: [ .foregroundColor: textSecondary] + ) + } + } } public override func textRect(forBounds bounds: CGRect) -> CGRect { if usesDefaultHeight { return bounds.insetBy(dx: horizontalInset, dy: verticalInset) - } else { + } + else { return bounds.insetBy(dx: Values.mediumSpacing, dy: Values.smallSpacing) } } @@ -61,7 +77,8 @@ public final class TextField : UITextField { public override func editingRect(forBounds bounds: CGRect) -> CGRect { if usesDefaultHeight { return bounds.insetBy(dx: horizontalInset, dy: verticalInset) - } else { + } + else { return bounds.insetBy(dx: Values.mediumSpacing, dy: Values.smallSpacing) } } diff --git a/SessionUIKit/Components/TextView.swift b/SessionUIKit/Components/TextView.swift index 45e063931..e6a69ad71 100644 --- a/SessionUIKit/Components/TextView.swift +++ b/SessionUIKit/Components/TextView.swift @@ -12,18 +12,27 @@ public final class TextView : UITextView, UITextViewDelegate { private lazy var placeholderLabel: UILabel = { let result = UILabel() result.font = .systemFont(ofSize: Values.smallFontSize) - result.textColor = Colors.text.withAlphaComponent(Values.mediumOpacity) + result.themeTextColor = .textSecondary + return result }() - public init(placeholder: String, usesDefaultHeight: Bool = true, customHeight: CGFloat? = nil, customHorizontalInset: CGFloat? = nil, customVerticalInset: CGFloat? = nil) { + public init( + placeholder: String, + usesDefaultHeight: Bool = true, + customHeight: CGFloat? = nil, + customHorizontalInset: CGFloat? = nil, + customVerticalInset: CGFloat? = nil + ) { self.usesDefaultHeight = usesDefaultHeight self.height = customHeight ?? TextField.height self.horizontalInset = customHorizontalInset ?? (isIPhone5OrSmaller ? Values.mediumSpacing : Values.largeSpacing) self.verticalInset = customVerticalInset ?? (isIPhone5OrSmaller ? Values.smallSpacing : Values.largeSpacing) self.placeholder = placeholder + super.init(frame: CGRect.zero, textContainer: nil) self.delegate = self + setUpStyle() } @@ -38,18 +47,21 @@ public final class TextView : UITextView, UITextViewDelegate { private func setUpStyle() { showsHorizontalScrollIndicator = false showsVerticalScrollIndicator = false - placeholderLabel.text = placeholder - backgroundColor = .clear - textColor = Colors.text + font = .systemFont(ofSize: Values.smallFontSize) - tintColor = Colors.accent - keyboardAppearance = isLightMode ? .light : .dark + themeBackgroundColor = .clear + themeTextColor = .textPrimary + themeTintColor = .primary + themeBorderColor = .borderSeparator + layer.borderWidth = 1 + layer.cornerRadius = TextField.cornerRadius + + placeholderLabel.text = placeholder + if usesDefaultHeight { set(.height, to: height) } - layer.borderColor = isLightMode ? Colors.text.cgColor : Colors.border.withAlphaComponent(Values.lowOpacity).cgColor - layer.borderWidth = 1 - layer.cornerRadius = TextField.cornerRadius + let horizontalInset = usesDefaultHeight ? self.horizontalInset : Values.mediumSpacing textContainerInset = UIEdgeInsets(top: 0, left: horizontalInset, bottom: 0, right: horizontalInset) addSubview(placeholderLabel) @@ -57,6 +69,13 @@ public final class TextView : UITextView, UITextViewDelegate { placeholderLabel.pin(.top, to: .top, of: self) pin(.trailing, to: .trailing, of: placeholderLabel, withInset: horizontalInset) pin(.bottom, to: .bottom, of: placeholderLabel) + + ThemeManager.onThemeChange(observer: self) { [weak self] theme, _ in + switch theme.interfaceStyle { + case .light: self?.keyboardAppearance = .light + default: self?.keyboardAppearance = .dark + } + } } public func textViewDidChange(_ textView: UITextView) { diff --git a/SessionUIKit/Style Guide/Values.swift b/SessionUIKit/Style Guide/Values.swift index 5e14957ae..d6b401ca3 100644 --- a/SessionUIKit/Style Guide/Values.swift +++ b/SessionUIKit/Style Guide/Values.swift @@ -18,7 +18,7 @@ public final class Values : NSObject { @objc public static let massiveFontSize = CGFloat(50) // MARK: - Element Sizes - @objc public static let smallButtonHeight = isIPhone5OrSmaller ? CGFloat(24) : CGFloat(27) + @objc public static let smallButtonHeight = isIPhone5OrSmaller ? CGFloat(24) : CGFloat(28) @objc public static let mediumButtonHeight = isIPhone5OrSmaller ? CGFloat(30) : CGFloat(34) @objc public static let largeButtonHeight = isIPhone5OrSmaller ? CGFloat(40) : CGFloat(45) @objc public static let alertButtonHeight: CGFloat = 50 diff --git a/SignalUtilitiesKit/Media Viewing & Editing/MediaMessageView.swift b/SignalUtilitiesKit/Media Viewing & Editing/MediaMessageView.swift index 6391397c8..49d0bb07a 100644 --- a/SignalUtilitiesKit/Media Viewing & Editing/MediaMessageView.swift +++ b/SignalUtilitiesKit/Media Viewing & Editing/MediaMessageView.swift @@ -136,12 +136,23 @@ public class MediaMessageView: UIView, OWSAudioPlayerDelegate { return stackView }() - private lazy var loadingView: NVActivityIndicatorView = { - let view: NVActivityIndicatorView = NVActivityIndicatorView(frame: CGRect.zero, type: .circleStrokeSpin, color: Colors.text, padding: nil) - view.translatesAutoresizingMaskIntoConstraints = false - view.isHidden = true + private let loadingView: NVActivityIndicatorView = { + let result: NVActivityIndicatorView = NVActivityIndicatorView( + frame: CGRect.zero, + type: .circleStrokeSpin, + color: .black, + padding: nil + ) + result.translatesAutoresizingMaskIntoConstraints = false + result.isHidden = true - return view + ThemeManager.onThemeChange(observer: result) { [weak result] theme, _ in + guard let textPrimary: UIColor = theme.colors[.textPrimary] else { return } + + result?.color = textPrimary + } + + return result }() private lazy var imageView: UIImageView = { diff --git a/SignalUtilitiesKit/Shared View Controllers/ModalActivityIndicatorViewController.swift b/SignalUtilitiesKit/Shared View Controllers/ModalActivityIndicatorViewController.swift index 4f1c818b0..0fd4d985b 100644 --- a/SignalUtilitiesKit/Shared View Controllers/ModalActivityIndicatorViewController.swift +++ b/SignalUtilitiesKit/Shared View Controllers/ModalActivityIndicatorViewController.swift @@ -1,6 +1,4 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// +// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import Foundation import MediaPlayer @@ -9,25 +7,49 @@ import NVActivityIndicatorView // A modal view that be used during blocking interactions (e.g. waiting on response from // service or on the completion of a long-running local operation). -@objc public class ModalActivityIndicatorViewController: OWSViewController { let canCancel: Bool - let message: String? - @objc public var wasCancelled: Bool = false + lazy var dimmingView: UIView = { + let result = UIVisualEffectView() + + ThemeManager.onThemeChange(observer: result) { [weak result] theme, _ in + result?.effect = UIBlurEffect( + style: (theme.interfaceStyle == .light ? + UIBlurEffect.Style.systemUltraThinMaterialLight : + UIBlurEffect.Style.systemUltraThinMaterial + ) + ) + } + + return result + }() + private lazy var spinner: NVActivityIndicatorView = { - let result = NVActivityIndicatorView(frame: CGRect.zero, type: .circleStrokeSpin, color: .white, padding: nil) + let result: NVActivityIndicatorView = NVActivityIndicatorView( + frame: CGRect.zero, + type: .circleStrokeSpin, + color: .white, + padding: nil + ) result.set(.width, to: 64) result.set(.height, to: 64) + + ThemeManager.onThemeChange(observer: result) { [weak result] theme, _ in + guard let textPrimary: UIColor = theme.colors[.textPrimary] else { return } + + result?.color = textPrimary + } + return result }() var wasDimissed: Bool = false - // MARK: Initializers + // MARK: - Initializers @available(*, unavailable, message:"use other constructor instead.") public required init?(coder aDecoder: NSCoder) { @@ -40,7 +62,6 @@ public class ModalActivityIndicatorViewController: OWSViewController { super.init(nibName: nil, bundle: nil) } - @objc public class func present( fromViewController: UIViewController?, canCancel: Bool = false, @@ -52,9 +73,11 @@ public class ModalActivityIndicatorViewController: OWSViewController { AssertIsOnMainThread() let view = ModalActivityIndicatorViewController(canCancel: canCancel, message: message) + // Present this modal _over_ the current view contents. view.modalPresentationStyle = .overFullScreen view.modalTransitionStyle = .crossDissolve + fromViewController.present(view, animated: false) { DispatchQueue.global().async { backgroundBlock(view) @@ -62,7 +85,6 @@ public class ModalActivityIndicatorViewController: OWSViewController { } } - @objc public func dismiss(completion: @escaping () -> Void) { guard Thread.isMainThread else { DispatchQueue.main.async { [weak self] in @@ -75,7 +97,8 @@ public class ModalActivityIndicatorViewController: OWSViewController { // Only dismiss once. self.dismiss(animated: false, completion: completion) wasDimissed = true - } else { + } + else { // If already dismissed, wait a beat then call completion. DispatchQueue.main.async { completion() @@ -86,41 +109,48 @@ public class ModalActivityIndicatorViewController: OWSViewController { public override func loadView() { super.loadView() - self.view.backgroundColor = UIColor(white: 0, alpha: 0.6) - self.view.isOpaque = false + self.view.themeBackgroundColor = .clear + + self.view.addSubview(dimmingView) + dimmingView.pin(to: self.view) if let message = message { - let messageLabel = UILabel() - messageLabel.text = message + let messageLabel: UILabel = UILabel() messageLabel.font = .systemFont(ofSize: Values.mediumFontSize) - messageLabel.textColor = UIColor.white + messageLabel.text = message + messageLabel.themeTextColor = .textPrimary messageLabel.numberOfLines = 0 messageLabel.textAlignment = .center messageLabel.lineBreakMode = .byWordWrapping messageLabel.set(.width, to: UIScreen.main.bounds.width - 2 * Values.mediumSpacing) + let stackView = UIStackView(arrangedSubviews: [ messageLabel, spinner ]) stackView.axis = .vertical stackView.spacing = Values.largeSpacing stackView.alignment = .center self.view.addSubview(stackView) + stackView.center(in: self.view) - } else { + } + else { self.view.addSubview(spinner) spinner.autoCenterInSuperview() } if canCancel { - let cancelButton = UIButton(type: .custom) + let cancelButton: UIButton = UIButton(type: .custom) cancelButton.setTitle(CommonStrings.cancelButton, for: .normal) - cancelButton.setTitleColor(UIColor.white, for: .normal) + cancelButton.setThemeTitleColor(.textPrimary, for: .normal) cancelButton.backgroundColor = UIColor.ows_darkGray cancelButton.titleLabel?.font = UIFont.ows_mediumFont(withSize: ScaleFromIPhone5To7Plus(18, 22)) cancelButton.layer.cornerRadius = ScaleFromIPhone5To7Plus(4, 5) cancelButton.clipsToBounds = true cancelButton.addTarget(self, action: #selector(cancelPressed), for: .touchUpInside) + let buttonWidth = ScaleFromIPhone5To7Plus(140, 160) let buttonHeight = ScaleFromIPhone5To7Plus(40, 50) self.view.addSubview(cancelButton) + cancelButton.autoHCenterInSuperview() cancelButton.autoPinEdge(toSuperviewEdge: .bottom, withInset: 50) cancelButton.autoSetDimension(.width, toSize: buttonWidth) diff --git a/SignalUtilitiesKit/Utilities/UIView+Utilities.swift b/SignalUtilitiesKit/Utilities/UIView+Utilities.swift index 54cb888bc..374d12e29 100644 --- a/SignalUtilitiesKit/Utilities/UIView+Utilities.swift +++ b/SignalUtilitiesKit/Utilities/UIView+Utilities.swift @@ -1,30 +1,35 @@ +// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. + import SessionUIKit public extension UIView { - static func hSpacer(_ width: CGFloat) -> UIView { - let result = UIView() + let result: UIView = UIView() result.set(.width, to: width) + return result } static func vSpacer(_ height: CGFloat) -> UIView { - let result = UIView() + let result: UIView = UIView() result.set(.height, to: height) + return result } static func vhSpacer(_ width: CGFloat, _ height: CGFloat) -> UIView { - let result = UIView() + let result: UIView = UIView() result.set(.width, to: width) result.set(.height, to: height) + return result } static func separator() -> UIView { - let result = UIView() + let result: UIView = UIView() result.set(.height, to: Values.separatorThickness) result.themeBackgroundColor = .borderSeparator + return result } }