Resolve more errors

This commit is contained in:
Niels Andriesse 2021-08-05 14:40:52 +10:00
parent 90027c4a04
commit 657750415c
9 changed files with 720 additions and 11 deletions

View File

@ -279,6 +279,8 @@
B88FA7F2260C3EB10049422F /* OpenGroupSuggestionGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = B88FA7F1260C3EB10049422F /* OpenGroupSuggestionGrid.swift */; };
B88FA7FB26114EA70049422F /* Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = B88FA7FA26114EA70049422F /* Hex.swift */; };
B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */; };
B893550126BB9FB3008A7A3A /* ConversationSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B893550026BB9FB3008A7A3A /* ConversationSplitViewController.swift */; };
B893550326BBA26F008A7A3A /* CallKitIdStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B893550226BBA26F008A7A3A /* CallKitIdStore.swift */; };
B894D0752339EDCF00B4D94D /* NukeDataModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B894D0742339EDCF00B4D94D /* NukeDataModal.swift */; };
B897621C25D201F7004F83B2 /* ScrollToBottomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B897621B25D201F7004F83B2 /* ScrollToBottomButton.swift */; };
B8AE75A425A6C6A6001A84D2 /* Data+Trimming.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8AE75A325A6C6A6001A84D2 /* Data+Trimming.swift */; };
@ -1289,6 +1291,8 @@
B88FA7F1260C3EB10049422F /* OpenGroupSuggestionGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupSuggestionGrid.swift; sourceTree = "<group>"; };
B88FA7FA26114EA70049422F /* Hex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Hex.swift; sourceTree = "<group>"; };
B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanQRCodeWrapperVC.swift; sourceTree = "<group>"; };
B893550026BB9FB3008A7A3A /* ConversationSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSplitViewController.swift; sourceTree = "<group>"; };
B893550226BBA26F008A7A3A /* CallKitIdStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallKitIdStore.swift; sourceTree = "<group>"; };
B894D0742339EDCF00B4D94D /* NukeDataModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NukeDataModal.swift; sourceTree = "<group>"; };
B897621B25D201F7004F83B2 /* ScrollToBottomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollToBottomButton.swift; sourceTree = "<group>"; };
B8AE75A325A6C6A6001A84D2 /* Data+Trimming.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Trimming.swift"; sourceTree = "<group>"; };
@ -2233,6 +2237,7 @@
B82A0C1326B7B45200C1BCE3 /* CallControls.swift */,
B82A0C1426B7B45200C1BCE3 /* RemoteVideoView.h */,
B82A0C0F26B7B45200C1BCE3 /* RemoteVideoView.m */,
B893550026BB9FB3008A7A3A /* ConversationSplitViewController.swift */,
);
path = UserInterface;
sourceTree = "<group>";
@ -2277,6 +2282,7 @@
isa = PBXGroup;
children = (
B82A0C3326B7C0C900C1BCE3 /* TSAccountManager.swift */,
B893550226BBA26F008A7A3A /* CallKitIdStore.swift */,
);
path = Utilities;
sourceTree = "<group>";
@ -5066,6 +5072,7 @@
B82A0C2126B7B45200C1BCE3 /* GroupCallVideoGrid.swift in Sources */,
B8D84EA325DF745A005A043E /* LinkPreviewState.swift in Sources */,
45C0DC1E1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */,
B893550326BBA26F008A7A3A /* CallKitIdStore.swift in Sources */,
45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */,
B82B408E239DC00D00A248E7 /* DisplayNameVC.swift in Sources */,
B8214A2B25D63EB9009C0F2A /* MessagesTableView.swift in Sources */,
@ -5085,6 +5092,7 @@
34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */,
B8F5F71A25F1B35C003BF8D4 /* MediaPlaceholderView.swift in Sources */,
341341EF2187467A00192D59 /* ConversationViewModel.m in Sources */,
B893550126BB9FB3008A7A3A /* ConversationSplitViewController.swift in Sources */,
4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */,
B82A0C3426B7C0C900C1BCE3 /* TSAccountManager.swift in Sources */,
C331FFF32558FF0300070591 /* PathStatusView.swift in Sources */,

View File

@ -0,0 +1,671 @@
//
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
import Foundation
import MultipeerConnectivity
@objc
class ConversationSplitViewController : UIViewController {/*}: UISplitViewController, ConversationSplit {
fileprivate var deviceTransferNavController: DeviceTransferNavigationController?
private let conversationListVC = ConversationListViewController()
private let detailPlaceholderVC = NoSelectedConversationViewController()
private lazy var primaryNavController = OWSNavigationController(rootViewController: conversationListVC)
private lazy var detailNavController = OWSNavigationController()
private lazy var lastActiveInterfaceOrientation = CurrentAppContext().interfaceOrientation
@objc private(set) weak var selectedConversationViewController: ConversationViewController?
weak var navigationTransitionDelegate: UINavigationControllerDelegate?
/// The thread, if any, that is currently presented in the view hieararchy. It may be currently
/// covered by a modal presentation or a pushed view controller.
@objc var selectedThread: TSThread? {
// If the placeholder view is in the view hierarchy, there is no selected thread.
guard detailPlaceholderVC.view.superview == nil else { return nil }
guard let selectedConversationViewController = selectedConversationViewController else { return nil }
// In order to not show selected when collapsed during an interactive dismissal,
// we verify the conversation is still in the nav stack when collapsed. There is
// no interactive dismissal when expanded, so we don't have to do any special check.
guard !isCollapsed || primaryNavController.viewControllers.contains(selectedConversationViewController) else { return nil }
return selectedConversationViewController.thread
}
/// Returns the currently selected thread if it is visible on screen, otherwise
/// returns nil.
@objc var visibleThread: TSThread? {
guard view.window?.isKeyWindow == true else { return nil }
guard selectedConversationViewController?.isViewVisible == true else { return nil }
return selectedThread
}
@objc var topViewController: UIViewController? {
guard !isCollapsed else {
return primaryNavController.topViewController
}
return detailNavController.topViewController ?? primaryNavController.topViewController
}
@objc
init() {
super.init(nibName: nil, bundle: nil)
viewControllers = [primaryNavController, detailPlaceholderVC]
primaryNavController.delegate = self
delegate = self
preferredDisplayMode = .allVisible
NotificationCenter.default.addObserver(self, selector: #selector(applyTheme), name: .ThemeDidChange, object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(orientationDidChange),
name: UIDevice.orientationDidChangeNotification,
object: UIDevice.current
)
NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: .OWSApplicationDidBecomeActive, object: nil)
applyTheme()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return Theme.isDarkThemeEnabled ? .lightContent : .default
}
@objc func applyTheme() {
view.backgroundColor = Theme.secondaryBackgroundColor
applyNavBarStyle(collapsed: isCollapsed)
}
@objc func orientationDidChange() {
AssertIsOnMainThread()
guard UIApplication.shared.applicationState == .active else { return }
lastActiveInterfaceOrientation = CurrentAppContext().interfaceOrientation
}
@objc func didBecomeActive() {
AssertIsOnMainThread()
lastActiveInterfaceOrientation = CurrentAppContext().interfaceOrientation
}
func applyNavBarStyle(collapsed: Bool) {
guard let owsNavBar = primaryNavController.navigationBar as? OWSNavigationBar else {
return owsFailDebug("unexpected nav bar")
}
owsNavBar.switchToStyle(collapsed ? .default : .secondaryBar)
}
private var hasHiddenExtraSubivew = false
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
// We don't want to hide anything on iOS 13, as the extra subview no longer exists
if #available(iOS 13, *) { hasHiddenExtraSubivew = true }
// HACK: UISplitViewController adds an extra subview behind the navigation
// bar area that extends across both views. As far as I can tell, it's not
// possible to adjust the color of this view. It gets reset constantly.
// Without this fix, the space between the primary and detail view has a
// hairline of the wrong color, most apparent in dark mode.
guard !hasHiddenExtraSubivew, let firstSubview = view.subviews.first,
!viewControllers.map({ $0.view }).contains(firstSubview) else { return }
hasHiddenExtraSubivew = true
firstSubview.isHidden = true
}
@objc(closeSelectedConversationAnimated:)
func closeSelectedConversation(animated: Bool) {
guard let selectedConversationViewController = selectedConversationViewController else { return }
if isCollapsed {
// If we're currently displaying the conversation in the primary nav controller, remove it
// and everything it pushed to the navigation stack from the nav controller. We don't want
// to just pop to root as we might have opened this conversation from the archive.
if let selectedConversationIndex = primaryNavController.viewControllers.firstIndex(of: selectedConversationViewController) {
let targetViewController = primaryNavController.viewControllers[max(0, selectedConversationIndex-1)]
primaryNavController.popToViewController(targetViewController, animated: animated)
}
} else {
viewControllers[1] = detailPlaceholderVC
}
}
@objc
func presentThread(_ thread: TSThread, action: ConversationViewAction, focusMessageId: String?, animated: Bool) {
AssertIsOnMainThread()
// On iOS 13, there is a bug with UISplitViewController that causes the `isCollapsed` state to
// get out of sync while the app isn't active and the orientation has changed while backgrounded.
// This results in conversations opening up in the wrong pane when you were in portrait and then
// try and open the app in landscape. We work around this by dispatching to the next runloop
// at which point things have stabilized.
if #available(iOS 13, *), UIApplication.shared.applicationState != .active, lastActiveInterfaceOrientation != CurrentAppContext().interfaceOrientation {
if #available(iOS 14, *) { owsFailDebug("check if this still happens") }
// Reset this to avoid getting stuck in a loop. We're becoming active.
lastActiveInterfaceOrientation = CurrentAppContext().interfaceOrientation
DispatchQueue.main.async { self.presentThread(thread, action: action, focusMessageId: focusMessageId, animated: animated) }
return
}
guard selectedThread?.uniqueId != thread.uniqueId else {
// If this thread is already selected, pop to the thread if
// anything else has been presented above the view.
guard let selectedConversationVC = selectedConversationViewController else { return }
if isCollapsed {
primaryNavController.popToViewController(selectedConversationVC, animated: animated)
} else {
detailNavController.popToViewController(selectedConversationVC, animated: animated)
}
return
}
// Update the last viewed thread on the conversation list so it
// can maintain its scroll position when navigating back.
conversationListVC.lastViewedThread = thread
let threadViewModel = databaseStorage.read {
return ThreadViewModel(thread: thread,
forConversationList: false,
transaction: $0)
}
let vc = ConversationViewController(threadViewModel: threadViewModel, action: action, focusMessageId: focusMessageId)
selectedConversationViewController = vc
let detailVC: UIViewController = {
guard !isCollapsed else { return vc }
detailNavController.viewControllers = [vc]
return detailNavController
}()
if animated {
showDetailViewController(detailVC, sender: self)
} else {
UIView.performWithoutAnimation { showDetailViewController(detailVC, sender: self) }
}
}
override var shouldAutorotate: Bool {
if let presentedViewController = presentedViewController {
return presentedViewController.shouldAutorotate
} else if let selectedConversationViewController = selectedConversationViewController {
return selectedConversationViewController.shouldAutorotate
} else {
return super.shouldAutorotate
}
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if let presentedViewController = presentedViewController {
return presentedViewController.supportedInterfaceOrientations
} else {
return super.supportedInterfaceOrientations
}
}
// The stock implementation of `showDetailViewController` will in some cases,
// particularly when launching a conversation from another window, fail to
// recognize the right context to present the view controller. When this happens,
// it presents the view modally instead of within the split view controller.
// We never want this to happen, so we implement a version that knows the
// correct context is always the split view controller.
private weak var currentDetailViewController: UIViewController?
override func showDetailViewController(_ vc: UIViewController, sender: Any?) {
if isCollapsed {
var viewControllersToDisplay = primaryNavController.viewControllers
// If we already have a detail VC displayed, we want to replace it.
// The normal behavior of `showDetailViewController` pushes on
// top of it in collapsed mode.
if let currentDetailVC = currentDetailViewController,
let detailVCIndex = viewControllersToDisplay.firstIndex(of: currentDetailVC) {
viewControllersToDisplay = Array(viewControllersToDisplay[0..<detailVCIndex])
}
viewControllersToDisplay.append(vc)
primaryNavController.setViewControllers(viewControllersToDisplay, animated: true)
} else {
// There is a race condition at app launch where `isCollapsed` cannot be
// relied upon. This leads to a crash where viewControllers is empty, so
// setting index 1 is not possible. We know what the primary view controller
// should always be, so we attempt to fill it in when that happens. The only
// ways this could really be happening is if, somehow, before `viewControllers`
// is set in init this method is getting called OR this `viewControllers` is
// returning stale information. The latter seems most plausible, but is near
// impossible to reproduce.
owsAssertDebug(viewControllers.first == primaryNavController)
viewControllers = [primaryNavController, vc]
}
// If the detail VC is a nav controller, we want to keep track of
// the root view controller. We use this to determine the start
// point of the current detail view when replacing it while
// collapsed. At that point, this nav controller's view controllers
// will have been merged into the primary nav controller.
if let vc = vc as? UINavigationController {
currentDetailViewController = vc.viewControllers.first
} else {
currentDetailViewController = vc
}
}
// MARK: - Keyboard Shortcuts
override var canBecomeFirstResponder: Bool {
return true
}
let globalKeyCommands = [
UIKeyCommand(
input: "n",
modifierFlags: .command,
action: #selector(showNewConversationView),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_NEW_MESSAGE",
comment: "A keyboard command to present the new message dialog."
)
),
UIKeyCommand(
input: "g",
modifierFlags: .command,
action: #selector(showNewGroupView),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_NEW_GROUP",
comment: "A keyboard command to present the new group dialog."
)
),
UIKeyCommand(
input: ",",
modifierFlags: .command,
action: #selector(showAppSettings),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_SETTINGS",
comment: "A keyboard command to present the application settings dialog."
)
),
UIKeyCommand(
input: "f",
modifierFlags: .command,
action: #selector(focusSearch),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_SEARCH",
comment: "A keyboard command to begin a search on the conversation list."
)
),
UIKeyCommand(
input: UIKeyCommand.inputUpArrow,
modifierFlags: .alternate,
action: #selector(selectPreviousConversation),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_PREVIOUS_CONVERSATION",
comment: "A keyboard command to jump to the previous conversation in the list."
)
),
UIKeyCommand(
input: UIKeyCommand.inputDownArrow,
modifierFlags: .alternate,
action: #selector(selectNextConversation),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_NEXT_CONVERSATION",
comment: "A keyboard command to jump to the next conversation in the list."
)
)
]
var selectedConversationKeyCommands: [UIKeyCommand] {
return [
UIKeyCommand(
input: "i",
modifierFlags: [.command, .shift],
action: #selector(openConversationSettings),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_CONVERSATION_INFO",
comment: "A keyboard command to open the current conversation's settings."
)
),
UIKeyCommand(
input: "m",
modifierFlags: [.command, .shift],
action: #selector(openAllMedia),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_ALL_MEDIA",
comment: "A keyboard command to open the current conversation's all media view."
)
),
UIKeyCommand(
input: "g",
modifierFlags: [.command, .shift],
action: #selector(openGifSearch),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_GIF_SEARCH",
comment: "A keyboard command to open the current conversations GIF picker."
)
),
UIKeyCommand(
input: "u",
modifierFlags: .command,
action: #selector(openAttachmentKeyboard),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_ATTACHMENTS",
comment: "A keyboard command to open the current conversation's attachment picker."
)
),
UIKeyCommand(
input: "s",
modifierFlags: [.command, .shift],
action: #selector(openStickerKeyboard),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_STICKERS",
comment: "A keyboard command to open the current conversation's sticker picker."
)
),
UIKeyCommand(
input: "a",
modifierFlags: [.command, .shift],
action: #selector(archiveSelectedConversation),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_ARCHIVE",
comment: "A keyboard command to archive the current coversation."
)
),
UIKeyCommand(
input: "u",
modifierFlags: [.command, .shift],
action: #selector(unarchiveSelectedConversation),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_UNARCHIVE",
comment: "A keyboard command to unarchive the current coversation."
)
),
UIKeyCommand(
input: "t",
modifierFlags: [.command, .shift],
action: #selector(focusInputToolbar),
discoverabilityTitle: NSLocalizedString(
"KEY_COMMAND_FOCUS_COMPOSER",
comment: "A keyboard command to focus the current conversation's input field."
)
)
]
}
override var keyCommands: [UIKeyCommand]? {
// If there is a modal presented over us, or another window above us, don't respond to keyboard commands.
guard presentedViewController == nil || view.window?.isKeyWindow != true else { return nil }
// Don't allow keyboard commands while presenting message actions.
guard selectedConversationViewController?.isPresentingMessageActions != true else { return nil }
if selectedThread != nil {
return selectedConversationKeyCommands + globalKeyCommands
} else {
return globalKeyCommands
}
}
@objc func showNewConversationView() {
conversationListVC.showNewConversationView()
}
@objc func showNewGroupView() {
conversationListVC.showNewGroupView()
}
@objc func showAppSettings() {
conversationListVC.showAppSettings()
}
func showAppSettingsWithMode(_ mode: ShowAppSettingsMode) {
conversationListVC.showAppSettings(mode: mode)
}
@objc func focusSearch() {
conversationListVC.focusSearch()
}
@objc func selectPreviousConversation() {
conversationListVC.selectPreviousConversation()
}
@objc func selectNextConversation(_ sender: UIKeyCommand) {
conversationListVC.selectNextConversation()
}
@objc func archiveSelectedConversation() {
conversationListVC.archiveSelectedConversation()
}
@objc func unarchiveSelectedConversation() {
conversationListVC.unarchiveSelectedConversation()
}
@objc func openConversationSettings() {
guard let selectedConversationViewController = selectedConversationViewController else {
return owsFailDebug("unexpectedly missing selected conversation")
}
selectedConversationViewController.showConversationSettings()
}
@objc func focusInputToolbar() {
guard let selectedConversationViewController = selectedConversationViewController else {
return owsFailDebug("unexpectedly missing selected conversation")
}
selectedConversationViewController.focusInputToolbar()
}
@objc func openAllMedia() {
guard let selectedConversationViewController = selectedConversationViewController else {
return owsFailDebug("unexpectedly missing selected conversation")
}
selectedConversationViewController.openAllMedia()
}
@objc func openStickerKeyboard() {
guard let selectedConversationViewController = selectedConversationViewController else {
return owsFailDebug("unexpectedly missing selected conversation")
}
selectedConversationViewController.openStickerKeyboard()
}
@objc func openAttachmentKeyboard() {
guard let selectedConversationViewController = selectedConversationViewController else {
return owsFailDebug("unexpectedly missing selected conversation")
}
selectedConversationViewController.openAttachmentKeyboard()
}
@objc func openGifSearch() {
guard let selectedConversationViewController = selectedConversationViewController else {
return owsFailDebug("unexpectedly missing selected conversation")
}
selectedConversationViewController.openGifSearch()
}
}
extension ConversationSplitViewController: UISplitViewControllerDelegate {
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
applyNavBarStyle(collapsed: true)
// If we're currently showing the placeholder view, we want to do nothing with in
// when collapsing into a signle nav controller without a side panel.
guard secondaryViewController != detailPlaceholderVC else { return true }
assert(secondaryViewController == detailNavController)
// Move all the views from the detail nav controller onto the primary nav controller.
primaryNavController.viewControllers += detailNavController.viewControllers
return true
}
func splitViewController(_ splitViewController: UISplitViewController, separateSecondaryFrom primaryViewController: UIViewController) -> UIViewController? {
assert(primaryViewController == primaryNavController)
applyNavBarStyle(collapsed: false)
// See if the current conversation is currently in the view hierarchy. If not,
// show the placeholder view as no conversation is selected. The conversation
// was likely popped from the stack while the split view was collapsed.
guard let currentConversationVC = selectedConversationViewController,
let conversationVCIndex = primaryNavController.viewControllers.firstIndex(of: currentConversationVC) else {
self.selectedConversationViewController = nil
return detailPlaceholderVC
}
// Move everything on the nav stack from the conversation view on back onto
// the detail nav controller.
let allViewControllers = primaryNavController.viewControllers
primaryNavController.viewControllers = Array(allViewControllers[0..<conversationVCIndex]).filter { vc in
// Don't ever allow a conversation view controller to be transfered on the master
// stack when expanding from collapsed mode. This should never happen.
guard let vc = vc as? ConversationViewController else { return true }
owsFailDebug("Unexpected conversation in view hierarchy: \(vc.thread.uniqueId)")
return false
}
// Create a new detail nav because reusing the existing one causes
// some strange behavior around the title view + input accessory view.
// TODO iPad: Maybe investigate this further.
detailNavController = OWSNavigationController()
detailNavController.viewControllers = Array(allViewControllers[conversationVCIndex..<allViewControllers.count])
return detailNavController
}
}
extension ConversationSplitViewController: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
// If we're collapsed and navigating to a list VC (either inbox or archive)
// the current conversation is no longer selected.
guard isCollapsed, viewController is ConversationListViewController else { return }
selectedConversationViewController = nil
}
func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return navigationTransitionDelegate?.navigationController?(
navigationController,
interactionControllerFor: animationController
)
}
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return navigationTransitionDelegate?.navigationController?(
navigationController,
animationControllerFor: operation,
from: fromVC,
to: toVC
)
}
}
@objc extension ConversationListViewController {
var conversationSplitViewController: ConversationSplitViewController? {
return splitViewController as? ConversationSplitViewController
}
}
@objc extension ConversationViewController {
var conversationSplitViewController: ConversationSplitViewController? {
return splitViewController as? ConversationSplitViewController
}
}
private class NoSelectedConversationViewController: OWSViewController {
let titleLabel = UILabel()
let bodyLabel = UILabel()
let logoImageView = UIImageView()
override func loadView() {
view = UIView()
let logoContainer = UIView.container()
logoImageView.image = #imageLiteral(resourceName: "signal-logo-128").withRenderingMode(.alwaysTemplate)
logoImageView.contentMode = .scaleAspectFit
logoContainer.addSubview(logoImageView)
logoImageView.autoPinTopToSuperviewMargin()
logoImageView.autoPinBottomToSuperviewMargin(withInset: 8)
logoImageView.autoHCenterInSuperview()
logoImageView.autoSetDimension(.height, toSize: 72)
titleLabel.font = UIFont.ows_dynamicTypeBody.ows_semibold
titleLabel.textAlignment = .center
titleLabel.numberOfLines = 0
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.text = NSLocalizedString("NO_SELECTED_CONVERSATION_TITLE", comment: "Title welcoming to the app")
bodyLabel.font = .ows_dynamicTypeBody
bodyLabel.textAlignment = .center
bodyLabel.numberOfLines = 0
bodyLabel.lineBreakMode = .byWordWrapping
bodyLabel.text = NSLocalizedString("NO_SELECTED_CONVERSATION_DESCRIPTION", comment: "Explanation of how to see a conversation.")
let centerStackView = UIStackView(arrangedSubviews: [logoContainer, titleLabel, bodyLabel])
centerStackView.axis = .vertical
centerStackView.spacing = 4
view.addSubview(centerStackView)
// Slightly offset from center to better optically center
centerStackView.autoAlignAxis(.horizontal, toSameAxisOf: view, withMultiplier: 0.88)
centerStackView.autoPinWidthToSuperview()
}
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.applyTheme), name: .ThemeDidChange, object: nil)
applyTheme()
}
@objc
override func applyTheme() {
view.backgroundColor = Theme.backgroundColor
titleLabel.textColor = Theme.primaryTextColor
bodyLabel.textColor = Theme.secondaryTextAndIconColor
logoImageView.tintColor = Theme.isDarkThemeEnabled ? .ows_gray05 : .ows_gray65
}
}
extension ConversationSplitViewController: DeviceTransferServiceObserver {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
deviceTransferService.addObserver(self)
deviceTransferService.startListeningForNewDevices()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
deviceTransferService.removeObserver(self)
deviceTransferService.stopListeningForNewDevices()
}
func deviceTransferServiceDiscoveredNewDevice(peerId: MCPeerID, discoveryInfo: [String: String]?) {
guard deviceTransferNavController?.presentingViewController == nil else { return }
let navController = DeviceTransferNavigationController()
deviceTransferNavController = navController
navController.present(fromViewController: self)
}
func deviceTransferServiceDidStartTransfer(progress: Progress) {}
func deviceTransferServiceDidEndTransfer(error: DeviceTransferService.Error?) {}
*/
}

View File

@ -568,6 +568,9 @@ extension GroupCallViewController: CallObserver {
}
func groupCallEnded(_ call: SignalCall, reason: GroupCallEndReason) {
// TODO: Implement
/*
AssertIsOnMainThread()
owsAssertDebug(call.isGroupCall)
@ -608,6 +611,7 @@ extension GroupCallViewController: CallObserver {
}
))
presentActionSheet(actionSheet)
*/
}
func callMessageSendFailedUntrustedIdentity(_ call: SignalCall) {
@ -671,8 +675,11 @@ extension GroupCallViewController: CallHeaderDelegate {
}
func didTapMembersButton() {
// TODO: Implement
/*
let sheet = GroupCallMemberSheet(call: call)
present(sheet, animated: true)
*/
}
}
@ -705,6 +712,9 @@ extension GroupCallViewController: UIScrollViewDelegate {
extension GroupCallViewController: GroupCallMemberViewDelegate {
func memberView(_ view: GroupCallMemberView, userRequestedInfoAboutError error: GroupCallMemberView.ErrorState) {
// TODO: Implement
/*
let title: String
let message: String
@ -735,5 +745,6 @@ extension GroupCallViewController: GroupCallMemberViewDelegate {
let actionSheet = ActionSheetController(title: title, message: message, theme: .translucentDark)
actionSheet.addAction(ActionSheetAction(title: CommonStrings.okButton))
presentActionSheet(actionSheet)
*/
}
}

View File

@ -42,7 +42,7 @@ final class CallKitCallManager: NSObject {
} else {
let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.individualCall.localId.uuidString
handle = CXHandle(type: .generic, value: callKitId)
CallKitIdStore.setAddress(call.individualCall.remoteAddress, forCallKitId: callKitId)
CallKitIdStore.setAddress(call.individualCall.publicKey, forCallKitId: callKitId)
}
let startCallAction = CXStartCallAction(call: call.individualCall.localId, handle: handle)

View File

@ -141,14 +141,13 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
let update = CXCallUpdate()
if showNamesOnCallScreen {
update.localizedCallerName = contactsManager.displayName(for: call.individualCall.remoteAddress)
if let phoneNumber = call.individualCall.remoteAddress.phoneNumber {
update.remoteHandle = CXHandle(type: .phoneNumber, value: phoneNumber)
}
let publicKey = call.individualCall.publicKey
update.localizedCallerName = Storage.shared.getContact(with: publicKey)?.displayName(for: Contact.Context.regular) ?? publicKey
update.remoteHandle = CXHandle(type: .phoneNumber, value: publicKey)
} else {
let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.individualCall.localId.uuidString
update.remoteHandle = CXHandle(type: .generic, value: callKitId)
CallKitIdStore.setAddress(call.individualCall.remoteAddress, forCallKitId: callKitId)
CallKitIdStore.setAddress(call.individualCall.publicKey, forCallKitId: callKitId)
update.localizedCallerName = NSLocalizedString("CALLKIT_ANONYMOUS_CONTACT_NAME", comment: "The generic name used for calls if CallKit privacy is enabled")
}

View File

@ -0,0 +1,13 @@
// Mimics Signal's CallKitIdStore
enum CallKitIdStore {
private static let callKitIDCollection = "CallKitIDCollection"
static func setAddress(_ publicKey: String, forCallKitId callKitId: String) {
Storage.write { transaction in
transaction.setObject(publicKey, forKey: callKitId, inCollection: CallKitIdStore.callKitIDCollection)
}
}
}

View File

@ -41,11 +41,6 @@ class PhotoCapture: NSObject {
self.session = AVCaptureSession()
self.captureOutput = CaptureOutput()
}
// MARK: - Dependencies
var audioSession: OWSAudioSession {
return Environment.shared.audioSession
}
// MARK: -
var audioDeviceInput: AVCaptureDeviceInput?

View File

@ -55,6 +55,8 @@ NS_ASSUME_NONNULL_BEGIN
- (void)showHomeView;
- (nullable UIView *)snapshotSplitViewControllerAfterScreenUpdates:(BOOL)afterScreenUpdates;
@end
NS_ASSUME_NONNULL_END

View File

@ -163,6 +163,16 @@ NS_ASSUME_NONNULL_BEGIN
[self setSignUpFlowNavigationController:nil];
}
- (nullable UIView *)snapshotSplitViewControllerAfterScreenUpdates:(BOOL)afterScreenUpdates
{
return [self.conversationSplitViewController.view snapshotViewAfterScreenUpdates:afterScreenUpdates];
}
- (nullable ConversationSplitViewController *)conversationSplitViewControllerForSwift
{
return self.conversationSplitViewController;
}
@end
NS_ASSUME_NONNULL_END