diff --git a/.gitignore b/.gitignore index ad1b2afc..a837a72a 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,4 @@ fastlane/screenshots fastlane/test_output .DS_Store xcuserdata +Libraries diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 00000000..8387866d --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,4 @@ +disabled_rules: + - trailing_whitespace +included: + - iOS/Controller/Library/LibraryViewController.swift \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 066f5348..8a80e59a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 1.14.3 + +- Library zim file detail now show file descriptions +- Technical implementation improvements for library on iOS 13 & 14 (Mostly SwiftUI) +- Fixed an issue where recent search button doesn't do anything if the search text contains spaces +- Note: we will drop support for iOS 12 once iOS 15 is released, we support the last three major iOS versions + ## 1.14.2 - Search result UI tweaks diff --git a/Kiwix.xcodeproj/project.pbxproj b/Kiwix.xcodeproj/project.pbxproj index beb72fb0..04823eba 100644 --- a/Kiwix.xcodeproj/project.pbxproj +++ b/Kiwix.xcodeproj/project.pbxproj @@ -85,12 +85,10 @@ 9789C26424F9600D00072090 /* Platform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97B399912468502500BC6F5B /* Platform.swift */; }; 9789C26524F9601400072090 /* ZimFileService.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9779A5A92456793500F6F6FF /* ZimFileService.mm */; }; 9789C26624F9601700072090 /* ZimFileService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9779A5AA2456793500F6F6FF /* ZimFileService.swift */; }; - 9789C26724F9608500072090 /* libkiwix.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97E02DE324B00C82008E278D /* libkiwix.xcframework */; }; 9789C26824F960F500072090 /* WebKitHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9779A73A2456796B00F6F6FF /* WebKitHandler.swift */; }; 9789C26924F9611300072090 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9779A7E224567A5A00F6F6FF /* Log.swift */; }; 978B688924F8080E003CCA8C /* BarButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978B688824F8080E003CCA8C /* BarButtons.swift */; }; 978C58092468FC1100D56AC8 /* SettingSearchController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 975F97A720D00EAE0005D642 /* SettingSearchController.swift */; }; - 978D0AE525A26164003DEE33 /* libkiwix.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97E02DE324B00C82008E278D /* libkiwix.xcframework */; }; 978FA76825851B4D00666E1B /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978FA76725851B4D00666E1B /* HomeView.swift */; }; 9793548B257D86370076E94A /* Queries.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9793548A257D86370076E94A /* Queries.swift */; }; 97952EF3264F557B00FC9237 /* SearchResultsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97952EF2264F557B00FC9237 /* SearchResultsView.swift */; }; @@ -130,10 +128,6 @@ 97C5763D202CD9C000E37502 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97C575F3202CB0E800E37502 /* NotificationCenter.framework */; platformFilter = ios; }; 97CA4A7220A21D24008CEA6D /* LibraryLanguageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97CA4A7120A21D24008CEA6D /* LibraryLanguageController.swift */; }; 97CD2F0424D4FB6F0084C6B5 /* SearchFilterController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97CD2F0324D4FB6F0084C6B5 /* SearchFilterController.swift */; }; - 97CE15B723B26EB300378D9F /* Realm in Frameworks */ = {isa = PBXBuildFile; productRef = 97CE15B623B26EB300378D9F /* Realm */; }; - 97CE15B923B26EB300378D9F /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 97CE15B823B26EB300378D9F /* RealmSwift */; }; - 97CE15BB23B26ED200378D9F /* Realm in Frameworks */ = {isa = PBXBuildFile; productRef = 97CE15BA23B26ED200378D9F /* Realm */; }; - 97CE15BD23B26ED200378D9F /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 97CE15BC23B26ED200378D9F /* RealmSwift */; }; 97CE4241249086A600B334E9 /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = 97CE4240249086A600B334E9 /* Defaults */; }; 97CE4242249322E300B334E9 /* SearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 97B3998C2467561900BC6F5B /* SearchResult.m */; }; 97CE42432493234D00B334E9 /* SearchOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97B3998F2467626A00BC6F5B /* SearchOperation.swift */; }; @@ -144,9 +138,19 @@ 97CE424A24957C3500B334E9 /* LibraryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9779A59C2456793500F6F6FF /* LibraryService.swift */; }; 97D19F072546FF3700910CAE /* BuildingBlocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97D19F062546FF3700910CAE /* BuildingBlocks.swift */; }; 97DBCF9D203CA254004EE274 /* SettingExternalLinkController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97DBCF9C203CA254004EE274 /* SettingExternalLinkController.swift */; }; - 97E02DE424B00C82008E278D /* libkiwix.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97E02DE324B00C82008E278D /* libkiwix.xcframework */; }; 97E173D425733D11002CAD17 /* RootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97E173D325733D10002CAD17 /* RootViewController.swift */; }; 97E983541F4DDB670021E96A /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97E983531F4DDB670021E96A /* SearchView.swift */; }; + 97EC18B326E8555E008309ED /* libkiwix.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97EC18AF26E8555E008309ED /* libkiwix.xcframework */; }; + 97EC18B426E8555E008309ED /* libkiwix.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97EC18AF26E8555E008309ED /* libkiwix.xcframework */; }; + 97EC18B626E8555E008309ED /* RealmSwift.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97EC18B026E8555E008309ED /* RealmSwift.xcframework */; }; + 97EC18B726E8555E008309ED /* RealmSwift.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97EC18B026E8555E008309ED /* RealmSwift.xcframework */; }; + 97EC18B926E8555E008309ED /* Realm.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97EC18B126E8555E008309ED /* Realm.xcframework */; }; + 97EC18BA26E8555E008309ED /* Realm.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97EC18B126E8555E008309ED /* Realm.xcframework */; }; + 97EC18BB26E85C28008309ED /* libkiwix.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97EC18AF26E8555E008309ED /* libkiwix.xcframework */; }; + 97EC18BE26E85C58008309ED /* Realm.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97EC18B126E8555E008309ED /* Realm.xcframework */; }; + 97EC18BF26E85C58008309ED /* Realm.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 97EC18B126E8555E008309ED /* Realm.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 97EC18C126E85C5A008309ED /* RealmSwift.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97EC18B026E8555E008309ED /* RealmSwift.xcframework */; }; + 97EC18C226E85C5A008309ED /* RealmSwift.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 97EC18B026E8555E008309ED /* RealmSwift.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 97EFF05E235CAEFC00FBB7A4 /* ContentTabController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97EFF05D235CAEFC00FBB7A4 /* ContentTabController.swift */; }; 97F4210E22EE5590001E41F9 /* FileImportController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97F4210D22EE5590001E41F9 /* FileImportController.swift */; }; 97F4D10620AB80740038FC87 /* LibraryZimFileDetailController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97F4D10520AB80740038FC87 /* LibraryZimFileDetailController.swift */; }; @@ -193,6 +197,18 @@ name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; }; + 97EC18C026E85C58008309ED /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 97EC18BF26E85C58008309ED /* Realm.xcframework in Embed Frameworks */, + 97EC18C226E85C5A008309ED /* RealmSwift.xcframework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -311,9 +327,11 @@ 97CD2F0324D4FB6F0084C6B5 /* SearchFilterController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchFilterController.swift; sourceTree = ""; }; 97D19F062546FF3700910CAE /* BuildingBlocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildingBlocks.swift; sourceTree = ""; }; 97DBCF9C203CA254004EE274 /* SettingExternalLinkController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingExternalLinkController.swift; sourceTree = ""; }; - 97E02DE324B00C82008E278D /* libkiwix.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = libkiwix.xcframework; sourceTree = ""; }; 97E173D325733D10002CAD17 /* RootViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootViewController.swift; sourceTree = ""; }; 97E983531F4DDB670021E96A /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = ""; }; + 97EC18AF26E8555E008309ED /* libkiwix.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = libkiwix.xcframework; sourceTree = ""; }; + 97EC18B026E8555E008309ED /* RealmSwift.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = RealmSwift.xcframework; sourceTree = ""; }; + 97EC18B126E8555E008309ED /* Realm.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Realm.xcframework; sourceTree = ""; }; 97EFF05D235CAEFC00FBB7A4 /* ContentTabController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentTabController.swift; sourceTree = ""; }; 97F4210D22EE5590001E41F9 /* FileImportController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileImportController.swift; sourceTree = ""; }; 97F4D10520AB80740038FC87 /* LibraryZimFileDetailController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryZimFileDetailController.swift; sourceTree = ""; }; @@ -327,7 +345,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9789C26724F9608500072090 /* libkiwix.xcframework in Frameworks */, + 97EC18B426E8555E008309ED /* libkiwix.xcframework in Frameworks */, + 97EC18B726E8555E008309ED /* RealmSwift.xcframework in Frameworks */, + 97EC18BA26E8555E008309ED /* Realm.xcframework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -335,11 +355,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 97CE15BB23B26ED200378D9F /* Realm in Frameworks */, 97CE4241249086A600B334E9 /* Defaults in Frameworks */, - 978D0AE525A26164003DEE33 /* libkiwix.xcframework in Frameworks */, - 97CE15BD23B26ED200378D9F /* RealmSwift in Frameworks */, 97CE42462493239C00B334E9 /* SwiftSoup in Frameworks */, + 97EC18B326E8555E008309ED /* libkiwix.xcframework in Frameworks */, + 97EC18B626E8555E008309ED /* RealmSwift.xcframework in Frameworks */, + 97EC18B926E8555E008309ED /* Realm.xcframework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -347,13 +367,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 97CE15B723B26EB300378D9F /* Realm in Frameworks */, - 97CE15B923B26EB300378D9F /* RealmSwift in Frameworks */, - 97E02DE424B00C82008E278D /* libkiwix.xcframework in Frameworks */, 97C5763D202CD9C000E37502 /* NotificationCenter.framework in Frameworks */, + 97EC18BB26E85C28008309ED /* libkiwix.xcframework in Frameworks */, 971D589A247C5CC000532461 /* Defaults in Frameworks */, + 97EC18BE26E85C58008309ED /* Realm.xcframework in Frameworks */, 97A36C351F8C21210079B452 /* WebKit.framework in Frameworks */, 970EC3A423BCED7F008DCA27 /* SwiftSoup in Frameworks */, + 97EC18C126E85C5A008309ED /* RealmSwift.xcframework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -407,7 +427,6 @@ 970EC39E23BCE7F5008DCA27 /* Model */ = { isa = PBXGroup; children = ( - 97E02DE324B00C82008E278D /* libkiwix.xcframework */, 9779A5AB2456793600F6F6FF /* Entities */, 9779A59E2456793500F6F6FF /* Operations */, 9779A5AE2456793600F6F6FF /* Realm */, @@ -629,6 +648,7 @@ 97A2AB7F1C1B80FF00052E74 = { isa = PBXGroup; children = ( + 97EC18AE26E8555E008309ED /* Libraries */, 970EC39E23BCE7F5008DCA27 /* Model */, 979315821E5127930093D3BA /* macOS */, 975FDAD81F6082DA00A10E8C /* iOS */, @@ -722,6 +742,16 @@ path = View; sourceTree = ""; }; + 97EC18AE26E8555E008309ED /* Libraries */ = { + isa = PBXGroup; + children = ( + 97EC18AF26E8555E008309ED /* libkiwix.xcframework */, + 97EC18B026E8555E008309ED /* RealmSwift.xcframework */, + 97EC18B126E8555E008309ED /* Realm.xcframework */, + ); + path = Libraries; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -757,8 +787,6 @@ ); name = macOS; packageProductDependencies = ( - 97CE15BA23B26ED200378D9F /* Realm */, - 97CE15BC23B26ED200378D9F /* RealmSwift */, 97CE4240249086A600B334E9 /* Defaults */, 97CE42452493239C00B334E9 /* SwiftSoup */, ); @@ -774,6 +802,7 @@ 97A36C341F8C21210079B452 /* Frameworks */, 97A36C431F8C21210079B452 /* Resources */, 97C57602202CB0E900E37502 /* Embed App Extensions */, + 97EC18C026E85C58008309ED /* Embed Frameworks */, ); buildRules = ( ); @@ -782,8 +811,6 @@ ); name = iOS; packageProductDependencies = ( - 97CE15B623B26EB300378D9F /* Realm */, - 97CE15B823B26EB300378D9F /* RealmSwift */, 970EC3A323BCED7F008DCA27 /* SwiftSoup */, 971D5899247C5CC000532461 /* Defaults */, ); @@ -902,7 +929,6 @@ ); mainGroup = 97A2AB7F1C1B80FF00052E74; packageReferences = ( - 97CE15B523B26EB300378D9F /* XCRemoteSwiftPackageReference "realm-cocoa" */, 970EC3A223BCED7F008DCA27 /* XCRemoteSwiftPackageReference "SwiftSoup" */, 971D5898247C5CC000532461 /* XCRemoteSwiftPackageReference "Defaults" */, ); @@ -1428,7 +1454,7 @@ CODE_SIGN_ENTITLEMENTS = iOS/Support/Kiwix.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = L7HWM3SP3L; ENABLE_BITCODE = YES; GCC_C_LANGUAGE_STANDARD = c11; @@ -1468,7 +1494,7 @@ CODE_SIGN_ENTITLEMENTS = iOS/Support/Kiwix.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = L7HWM3SP3L; ENABLE_BITCODE = YES; GCC_C_LANGUAGE_STANDARD = c11; @@ -1560,7 +1586,7 @@ CODE_SIGN_ENTITLEMENTS = iOS/BookmarksWidget/Bookmarks.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = L7HWM3SP3L; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = iOS/BookmarksWidget/Info.plist; @@ -1592,7 +1618,7 @@ CODE_SIGN_ENTITLEMENTS = iOS/BookmarksWidget/Bookmarks.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 70; + CURRENT_PROJECT_VERSION = 72; DEVELOPMENT_TEAM = L7HWM3SP3L; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = iOS/BookmarksWidget/Info.plist; @@ -1688,14 +1714,6 @@ minimumVersion = 5.0.0; }; }; - 97CE15B523B26EB300378D9F /* XCRemoteSwiftPackageReference "realm-cocoa" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/realm/realm-cocoa"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 10.8.0; - }; - }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -1709,26 +1727,6 @@ package = 971D5898247C5CC000532461 /* XCRemoteSwiftPackageReference "Defaults" */; productName = Defaults; }; - 97CE15B623B26EB300378D9F /* Realm */ = { - isa = XCSwiftPackageProductDependency; - package = 97CE15B523B26EB300378D9F /* XCRemoteSwiftPackageReference "realm-cocoa" */; - productName = Realm; - }; - 97CE15B823B26EB300378D9F /* RealmSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 97CE15B523B26EB300378D9F /* XCRemoteSwiftPackageReference "realm-cocoa" */; - productName = RealmSwift; - }; - 97CE15BA23B26ED200378D9F /* Realm */ = { - isa = XCSwiftPackageProductDependency; - package = 97CE15B523B26EB300378D9F /* XCRemoteSwiftPackageReference "realm-cocoa" */; - productName = Realm; - }; - 97CE15BC23B26ED200378D9F /* RealmSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 97CE15B523B26EB300378D9F /* XCRemoteSwiftPackageReference "realm-cocoa" */; - productName = RealmSwift; - }; 97CE4240249086A600B334E9 /* Defaults */ = { isa = XCSwiftPackageProductDependency; package = 971D5898247C5CC000532461 /* XCRemoteSwiftPackageReference "Defaults" */; diff --git a/Kiwix.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Kiwix.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d6eca680..ebee67da 100644 --- a/Kiwix.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Kiwix.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -10,24 +10,6 @@ "version": "5.0.0" } }, - { - "package": "Realm", - "repositoryURL": "https://github.com/realm/realm-cocoa", - "state": { - "branch": null, - "revision": "e7e7f072a1571435049683ca43c51501de2612fd", - "version": "10.14.0" - } - }, - { - "package": "RealmDatabase", - "repositoryURL": "https://github.com/realm/realm-core", - "state": { - "branch": null, - "revision": "fdb2157346dcdf0c2677b3608d9a4c30315fa7f0", - "version": "11.3.1" - } - }, { "package": "SwiftSoup", "repositoryURL": "https://github.com/scinfu/SwiftSoup", diff --git a/iOS/Controller/Library/LibraryViewController.swift b/iOS/Controller/Library/LibraryViewController.swift index d0f9dfef..81f59ef5 100644 --- a/iOS/Controller/Library/LibraryViewController.swift +++ b/iOS/Controller/Library/LibraryViewController.swift @@ -12,7 +12,8 @@ import Defaults import RealmSwift @available(iOS 13.0, *) -class LibraryViewController: UISplitViewController, UISplitViewControllerDelegate, UISearchResultsUpdating { +class LibraryViewController: UISplitViewController, UISplitViewControllerDelegate, + UISearchResultsUpdating, UIDocumentPickerDelegate { private let primaryController = UIHostingController(rootView: LibraryPrimaryView()) private let searchResultsController = UIHostingController(rootView: LibrarySearchResultView()) private let searchController: UISearchController @@ -57,16 +58,22 @@ class LibraryViewController: UISplitViewController, UISplitViewControllerDelegat style: .plain, target: self, action: #selector(showSettings(sender:)) + ), + UIBarButtonItem( + image: UIImage(systemName: "plus"), + style: .plain, + target: self, + action: #selector(importFiles(sender:)) ) ] - primaryController.rootView.zimFileSelected = { - [unowned self] zimFileID, title in self.showZimFile(zimFileID, title) + primaryController.rootView.zimFileSelected = { [unowned self] zimFileID, title in + self.showZimFile(zimFileID, title) } primaryController.rootView.categorySelected = { [unowned self] category in self.showCategory(category) } // configure search result controller action - searchResultsController.rootView.zimFileSelected = { - [unowned self] zimFileID, title in self.showZimFile(zimFileID, title) + searchResultsController.rootView.zimFileSelected = { [unowned self] zimFileID, title in + self.showZimFile(zimFileID, title) } // refresh library when library is opened, but only when library has been previously refreshed @@ -91,6 +98,15 @@ class LibraryViewController: UISplitViewController, UISplitViewControllerDelegat } } + func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { + guard let url = urls.first else { return } + if let _ = ZimFileService.getMetaData(url: url) { + present(FileImportController(fileURL: url), animated: true) + } else { + present(FileImportAlertController(fileName: url.lastPathComponent), animated: true) + } + } + // MARK: - Action @objc private func dismissController() { @@ -101,6 +117,13 @@ class LibraryViewController: UISplitViewController, UISplitViewControllerDelegat presentedViewController?.dismiss(animated: true) } + @objc private func importFiles(sender: UIBarButtonItem) { + let controller = UIDocumentPickerViewController(documentTypes: ["org.openzim.zim"], in: .open) + controller.allowsMultipleSelection = false + controller.delegate = self + present(controller, animated: true) + } + @objc private func showSettings(sender: UIBarButtonItem) { let controller = UIHostingController(rootView: LibrarySettingsView()) controller.title = "Settings" diff --git a/iOS/Controller/Library/LibraryZimFileDetailController.swift b/iOS/Controller/Library/LibraryZimFileDetailController.swift index 48500a83..98ef09ac 100644 --- a/iOS/Controller/Library/LibraryZimFileDetailController.swift +++ b/iOS/Controller/Library/LibraryZimFileDetailController.swift @@ -12,7 +12,6 @@ import RealmSwift class LibraryZimFileDetailController: UIViewController, UITableViewDataSource, UITableViewDelegate { private let zimFile: ZimFile private var zimFileObserver: NotificationToken? - private var zimFileStateRawObserver: NSKeyValueObservation? private let documentDirectoryURL = try! FileManager.default.url( for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) @@ -89,6 +88,7 @@ class LibraryZimFileDetailController: UIViewController, UITableViewDataSource, U override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) configureZimFileObservers() + configureState() } // MARK: - @@ -109,56 +109,58 @@ class LibraryZimFileDetailController: UIViewController, UITableViewDataSource, U self.navigationController?.popViewController(animated: true) } } + case .change(_, let properties): + for property in properties { + if property.name == "stateRaw" { + self.configureState(property: property) + } + } default: break } } - zimFileStateRawObserver = zimFile.observe(\.stateRaw, - options: [.initial, .old], - changeHandler: { (zimFile, change) in - guard let state = ZimFile.State(rawValue: zimFile.stateRaw) else { - self.actions = ([[]], [[]]) - return - } - switch state { - case .remote: - let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first - let freespace: Int64 = { - if let free = (((try? url?.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey])) as URLResourceValues??))??.volumeAvailableCapacityForImportantUsage { - return free - } else { - return 0 - } - }() - self.actions = (zimFile.size <= freespace ? [[.downloadWifiOnly, .downloadWifiAndCellular]] : [[.downloadSpaceNotEnough]], []) - - // when state changed from onDevice to remote, and when split view controller is collapsed - // pop this view controller - if let oldState = ZimFile.State(rawValue: change.oldValue ?? ""), - oldState == .onDevice, - let splitViewController = self.splitViewController, - splitViewController.isCollapsed, - let masterNavigationController = splitViewController.viewControllers.first as? UINavigationController { - masterNavigationController.popViewController(animated: true) - } - case .onDevice: - if LibraryService().isFileInDocumentDirectory(zimFileID: zimFile.fileID) { - self.actions = ([[.openMainPage]], [[.deleteFile]]) + } + + func configureState(property: PropertyChange? = nil) { + guard let state = ZimFile.State(rawValue: property?.newValue as? String ?? zimFile.stateRaw) else { return } + switch state { + case .remote: + let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first + let freespace: Int64 = { + if let free = (((try? url?.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey])) as URLResourceValues??))??.volumeAvailableCapacityForImportantUsage { + return free } else { - self.actions = ([[.openMainPage]], [[.unlink]]) + return 0 } - case .retained: - self.actions = ([], [[.deleteBookmarks]]) - case .downloadQueued: - self.actions = ([[.cancel]], []) - case .downloadInProgress: - self.actions = ([[.pause, .cancel]], []) - case .downloadPaused: - self.actions = ([[.resume, .cancel]], []) - case .downloadError: - self.actions = ([[.cancel]], []) + }() + self.actions = (zimFile.size <= freespace ? [[.downloadWifiOnly, .downloadWifiAndCellular]] : [[.downloadSpaceNotEnough]], []) + + // when state changed from onDevice to remote, and when split view controller is collapsed + // pop this view controller + if let oldState = ZimFile.State(rawValue: property?.oldValue as? String ?? ""), + oldState == .onDevice, + let splitViewController = self.splitViewController, + splitViewController.isCollapsed, + let masterNavigationController = splitViewController.viewControllers.first as? UINavigationController { + masterNavigationController.popViewController(animated: true) } - }) + case .onDevice: + if LibraryService().isFileInDocumentDirectory(zimFileID: zimFile.fileID) { + self.actions = ([[.openMainPage]], [[.deleteFile]]) + } else { + self.actions = ([[.openMainPage]], [[.unlink]]) + } + case .retained: + self.actions = ([], [[.deleteBookmarks]]) + case .downloadQueued: + self.actions = ([[.cancel]], []) + case .downloadInProgress: + self.actions = ([[.pause, .cancel]], []) + case .downloadPaused: + self.actions = ([[.resume, .cancel]], []) + case .downloadError: + self.actions = ([[.cancel]], []) + } } // MARK: - UITableViewDataSource & Delagates