mirror of
https://github.com/kiwix/kiwix-apple.git
synced 2025-08-03 12:37:15 -04:00
Merge pull request #1258 from kiwix/1255-default-select-opened-file
Open ZimFileDetails when importing a single file
This commit is contained in:
commit
62e9a33308
@ -178,8 +178,13 @@ final class SplitViewController: UISplitViewController {
|
||||
}()
|
||||
setViewController(UINavigationController(rootViewController: controller), for: .secondary)
|
||||
case .opened:
|
||||
let controller = UIHostingController(rootView: ZimFilesOpened(dismiss: nil))
|
||||
setViewController(UINavigationController(rootViewController: controller), for: .secondary)
|
||||
// workaround for programatic triggering ZimFileDetails
|
||||
// on iPad full screen view
|
||||
let navHelper = NavigationHelper()
|
||||
let controller = UIHostingController(rootView: ZimFilesOpened(navigationHelper: navHelper))
|
||||
let navController = UINavigationController(rootViewController: controller)
|
||||
navHelper.navigationController = navController
|
||||
setViewController(navController, for: .secondary)
|
||||
case .categories:
|
||||
let controller = UIHostingController(rootView: ZimFilesCategories(dismiss: nil))
|
||||
setViewController(UINavigationController(rootViewController: controller), for: .secondary)
|
||||
|
@ -71,6 +71,7 @@ extension Notification.Name {
|
||||
static let alert = Notification.Name("alert")
|
||||
static let openFiles = Notification.Name("openFiles")
|
||||
static let openURL = Notification.Name("openURL")
|
||||
static let selectFile = Notification.Name("selectFile")
|
||||
static let exportFileData = Notification.Name("exportFileData")
|
||||
static let saveContent = Notification.Name("saveContent")
|
||||
static let toggleSidebar = Notification.Name("toggleSidebar")
|
||||
@ -111,6 +112,11 @@ extension NotificationCenter {
|
||||
)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
static func selectFileBy(fileId: UUID) {
|
||||
NotificationCenter.default.post(name: .selectFile, object: nil, userInfo: ["fileId": fileId])
|
||||
}
|
||||
|
||||
static func openFiles(_ urls: [URL], context: OpenFileContext) {
|
||||
NotificationCenter.default.post(name: .openFiles, object: nil, userInfo: ["urls": urls, "context": context])
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ struct Library: View {
|
||||
.listStyle(.plain)
|
||||
.navigationTitle(MenuItem.categories.name)
|
||||
case .opened:
|
||||
ZimFilesOpened(dismiss: dismiss)
|
||||
ZimFilesOpenedNavStack(dismiss: dismiss)
|
||||
case .downloads:
|
||||
ZimFilesDownloads(dismiss: dismiss)
|
||||
.environment(\.managedObjectContext, Database.shared.viewContext)
|
||||
|
@ -27,6 +27,8 @@ struct ZimFilesMultiOpened: View {
|
||||
) private var zimFiles: FetchedResults<ZimFile>
|
||||
@State private var isFileImporterPresented = false
|
||||
@StateObject private var selection = MultiSelectedZimFilesViewModel()
|
||||
private let selectFileById = NotificationCenter.default.publisher(for: .selectFile)
|
||||
@State private var fileIdToOpen: UUID?
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
@ -57,9 +59,23 @@ struct ZimFilesMultiOpened: View {
|
||||
Message(text: LocalString.zim_file_opened_overlay_no_opened_message)
|
||||
}
|
||||
}
|
||||
.onReceive(selectFileById, perform: { notification in
|
||||
guard let fileId = notification.userInfo?["fileId"] as? UUID else {
|
||||
fileIdToOpen = nil
|
||||
return
|
||||
}
|
||||
fileIdToOpen = fileId
|
||||
})
|
||||
.onChange(of: zimFiles.count) { _ in
|
||||
if let firstZimFile = zimFiles.first {
|
||||
selection.singleSelect(zimFile: firstZimFile)
|
||||
let selectedZimFile: ZimFile?
|
||||
if let fileIdToOpen {
|
||||
selectedZimFile = zimFiles.first { $0.fileID == fileIdToOpen }
|
||||
self.fileIdToOpen = nil
|
||||
} else {
|
||||
selectedZimFile = zimFiles.first
|
||||
}
|
||||
if let selectedZimFile {
|
||||
selection.singleSelect(zimFile: selectedZimFile)
|
||||
} else {
|
||||
selection.reset()
|
||||
}
|
||||
|
@ -17,8 +17,21 @@ import SwiftUI
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
#if os(iOS)
|
||||
|
||||
final class NavigationHelper {
|
||||
weak var navigationController: UINavigationController?
|
||||
func push<V: View>(@ViewBuilder _ view: () -> V) {
|
||||
let hostingVC = UIHostingController(rootView: view())
|
||||
navigationController?.pushViewController(hostingVC, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
/// A grid of zim files that are opened, or was open but is now missing
|
||||
/// iOS only
|
||||
/// iOS only, only iPad splitView
|
||||
/// the UINavigationController used in splitView doesn't work with
|
||||
/// NavigationStack
|
||||
/// therefore programatic selection of newly added file is with a
|
||||
/// workaround
|
||||
struct ZimFilesOpened: View {
|
||||
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
||||
@FetchRequest(
|
||||
@ -28,7 +41,9 @@ struct ZimFilesOpened: View {
|
||||
) private var zimFiles: FetchedResults<ZimFile>
|
||||
@State private var isFileImporterPresented = false
|
||||
@EnvironmentObject var selection: SelectedZimFileViewModel
|
||||
let dismiss: (() -> Void)? // iOS only
|
||||
let navigationHelper: NavigationHelper
|
||||
private let selectFileById = NotificationCenter.default.publisher(for: .selectFile)
|
||||
@State private var fileIdToOpen: UUID?
|
||||
|
||||
var body: some View {
|
||||
LazyVGrid(
|
||||
@ -37,17 +52,15 @@ struct ZimFilesOpened: View {
|
||||
spacing: 12
|
||||
) {
|
||||
ForEach(zimFiles) { zimFile in
|
||||
LibraryZimFileContext(
|
||||
content: {
|
||||
NavigationLink {
|
||||
ZimFileDetail(zimFile: zimFile, dismissParent: nil)
|
||||
} label: {
|
||||
ZimFileCell(
|
||||
zimFile,
|
||||
prominent: .name,
|
||||
isSelected: selection.isSelected(zimFile)
|
||||
)
|
||||
},
|
||||
zimFile: zimFile,
|
||||
selection: selection,
|
||||
dismiss: dismiss)
|
||||
} .accessibilityIdentifier(zimFile.name)
|
||||
}
|
||||
}
|
||||
.modifier(GridCommon(edges: .all))
|
||||
@ -58,13 +71,34 @@ struct ZimFilesOpened: View {
|
||||
Message(text: LocalString.zim_file_opened_overlay_no_opened_message)
|
||||
}
|
||||
}
|
||||
.onReceive(selectFileById, perform: { notification in
|
||||
guard let fileId = notification.userInfo?["fileId"] as? UUID else {
|
||||
fileIdToOpen = nil
|
||||
return
|
||||
}
|
||||
fileIdToOpen = fileId
|
||||
})
|
||||
.onChange(of: zimFiles.count) { _ in
|
||||
if let firstZimFile = zimFiles.first {
|
||||
selection.selectedZimFile = firstZimFile
|
||||
let selectedZimFile: ZimFile?
|
||||
if let fileIdToOpen {
|
||||
selectedZimFile = zimFiles.first { $0.fileID == fileIdToOpen }
|
||||
self.fileIdToOpen = nil
|
||||
} else {
|
||||
selectedZimFile = nil
|
||||
}
|
||||
if let selectedZimFile {
|
||||
selection.selectedZimFile = selectedZimFile
|
||||
} else {
|
||||
selection.reset()
|
||||
}
|
||||
}
|
||||
.onReceive(selection.$selectedZimFile, perform: { selectedZimFile in
|
||||
if let selectedZimFile {
|
||||
navigationHelper.push {
|
||||
ZimFileDetail(zimFile: selectedZimFile, dismissParent: nil)
|
||||
}
|
||||
}
|
||||
})
|
||||
// not using OpenFileButton here, because it does not work on iOS/iPadOS 15 when this view is in a modal
|
||||
.fileImporter(
|
||||
isPresented: $isFileImporterPresented,
|
||||
|
101
Views/Library/ZimFilesOpenedNavStack.swift
Normal file
101
Views/Library/ZimFilesOpenedNavStack.swift
Normal file
@ -0,0 +1,101 @@
|
||||
// This file is part of Kiwix for iOS & macOS.
|
||||
//
|
||||
// Kiwix is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kiwix is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kiwix; If not, see https://www.gnu.org/licenses/.
|
||||
|
||||
#if os(iOS)
|
||||
|
||||
import SwiftUI
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
/// A grid of zim files that are opened, or was open but is now missing
|
||||
/// iOS only
|
||||
struct ZimFilesOpenedNavStack: View {
|
||||
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
||||
@FetchRequest(
|
||||
sortDescriptors: [NSSortDescriptor(keyPath: \ZimFile.size, ascending: false)],
|
||||
predicate: ZimFile.Predicate.isDownloaded,
|
||||
animation: .easeInOut
|
||||
) private var zimFiles: FetchedResults<ZimFile>
|
||||
@State private var isFileImporterPresented = false
|
||||
@State private var navPath: [ZimFile] = []
|
||||
// opening the details of a freshly added zimFile
|
||||
private let selectFileById = NotificationCenter.default.publisher(for: .selectFile)
|
||||
@State private var fileIdToOpen: UUID?
|
||||
|
||||
let dismiss: (() -> Void)?
|
||||
|
||||
var body: some View {
|
||||
NavigationStack(path: $navPath) {
|
||||
LazyVGrid(
|
||||
columns: ([GridItem(.adaptive(minimum: 250, maximum: 500), spacing: 12)]),
|
||||
alignment: .leading,
|
||||
spacing: 12
|
||||
) {
|
||||
ForEach(zimFiles) { zimFile in
|
||||
NavigationLink(value: zimFile) {
|
||||
ZimFileCell(
|
||||
zimFile,
|
||||
prominent: .name,
|
||||
isSelected: navPath.contains(where: { $0.fileID == zimFile.fileID })
|
||||
)
|
||||
}.accessibilityIdentifier(zimFile.name)
|
||||
}
|
||||
}
|
||||
.navigationDestination(for: ZimFile.self) { zimFile in
|
||||
ZimFileDetail(zimFile: zimFile, dismissParent: dismiss)
|
||||
}
|
||||
}
|
||||
.modifier(GridCommon(edges: .all))
|
||||
.modifier(ToolbarRoleBrowser())
|
||||
.navigationTitle(MenuItem.opened.name)
|
||||
.overlay {
|
||||
if zimFiles.isEmpty {
|
||||
Message(text: LocalString.zim_file_opened_overlay_no_opened_message)
|
||||
}
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
Button {
|
||||
isFileImporterPresented = true
|
||||
} label: {
|
||||
Label(LocalString.zim_file_opened_toolbar_open_title, systemImage: "plus")
|
||||
}.help(LocalString.zim_file_opened_toolbar_open_help)
|
||||
}
|
||||
}
|
||||
// not using OpenFileButton here, because it does not work on iOS/iPadOS 15 when this view is in a modal
|
||||
.fileImporter(
|
||||
isPresented: $isFileImporterPresented,
|
||||
allowedContentTypes: [UTType.zimFile],
|
||||
allowsMultipleSelection: true
|
||||
) { result in
|
||||
guard case let .success(urls) = result else { return }
|
||||
NotificationCenter.openFiles(urls, context: .library)
|
||||
}
|
||||
.onReceive(selectFileById, perform: { notification in
|
||||
guard let fileId = notification.userInfo?["fileId"] as? UUID else {
|
||||
return
|
||||
}
|
||||
fileIdToOpen = fileId
|
||||
})
|
||||
.onChange(of: zimFiles.count) { _ in
|
||||
if let fileIdToOpen,
|
||||
let selectedZimFile = zimFiles.first(where: { $0.fileID == fileIdToOpen }) {
|
||||
self.fileIdToOpen = nil
|
||||
navPath = [selectedZimFile]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -81,6 +81,11 @@ struct OpenFileHandler: ViewModifier {
|
||||
// action for zim files that can be opened (e.g. open main page)
|
||||
if case .library = context {
|
||||
// don't need to open the main page
|
||||
// but we should select it to show the details
|
||||
// if there's only one ZIM file imported
|
||||
if openedZimFileIDs.count == 1, let firstFileID = openedZimFileIDs.first {
|
||||
NotificationCenter.selectFileBy(fileId: firstFileID)
|
||||
}
|
||||
} else {
|
||||
for fileID in openedZimFileIDs {
|
||||
if let url = await ZimFileService.shared.getMainPageURL(zimFileID: fileID) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user