Skip to content

Commit

Permalink
Version 3.2 (#523)
Browse files Browse the repository at this point in the history
* view model

* setup

* library

* changelog

* macOS

* purge cache
  • Loading branch information
automactic authored Sep 27, 2023
1 parent 20d4ef2 commit fa397a9
Show file tree
Hide file tree
Showing 43 changed files with 1,499 additions and 1,365 deletions.
97 changes: 33 additions & 64 deletions App/App_iOS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import UserNotifications
#if os(iOS)
@main
struct Kiwix: App {
@Environment(\.scenePhase) private var scenePhase
@StateObject private var library = LibraryViewModel()
@StateObject private var navigation = NavigationViewModel()
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate

private let fileMonitor: DirectoryMonitor
Expand All @@ -29,7 +32,24 @@ struct Kiwix: App {

var body: some Scene {
WindowGroup {
RootView().environment(\.managedObjectContext, Database.viewContext)
RootView()
.ignoresSafeArea()
.environment(\.managedObjectContext, Database.viewContext)
.environmentObject(library)
.environmentObject(navigation)
.modifier(AlertHandler())
.modifier(OpenFileHandler())
.onChange(of: scenePhase) { newValue in
guard newValue == .inactive else { return }
try? Database.viewContext.save()
}
.onOpenURL { url in
if url.isFileURL {
NotificationCenter.openFiles([url], context: .file)
} else if url.scheme == "kiwix" {
NotificationCenter.openURL(url)
}
}
}
.commands {
CommandGroup(replacing: .undoRedo) {
Expand All @@ -55,77 +75,26 @@ struct Kiwix: App {
withCompletionHandler completionHandler: @escaping () -> Void) {
if let zimFileID = UUID(uuidString: response.notification.request.identifier),
let mainPageURL = ZimFileService.shared.getMainPageURL(zimFileID: zimFileID) {
UIApplication.shared.open(mainPageURL)
NotificationCenter.openURL(mainPageURL, inNewTab: true)
}
completionHandler()
}

/// Purge some cached browser view models when receiving memory warning
func applicationDidReceiveMemoryWarning(_ application: UIApplication) {
BrowserViewModel.purgeCache()
}
}
}

struct RootView: View {
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
@Environment(\.scenePhase) private var scenePhase
@StateObject private var library = LibraryViewModel()
@StateObject private var navigation = NavigationViewModel()
private struct RootView: UIViewControllerRepresentable {
@EnvironmentObject private var navigation: NavigationViewModel

private let primaryItems: [NavigationItem] = [.bookmarks, .settings]
private let libraryItems: [NavigationItem] = [.opened, .categories, .downloads, .new]
private let openURL = NotificationCenter.default.publisher(for: .openURL)
func makeUIViewController(context: Context) -> SplitViewController {
SplitViewController(navigationViewModel: navigation)
}

var body: some View {
Group {
if #available(iOS 16.0, *) {
if horizontalSizeClass == .regular {
RegularView()
} else {
ContainerView {
CompactView()
}
.ignoresSafeArea()
.onAppear() {
navigation.navigateToMostRecentTab()
}
}
} else {
ContainerView {
LegacyView()
}.ignoresSafeArea()
}
}
.focusedSceneValue(\.navigationItem, $navigation.currentItem)
.environmentObject(library)
.environmentObject(navigation)
.modifier(AlertHandler())
.modifier(ExternalLinkHandler())
.modifier(OpenFileHandler())
.onChange(of: scenePhase) { newScenePhase in
guard newScenePhase == .inactive else { return }
WebViewCache.shared.persistStates()
}
.onOpenURL { url in
if url.isFileURL {
NotificationCenter.openFiles([url], context: .file)
} else if url.scheme == "kiwix" {
NotificationCenter.openURL(url)
}
}
.onReceive(openURL) { notification in
guard let url = notification.userInfo?["url"] as? URL else { return }
let inNewTab = notification.userInfo?["inNewTab"] as? Bool ?? false
if #available(iOS 16.0, *) {
if inNewTab {
let tabID = navigation.createTab()
WebViewCache.shared.getWebView(tabID: tabID).load(URLRequest(url: url))
} else if case let .tab(tabID) = navigation.currentItem {
WebViewCache.shared.getWebView(tabID: tabID).load(URLRequest(url: url))
} else {
let tabID = navigation.createTab()
WebViewCache.shared.getWebView(tabID: tabID).load(URLRequest(url: url))
}
} else {
WebViewCache.shared.webView.load(URLRequest(url: url))
}
}
func updateUIViewController(_ controller: SplitViewController, context: Context) {
}
}
#endif
11 changes: 6 additions & 5 deletions App/App_macOS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,13 @@ struct Kiwix: App {
}

struct RootView: View {
@Environment(\.controlActiveState) var controlActiveState
@StateObject private var browser = BrowserViewModel()
@StateObject private var navigation = NavigationViewModel()

private let primaryItems: [NavigationItem] = [.reading, .bookmarks]
private let libraryItems: [NavigationItem] = [.opened, .categories, .downloads, .new]
private let openURL = NotificationCenter.default.publisher(for: Notification.Name.openURL)
private let openURL = NotificationCenter.default.publisher(for: .openURL)

var body: some View {
NavigationView {
Expand All @@ -108,7 +110,7 @@ struct RootView: View {
}
switch navigation.currentItem {
case .reading:
ReadingView()
BrowserTab().environmentObject(browser)
case .bookmarks:
Bookmarks()
case .opened:
Expand All @@ -127,7 +129,6 @@ struct RootView: View {
.focusedSceneValue(\.navigationItem, $navigation.currentItem)
.environmentObject(navigation)
.modifier(AlertHandler())
.modifier(ExternalLinkHandler())
.modifier(OpenFileHandler())
.onOpenURL { url in
if url.isFileURL {
Expand All @@ -137,8 +138,8 @@ struct RootView: View {
}
}
.onReceive(openURL) { notification in
guard let url = notification.userInfo?["url"] as? URL else { return }
WebViewCache.shared.webView.load(URLRequest(url: url))
guard controlActiveState == .key, let url = notification.userInfo?["url"] as? URL else { return }
browser.load(url: url)
navigation.currentItem = .reading
}
}
Expand Down
64 changes: 0 additions & 64 deletions App/CompactView.swift

This file was deleted.

142 changes: 142 additions & 0 deletions App/CompactViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//
// CompactViewController.swift
// Kiwix
//
// Created by Chris Li on 9/4/23.
// Copyright © 2023 Chris Li. All rights reserved.
//

#if os(iOS)
import Combine
import SwiftUI
import UIKit

class CompactViewController: UIHostingController<AnyView>, UISearchControllerDelegate, UISearchResultsUpdating {
private let searchViewModel: SearchViewModel
private let searchController: UISearchController
private var searchTextObserver: AnyCancellable?
private var openURLObserver: NSObjectProtocol?

init() {
searchViewModel = SearchViewModel()
let searchResult = SearchResults().environmentObject(searchViewModel)
searchController = UISearchController(searchResultsController: UIHostingController(rootView: searchResult))
super.init(rootView: AnyView(CompactView()))
searchController.searchResultsUpdater = self
}

@MainActor required dynamic init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
super.viewDidLoad()

definesPresentationContext = true
navigationController?.isToolbarHidden = false
navigationController?.toolbar.scrollEdgeAppearance = {
let apperance = UIToolbarAppearance()
apperance.configureWithDefaultBackground()
return apperance
}()
navigationItem.scrollEdgeAppearance = {
let apperance = UINavigationBarAppearance()
apperance.configureWithDefaultBackground()
return apperance
}()
navigationItem.titleView = searchController.searchBar
searchController.automaticallyShowsCancelButton = false
searchController.delegate = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.showsSearchResultsController = true

searchTextObserver = searchViewModel.$searchText.sink { [weak self] searchText in
guard self?.searchController.searchBar.text != searchText else { return }
self?.searchController.searchBar.text = searchText
}
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
openURLObserver = NotificationCenter.default.addObserver(
forName: .openURL, object: nil, queue: nil
) { [weak self] _ in
self?.searchController.isActive = false
self?.navigationItem.setRightBarButton(nil, animated: true)
}
}

override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
NotificationCenter.default.removeObserver(self)
}

func willPresentSearchController(_ searchController: UISearchController) {
navigationController?.setToolbarHidden(true, animated: true)
navigationItem.setRightBarButton(
UIBarButtonItem(systemItem: .cancel, primaryAction: UIAction { [unowned self] _ in
searchController.isActive = false
navigationItem.setRightBarButton(nil, animated: true)
}), animated: true
)
}

func willDismissSearchController(_ searchController: UISearchController) {
navigationController?.setToolbarHidden(false, animated: true)
searchViewModel.searchText = ""
}

func updateSearchResults(for searchController: UISearchController) {
searchViewModel.searchText = searchController.searchBar.text ?? ""
}
}

private struct CompactView: View {
@EnvironmentObject private var navigation: NavigationViewModel

var body: some View {
if case let .tab(tabID) = navigation.currentItem {
Content().id(tabID).toolbar {
ToolbarItemGroup(placement: .bottomBar) {
HStack {
NavigationButtons()
Spacer()
OutlineButton()
Spacer()
BookmarkButton()
Spacer()
ArticleShortcutButtons(displayMode: .randomArticle)
Spacer()
TabsManagerButton()
}
}
}
.environmentObject(BrowserViewModel.getCached(tabID: tabID))
}
}
}

private struct Content: View {
@EnvironmentObject private var browser: BrowserViewModel

var body: some View {
Group {
if browser.url == nil {
Welcome()
} else {
WebView().ignoresSafeArea()
}
}
.focusedSceneValue(\.browserViewModel, browser)
.focusedSceneValue(\.canGoBack, browser.canGoBack)
.focusedSceneValue(\.canGoForward, browser.canGoForward)
.modifier(ExternalLinkHandler())
.onAppear {
browser.updateLastOpened()
}
.onDisappear {
browser.persistState()
}
}
}
#endif
Loading

0 comments on commit fa397a9

Please sign in to comment.