Create and use MainWindowController for iOS.

This commit is contained in:
Brent Simmons
2025-02-02 20:18:38 -08:00
parent 08f21ca4b2
commit 7362b28c20
3 changed files with 110 additions and 34 deletions

View File

@@ -17,6 +17,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationC
var window: UIWindow?
private var mainWindowController: MainWindowController?
private var coordinator: SceneCoordinator?
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "Application")
@@ -77,30 +78,10 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationC
ArticleStatusSyncTimer.shared.update()
#endif
// Create window.
let window = UIWindow(frame: UIScreen.main.bounds)
self.window = window
// Create UI and add it to window.
let rootSplitViewController = RootSplitViewController()
coordinator = SceneCoordinator(rootSplitViewController: rootSplitViewController)
rootSplitViewController.coordinator = coordinator
rootSplitViewController.delegate = coordinator
window.rootViewController = rootSplitViewController
window.tintColor = AppColor.accent
updateUserInterfaceStyle()
UINavigationBar.appearance().scrollEdgeAppearance = UINavigationBarAppearance()
window.makeKeyAndVisible()
// Create window and UI
mainWindowController = MainWindowController()
Task { @MainActor in
// Ensure Feeds view shows on first run on iPad  otherwise the UI is empty.
if UIDevice.current.userInterfaceIdiom == .pad && AppDefaults.isFirstRun {
rootSplitViewController.show(.primary)
}
self.unreadCount = AccountManager.shared.unreadCount
}
@@ -119,7 +100,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationC
func applicationWillEnterForeground(_ application: UIApplication) {
prepareAccountsForForeground()
coordinator?.resetFocus()
mainWindowController?.resetFocus()
}
private func prepareAccountsForForeground() {
@@ -167,7 +148,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationC
ArticleThemeDownloader.shared.cleanUp()
CoalescingQueue.standard.performCallsImmediately()
coordinator?.suspend()
mainWindowController?.suspend()
logger.info("Application processing suspended.")
}
}
@@ -195,7 +176,7 @@ extension AppDelegate {
return
}
coordinator?.cleanUp(conditional: true)
mainWindowController?.cleanUp(conditional: true)
AccountManager.shared.refreshAll(errorHandler: errorHandler)
}
@@ -225,7 +206,7 @@ extension AppDelegate {
default:
handle(response)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.coordinator?.dismissIfLaunchingFromExternalAction()
self.mainWindowController?.dismissIfLaunchingFromExternalAction()
}
}
}
@@ -329,6 +310,6 @@ private extension AppDelegate {
func handle(_ response: UNNotificationResponse) {
AccountManager.shared.resumeAllIfSuspended()
coordinator?.handle(response)
mainWindowController?.handle(response)
}
}

View File

@@ -0,0 +1,88 @@
//
// MainWindowController.swift
// NetNewsWire-iOS
//
// Created by Brent Simmons on 2/2/25.
// Copyright © 2025 Ranchero Software. All rights reserved.
//
import Foundation
import UIKit
final class MainWindowController {
let window: UIWindow
let rootSplitViewController: RootSplitViewController
let sidebarViewController = MainFeedViewController()
let timelineViewController = TimelineViewController()
let articleViewController = ArticleViewController()
let coordinator: SceneCoordinator
init() {
let window = UIWindow(frame: UIScreen.main.bounds)
self.window = window
let rootSplitViewController = RootSplitViewController(
sidebarViewController: sidebarViewController,
timelineViewController: timelineViewController,
articleViewController: articleViewController
)
self.coordinator = SceneCoordinator(rootSplitViewController: rootSplitViewController)
rootSplitViewController.coordinator = coordinator
rootSplitViewController.delegate = coordinator
self.rootSplitViewController = rootSplitViewController
window.rootViewController = rootSplitViewController
window.tintColor = AppColor.accent
updateUserInterfaceStyle()
UINavigationBar.appearance().scrollEdgeAppearance = UINavigationBarAppearance()
window.makeKeyAndVisible()
Task { @MainActor in
// Ensure Feeds view shows on first run on iPad  otherwise the UI is empty.
if UIDevice.current.userInterfaceIdiom == .pad && AppDefaults.isFirstRun {
rootSplitViewController.show(.primary)
}
}
}
// MARK: - API
func resetFocus() {
coordinator.resetFocus()
}
func suspend() {
coordinator.suspend()
}
func cleanUp(conditional: Bool) {
coordinator.cleanUp(conditional: conditional)
}
func dismissIfLaunchingFromExternalAction() {
coordinator.dismissIfLaunchingFromExternalAction()
}
func handle(_ response: UNNotificationResponse) {
coordinator.handle(response)
}
}
private extension MainWindowController {
func updateUserInterfaceStyle() {
assert(Thread.isMainThread)
let updatedStyle = AppDefaults.userInterfaceColorPalette.uiUserInterfaceStyle
if window.overrideUserInterfaceStyle != updatedStyle {
window.overrideUserInterfaceStyle = updatedStyle
}
}
}

View File

@@ -19,16 +19,23 @@ final class RootSplitViewController: UISplitViewController {
}
}
private lazy var sidebarViewController = MainFeedViewController()
private lazy var timelineViewController = TimelineViewController()
private lazy var articleViewController = ArticleViewController()
private let sidebarViewController: MainFeedViewController
private let timelineViewController: TimelineViewController
private let articleViewController: ArticleViewController
init(sidebarViewController: MainFeedViewController,
timelineViewController: TimelineViewController,
articleViewController: ArticleViewController) {
self.sidebarViewController = sidebarViewController
self.timelineViewController = timelineViewController
self.articleViewController = articleViewController
init() {
super.init(style: .tripleColumn)
setViewController(self.sidebarViewController, for: .primary)
setViewController(self.timelineViewController, for: .supplementary)
setViewController(self.articleViewController, for: .secondary)
setViewController(sidebarViewController, for: .primary)
setViewController(timelineViewController, for: .supplementary)
setViewController(articleViewController, for: .secondary)
self.showsSecondaryOnlyButton = true
self.preferredDisplayMode = .oneBesideSecondary