Skip to content

Commit

Permalink
File open and import (#515)
Browse files Browse the repository at this point in the history
* open file button & handler

* open file in library

* file handler

* OpenFileContext

* open file action

* file owner

* remove tab id property

* disable open file button multi selection
  • Loading branch information
automactic authored Aug 21, 2023
1 parent a7ab087 commit 20d4ef2
Show file tree
Hide file tree
Showing 14 changed files with 157 additions and 81 deletions.
16 changes: 11 additions & 5 deletions App/App_iOS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ struct Kiwix: App {
RootView().environment(\.managedObjectContext, Database.viewContext)
}
.commands {
// CommandGroup(replacing: .importExport) {
// FileImportButton { Text("Open...") }
// }
CommandGroup(replacing: .undoRedo) {
NavigationCommands()
}
Expand Down Expand Up @@ -100,17 +97,26 @@ struct RootView: View {
.environmentObject(navigation)
.modifier(AlertHandler())
.modifier(ExternalLinkHandler())
.modifier(OpenFileHandler())
.onChange(of: scenePhase) { newScenePhase in
guard newScenePhase == .inactive else { return }
WebViewCache.shared.persistStates()
}
.onOpenURL { url in
NotificationCenter.openURL(url)
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 case let .tab(tabID) = navigation.currentItem {
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()
Expand Down
9 changes: 4 additions & 5 deletions App/App_macOS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ struct Kiwix: App {
}.commands {
SidebarCommands()
CommandGroup(replacing: .importExport) {
FileImportButton { Text("Open...") }
OpenFileButton(context: .command) { Text("Open...") }
}
CommandGroup(replacing: .newItem) {
Button("New Tab") {
Expand Down Expand Up @@ -128,13 +128,12 @@ struct RootView: View {
.environmentObject(navigation)
.modifier(AlertHandler())
.modifier(ExternalLinkHandler())
.modifier(OpenFileHandler())
.onOpenURL { url in
if url.isFileURL {
guard let metadata = ZimFileService.getMetaData(url: url) else { return }
LibraryOperations.open(url: url)
// self.url = ZimFileService.shared.getMainPageURL(zimFileID: metadata.fileID)
NotificationCenter.openFiles([url], context: .file)
} else if url.scheme == "kiwix" {
NotificationCenter.default.post(name: Notification.Name.openURL, object: nil, userInfo: ["url": url])
NotificationCenter.openURL(url)
}
}
.onReceive(openURL) { notification in
Expand Down
12 changes: 6 additions & 6 deletions Kiwix.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
9753D94B285B56C900A626CC /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = 9753D94A285B56C900A626CC /* Defaults */; };
97659CAC28DF817D002E6CE4 /* SearchResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 976A65B22659489F009A97C6 /* SearchResult.swift */; };
97659CAD28DF817D002E6CE4 /* SearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 97B3998C2467561900BC6F5B /* SearchResult.m */; };
97677B572A8FA80000F523AB /* FileImport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97677B562A8FA80000F523AB /* FileImport.swift */; };
9767E7862A72A21300C5082D /* App_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9767E7852A72A21300C5082D /* App_iOS.swift */; };
9767E78C2A75420400C5082D /* TabsManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9767E78B2A75420400C5082D /* TabsManagement.swift */; };
9767E7902A756CEE00C5082D /* NavigationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9767E78F2A756CEE00C5082D /* NavigationViewModel.swift */; };
Expand Down Expand Up @@ -96,7 +97,6 @@
97DE2BA02839D7AA00C63D9B /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97FD2F5E251EA07B0034927C /* FeatureFlags.swift */; };
97DE2BA3283A8E5C00C63D9B /* LibraryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97DE2BA1283A8E5C00C63D9B /* LibraryViewModel.swift */; };
97DE2BA6283A944100C63D9B /* GridCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97DE2BA4283A944100C63D9B /* GridCommon.swift */; };
97DE2BA7283AB6DC00C63D9B /* Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978A731127B9A0E0008101B4 /* Buttons.swift */; };
97DE2BAD283B133700C63D9B /* wikipedia_dark.css in Resources */ = {isa = PBXBuildFile; fileRef = 970885D0271339A300C5795C /* wikipedia_dark.css */; };
97E8033E2A7BD80F00DD251D /* LegacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97E8033D2A7BD80F00DD251D /* LegacyView.swift */; };
97F3333028AFC1A2007FF53C /* SearchResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97F3332E28AFC1A2007FF53C /* SearchResults.swift */; };
Expand Down Expand Up @@ -196,6 +196,7 @@
975088BC287DA10800273181 /* LibraryLastRefreshTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryLastRefreshTime.swift; sourceTree = "<group>"; };
9753D947285B55F100A626CC /* DefaultKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultKeys.swift; sourceTree = "<group>"; };
975FDB061F608F4100A10E8C /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
97677B562A8FA80000F523AB /* FileImport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileImport.swift; sourceTree = "<group>"; };
9767E7852A72A21300C5082D /* App_iOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App_iOS.swift; sourceTree = "<group>"; };
9767E78B2A75420400C5082D /* TabsManagement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsManagement.swift; sourceTree = "<group>"; };
9767E78F2A756CEE00C5082D /* NavigationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationViewModel.swift; sourceTree = "<group>"; };
Expand All @@ -212,7 +213,6 @@
9779A7E224567A5A00F6F6FF /* Log.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = "<group>"; };
977B1B63289801DE001D07C4 /* Map.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Map.swift; sourceTree = "<group>"; };
978A730F27B99F25008101B4 /* ReaderViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderViewModel.swift; sourceTree = "<group>"; };
978A731127B9A0E0008101B4 /* Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Buttons.swift; sourceTree = "<group>"; };
9790926E286BF0BB002B7AA5 /* Formatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Formatter.swift; sourceTree = "<group>"; };
9790CA5828A05EBB00D39FC6 /* ZimFilesCategories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZimFilesCategories.swift; sourceTree = "<group>"; };
97B0737527825E3D007C7DF3 /* Favicon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Favicon.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -380,6 +380,7 @@
9724FC2E28D5F5BE001B7DD2 /* BookmarkContextMenu.swift */,
97486D09284B96690096E4DD /* CellBackground.swift */,
972727BA2A89930600BCAF75 /* ExternalLinkHandler.swift */,
97677B562A8FA80000F523AB /* FileImport.swift */,
97DE2BA4283A944100C63D9B /* GridCommon.swift */,
);
path = ViewModifiers;
Expand Down Expand Up @@ -411,7 +412,6 @@
isa = PBXGroup;
children = (
97486D05284A36790096E4DD /* ArticleCell.swift */,
978A731127B9A0E0008101B4 /* Buttons.swift */,
97341C6C2852248500BC273E /* DownloadTaskCell.swift */,
97B0737527825E3D007C7DF3 /* Favicon.swift */,
973A2FCD277FB03F00BD4320 /* FlavorTag.swift */,
Expand Down Expand Up @@ -745,7 +745,6 @@
97E8033E2A7BD80F00DD251D /* LegacyView.swift in Sources */,
97B605A92A8DA32100317489 /* ContainerView.swift in Sources */,
9790CA5A28A05EBB00D39FC6 /* ZimFilesCategories.swift in Sources */,
97DE2BA7283AB6DC00C63D9B /* Buttons.swift in Sources */,
97486D08284A42B90096E4DD /* SearchResultRow.swift in Sources */,
9753D949285B55F100A626CC /* DefaultKeys.swift in Sources */,
973A0DE4281D80E300B41E71 /* ZimFileDetail.swift in Sources */,
Expand Down Expand Up @@ -818,6 +817,7 @@
973A0DE7281DC8F400B41E71 /* DownloadService.swift in Sources */,
9721BBB72841C16D005C910D /* Message.swift in Sources */,
97BD6C9D2886E06B004A8532 /* HTMLParser.swift in Sources */,
97677B572A8FA80000F523AB /* FileImport.swift in Sources */,
972727AA2A89122F00BCAF75 /* App_macOS.swift in Sources */,
97DE2BA3283A8E5C00C63D9B /* LibraryViewModel.swift in Sources */,
97DE2BA02839D7AA00C63D9B /* FeatureFlags.swift in Sources */,
Expand Down Expand Up @@ -953,7 +953,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.1.1;
MARKETING_VERSION = 3.2;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = self.Kiwix;
Expand Down Expand Up @@ -999,7 +999,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 3.1.1;
MARKETING_VERSION = 3.2;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = self.Kiwix;
PRODUCT_NAME = Kiwix;
Expand Down
1 change: 0 additions & 1 deletion Model/Entities/Entities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ class OutlineItem: ObservableObject, Identifiable {

class Tab: NSManagedObject, Identifiable {
@NSManaged var created: Date
@NSManaged var id: UUID
@NSManaged var interactionState: Data?
@NSManaged var lastOpened: Date
@NSManaged var title: String?
Expand Down
2 changes: 1 addition & 1 deletion Support/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<key>CFBundleTypeName</key>
<string>OpenZIM Content File</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>org.openzim.zim</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,13 @@
</entity>
<entity name="Tab" representedClassName=".Tab" syncable="YES">
<attribute name="created" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="id" attributeType="UUID" usesScalarValueType="NO"/>
<attribute name="interactionState" optional="YES" attributeType="Binary"/>
<attribute name="lastOpened" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="title" optional="YES" attributeType="String"/>
<relationship name="zimFile" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="ZimFile" inverseName="tabs" inverseEntity="ZimFile"/>
<fetchIndex name="created">
<fetchIndexElement property="created" type="Binary" order="ascending"/>
</fetchIndex>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="id"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="ZimFile" representedClassName=".ZimFile" syncable="YES">
<attribute name="articleCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
Expand Down
7 changes: 7 additions & 0 deletions SwiftUI/Model/Enum.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ enum ExternalLinkLoadingPolicy: String, CaseIterable, Identifiable, Defaults.Ser
}
}

enum OpenFileContext: String {
case command
case file
case onBoarding
case library
}

enum Flavor: String, CustomStringConvertible {
case max = "maxi"
case noPic = "nopic"
Expand Down
10 changes: 7 additions & 3 deletions SwiftUI/Model/LibraryOperations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@ struct LibraryOperations {

/// Open a zim file with url
/// - Parameter url: url of the zim file
static func open(url: URL) {
@discardableResult
static func open(url: URL) -> ZimFileMetaData? {
guard let metadata = ZimFileService.getMetaData(url: url),
let fileURLBookmark = ZimFileService.getBookmarkData(url: url) else { return }
let fileURLBookmark = ZimFileService.getBookmarkData(url: url) else { return nil }

// open the file
do {
try ZimFileService.shared.open(bookmark: fileURLBookmark)
} catch {
return
return nil
}

// upsert zim file in the database
Expand All @@ -44,6 +46,8 @@ struct LibraryOperations {
zimFile.isMissing = false
if context.hasChanges { try? context.save() }
}

return metadata
}

/// Reopen zim files from url bookmark data.
Expand Down
9 changes: 7 additions & 2 deletions SwiftUI/Patches.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ extension Color {
extension Notification.Name {
static let alert = Notification.Name("alert")
static let externalLink = Notification.Name("externalLink")
static let openFiles = Notification.Name("openFiles")
static let openURL = Notification.Name("openURL")
}

Expand All @@ -71,8 +72,12 @@ extension UTType {
}

extension NotificationCenter {
static func openURL(_ url: URL?) {
static func openURL(_ url: URL?, inNewTab: Bool = false) {
guard let url else { return }
NotificationCenter.default.post(name: .openURL, object: nil, userInfo: ["url": url])
NotificationCenter.default.post(name: .openURL, object: nil, userInfo: ["url": url, "inNewTab": inNewTab])
}

static func openFiles(_ urls: [URL], context: OpenFileContext) {
NotificationCenter.default.post(name: .openFiles, object: nil, userInfo: ["urls": urls, "context": context])
}
}
1 change: 0 additions & 1 deletion ViewModel/NavigationViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class NavigationViewModel: ObservableObject {

private func makeTab(context: NSManagedObjectContext) -> Tab {
let tab = Tab(context: context)
tab.id = UUID()
tab.created = Date()
tab.lastOpened = Date()
return tab
Expand Down
2 changes: 1 addition & 1 deletion Views/Browser/Welcome.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ struct Welcome: View {
/// Onboarding actions, open a zim file or refresh catalog
private var actions: some View {
HStack {
FileImportButton {
OpenFileButton(context: .onBoarding) {
HStack {
Spacer()
Text("Open File")
Expand Down
45 changes: 0 additions & 45 deletions Views/BuildingBlocks/Buttons.swift

This file was deleted.

9 changes: 4 additions & 5 deletions Views/Library/ZimFilesOpened.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,25 @@ struct ZimFilesOpened: View {
.navigationTitle(NavigationItem.opened.name)
.toolbar {
Button {
// On iOS 14 & 15, fileimporter's isPresented binding is not reset to false if user swipe to dismiss
// On iOS/iPadOS 15, fileimporter's isPresented binding is not reset to false if user swipe to dismiss
// the sheet. In order to mitigate the issue, the binding is set to false then true with a 0.1s delay.
isFileImporterPresented = false
DispatchQueue.main.asyncAfter(deadline: .now()+0.1) {
isFileImporterPresented = true
}
isFileImporterPresented = true
} label: {
Label("Open...", systemImage: "plus")
}.help("Open a zim file")
}
// not using FileImportButton here, because it does not work on iOS/iPadOS, since this view is in a modal
// not using OpenFileButton here, because it does not work on iOS/iPadOS 15, since this view is in a modal
.fileImporter(
isPresented: $isFileImporterPresented,
allowedContentTypes: [UTType.zimFile],
allowsMultipleSelection: true
) { result in
guard case let .success(urls) = result else { return }
for url in urls {
LibraryOperations.open(url: url)
}
NotificationCenter.openFiles(urls, context: .library)
}
}
}
Loading

0 comments on commit 20d4ef2

Please sign in to comment.