mirror of
https://github.com/kiwix/kiwix-apple.git
synced 2025-09-22 02:52:39 -04:00
Move macOS parts to viewModifiers
This commit is contained in:
parent
1cc07a85b3
commit
084d210326
@ -24,7 +24,7 @@ struct SearchResults: View {
|
||||
@Environment(\.managedObjectContext) private var managedObjectContext
|
||||
@EnvironmentObject private var viewModel: SearchViewModel
|
||||
@EnvironmentObject private var navigation: NavigationViewModel
|
||||
@FocusState private var focusedSearchItem: URL?
|
||||
@FocusState private var focusedSearchItem: URL? // macOS only
|
||||
@FetchRequest(
|
||||
sortDescriptors: [NSSortDescriptor(keyPath: \ZimFile.size, ascending: false)],
|
||||
predicate: ZimFile.Predicate.isDownloaded,
|
||||
@ -92,23 +92,26 @@ struct SearchResults: View {
|
||||
ArticleCell(result: result, zimFile: viewModel.zimFiles[result.zimFileID])
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.id(result.url)
|
||||
.focusable()
|
||||
.focused($focusedSearchItem, equals: result.url)
|
||||
.modifier(KeyPressHandler(key: .return, action: {
|
||||
NotificationCenter.openURL(result.url)
|
||||
}))
|
||||
.modifier(KeyPressHandler(key: .escape, action: {
|
||||
$focusedSearchItem.wrappedValue = nil
|
||||
dismissSearch()
|
||||
}))
|
||||
.modifier(
|
||||
Focusable( // macOS only
|
||||
$focusedSearchItem,
|
||||
equals: result.url,
|
||||
onReturn: {
|
||||
NotificationCenter.openURL(result.url)
|
||||
},
|
||||
onDismiss: {
|
||||
$focusedSearchItem.wrappedValue = nil
|
||||
dismissSearch()
|
||||
})
|
||||
)
|
||||
}
|
||||
}.padding()
|
||||
}
|
||||
.onReceive(self.focusedSearchItem.publisher) { focusedURL in
|
||||
scrollReader.scrollTo(focusedURL, anchor: .center)
|
||||
}
|
||||
.onMoveCommand { direction in
|
||||
.modifier(MoveCommand(perform: { direction in
|
||||
// macOS only
|
||||
if let focusedSearchItem,
|
||||
let index = viewModel.results.firstIndex(where: { $0.url == focusedSearchItem }) {
|
||||
let nextIndex: Int
|
||||
@ -121,7 +124,7 @@ struct SearchResults: View {
|
||||
$focusedSearchItem.wrappedValue = viewModel.results[nextIndex].url
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,7 +163,7 @@ struct SearchResults: View {
|
||||
} header: { searchFilterHeader }
|
||||
}
|
||||
}
|
||||
.focusable(false)
|
||||
.modifier(NotFocusable()) // macOS only
|
||||
}
|
||||
|
||||
private var recentSearchHeader: some View {
|
||||
|
65
Views/ViewModifiers/Focusable.swift
Normal file
65
Views/ViewModifiers/Focusable.swift
Normal file
@ -0,0 +1,65 @@
|
||||
// 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/.
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct NotFocusable: ViewModifier {
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
#if os(macOS)
|
||||
content.focusable(false)
|
||||
#else
|
||||
content
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
struct Focusable<Value: Hashable>: ViewModifier {
|
||||
|
||||
private let value: Value
|
||||
private let focusState: FocusState<Value>.Binding
|
||||
private let onReturn: () -> Void
|
||||
private let onDissmiss: () -> Void
|
||||
|
||||
init(
|
||||
_ binding: FocusState<Value>.Binding,
|
||||
equals value: Value,
|
||||
onReturn: @escaping () -> Void,
|
||||
onDismiss: @escaping () -> Void
|
||||
) {
|
||||
self.focusState = binding
|
||||
self.value = value
|
||||
self.onReturn = onReturn
|
||||
self.onDissmiss = onDismiss
|
||||
}
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
#if os(macOS)
|
||||
content
|
||||
.id(value)
|
||||
.focusable()
|
||||
.focused(focusState, equals: value)
|
||||
.modifier(KeyPressHandler(key: .return, action: {
|
||||
onReturn()
|
||||
}))
|
||||
.modifier(KeyPressHandler(key: .escape, action: {
|
||||
onDissmiss()
|
||||
}))
|
||||
#else
|
||||
content
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
@ -21,15 +21,19 @@ struct KeyPressHandler: ViewModifier {
|
||||
let action: () -> Void
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
#if os(macOS)
|
||||
if #available(macOS 14.0, *) {
|
||||
mac14(content: content)
|
||||
newApi(content: content)
|
||||
} else {
|
||||
content
|
||||
}
|
||||
#else
|
||||
content
|
||||
#endif
|
||||
}
|
||||
|
||||
@available(macOS 14.0, *)
|
||||
private func mac14(content: Content) -> some View {
|
||||
@available(macOS 14.0, iOS 17.0, *)
|
||||
private func newApi(content: Content) -> some View {
|
||||
content.onKeyPress(key, action: {
|
||||
Task { await MainActor.run {
|
||||
action()
|
||||
|
57
Views/ViewModifiers/MoveCommand.swift
Normal file
57
Views/ViewModifiers/MoveCommand.swift
Normal file
@ -0,0 +1,57 @@
|
||||
// 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/.
|
||||
|
||||
import SwiftUI
|
||||
|
||||
enum MoveDirection: Sendable {
|
||||
|
||||
case up
|
||||
case down
|
||||
case left
|
||||
case right
|
||||
|
||||
#if os(macOS)
|
||||
init?(from direction: MoveCommandDirection) {
|
||||
switch direction {
|
||||
case .up: self = .up
|
||||
case .down: self = .down
|
||||
case .left: self = .left
|
||||
case .right: self = .right
|
||||
@unknown default: return nil
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct MoveCommand: ViewModifier {
|
||||
|
||||
private let action: ((MoveDirection) -> Void)?
|
||||
|
||||
init(perform action: ((MoveDirection) -> Void)?) {
|
||||
self.action = action
|
||||
}
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
#if os(macOS)
|
||||
content.onMoveCommand { (direction: MoveCommandDirection) in
|
||||
if let mappedDirection = MoveDirection(from: direction) {
|
||||
action?(mappedDirection)
|
||||
}
|
||||
}
|
||||
#else
|
||||
content
|
||||
#endif
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user