More catalyst toolbar stuff
This commit is contained in:
parent
1d2e666c00
commit
36fda4d51f
|
@ -13,6 +13,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||||
var window: UIWindow?
|
var window: UIWindow?
|
||||||
|
|
||||||
private(set) var fervorController: FervorController!
|
private(set) var fervorController: FervorController!
|
||||||
|
private(set) var toggleReadBarButtonItem: UIBarButtonItem?
|
||||||
|
|
||||||
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "SceneDelegate")
|
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "SceneDelegate")
|
||||||
|
|
||||||
|
@ -144,23 +145,31 @@ extension SceneDelegate: HomeViewControllerDelegate {
|
||||||
#if targetEnvironment(macCatalyst)
|
#if targetEnvironment(macCatalyst)
|
||||||
extension NSToolbarItem.Identifier {
|
extension NSToolbarItem.Identifier {
|
||||||
static let toggleItemRead = NSToolbarItem.Identifier("ToggleItemRead")
|
static let toggleItemRead = NSToolbarItem.Identifier("ToggleItemRead")
|
||||||
|
static let shareItem = NSToolbarItem.Identifier("ShareItem")
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SceneDelegate: NSToolbarDelegate {
|
extension SceneDelegate: NSToolbarDelegate {
|
||||||
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
|
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
|
||||||
let item = NSToolbarItem(itemIdentifier: .toggleItemRead)
|
if itemIdentifier == .toggleItemRead {
|
||||||
item.target = nil
|
// need an item bar button item to make the size of the image match the share button
|
||||||
item.action = #selector(AppSplitViewController.toggleItemRead)
|
let item = NSToolbarItem(itemIdentifier: .toggleItemRead, barButtonItem: UIBarButtonItem(image: nil, style: .plain, target: nil, action: nil))
|
||||||
item.image = UIImage(systemName: "checkmark.circle")
|
item.image = UIImage(systemName: "checkmark.circle")
|
||||||
return item
|
item.target = nil
|
||||||
|
item.action = #selector(ReadViewController.toggleItemRead(_:))
|
||||||
|
return item
|
||||||
|
} else if itemIdentifier == .shareItem {
|
||||||
|
return NSSharingServicePickerToolbarItem(itemIdentifier: .shareItem)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||||
return [.toggleItemRead]
|
return [.shareItem, .toggleItemRead]
|
||||||
}
|
}
|
||||||
|
|
||||||
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
||||||
return [.toggleItemRead]
|
return [.shareItem, .toggleItemRead]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -51,55 +51,12 @@ class AppSplitViewController: UISplitViewController {
|
||||||
let nav = AppNavigationController(rootViewController: home)
|
let nav = AppNavigationController(rootViewController: home)
|
||||||
setViewController(nav, for: .compact)
|
setViewController(nav, for: .compact)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if targetEnvironment(macCatalyst)
|
|
||||||
@objc func toggleItemRead(_ item: NSToolbarItem) {
|
|
||||||
guard let nav = viewController(for: .secondary) as? UINavigationController,
|
|
||||||
let read = nav.topViewController as? ReadViewController else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
Task {
|
|
||||||
await fervorController.markItem(read.item, read: !read.item.read)
|
|
||||||
updateImage(toolbarItem: item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func updateImage(toolbarItem: NSToolbarItem) {
|
|
||||||
if let nav = viewController(for: .secondary) as? UINavigationController,
|
|
||||||
let read = nav.topViewController as? ReadViewController {
|
|
||||||
toolbarItem.image = UIImage(systemName: read.item.read ? "checkmark.circle.fill" : "checkmark.circle")
|
|
||||||
} else {
|
|
||||||
toolbarItem.image = UIImage(systemName: "checkmark.circle")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppSplitViewController: ItemsViewControllerDelegate {
|
extension AppSplitViewController: ItemsViewControllerDelegate {
|
||||||
func showReadItem(_ item: Item) {
|
func showReadItem(_ item: Item) {
|
||||||
secondaryNav.setViewControllers([ReadViewController(item: item, fervorController: fervorController)], animated: false)
|
secondaryNav.setViewControllers([ReadViewController(item: item, fervorController: fervorController)], animated: false)
|
||||||
|
|
||||||
#if targetEnvironment(macCatalyst)
|
|
||||||
if let titlebar = view.window?.windowScene?.titlebar,
|
|
||||||
let toggleRead = titlebar.toolbar?.items.first(where: { $0.itemIdentifier == .toggleItemRead }) {
|
|
||||||
updateImage(toolbarItem: toggleRead)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if targetEnvironment(macCatalyst)
|
|
||||||
extension AppSplitViewController {
|
|
||||||
override func responds(to aSelector: Selector!) -> Bool {
|
|
||||||
if aSelector == #selector(toggleItemRead) {
|
|
||||||
guard let nav = viewController(for: .secondary) as? UINavigationController else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return nav.topViewController is ReadViewController
|
|
||||||
} else {
|
|
||||||
return super.responds(to: aSelector)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -87,18 +87,21 @@ class ItemCollectionViewCell: UICollectionViewListCell {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setRead(_ read: Bool, animated: Bool) {
|
func setRead(_ read: Bool, animated: Bool) {
|
||||||
guard self.item.read != read else { return }
|
guard item.read != read else { return }
|
||||||
Task {
|
|
||||||
await self.delegate?.fervorController.markItem(self.item, read: read)
|
item.read = read
|
||||||
|
|
||||||
if animated {
|
if animated {
|
||||||
// i don't know why .transition works but .animate doesn't
|
// i don't know why .transition works but .animate doesn't
|
||||||
UIView.transition(with: self, duration: 0.2, options: .transitionCrossDissolve) {
|
UIView.transition(with: self, duration: 0.2, options: .transitionCrossDissolve) {
|
||||||
self.updateColors()
|
self.updateColors()
|
||||||
}
|
|
||||||
} else {
|
|
||||||
updateColors()
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
updateColors()
|
||||||
|
}
|
||||||
|
|
||||||
|
Task {
|
||||||
|
await delegate?.fervorController.markItem(item, read: read)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,16 +127,21 @@ extension ItemsViewController: UICollectionViewDelegate {
|
||||||
return UIContextMenuConfiguration(identifier: nil, previewProvider: {
|
return UIContextMenuConfiguration(identifier: nil, previewProvider: {
|
||||||
ReadViewController(item: item, fervorController: self.fervorController)
|
ReadViewController(item: item, fervorController: self.fervorController)
|
||||||
}, actionProvider: { _ in
|
}, actionProvider: { _ in
|
||||||
var children: [UIAction] = []
|
var children: [UIMenuElement] = []
|
||||||
if let url = item.url {
|
if let url = item.url {
|
||||||
children.append(UIAction(title: "Open in Safari", image: UIImage(systemName: "safari"), handler: { [weak self] _ in
|
children.append(UIAction(title: "Open in Safari", image: UIImage(systemName: "safari"), handler: { [weak self] _ in
|
||||||
let vc = SFSafariViewController(url: url)
|
let vc = SFSafariViewController(url: url)
|
||||||
vc.preferredControlTintColor = .appTintColor
|
vc.preferredControlTintColor = .appTintColor
|
||||||
self?.present(vc, animated: true)
|
self?.present(vc, animated: true)
|
||||||
}))
|
}))
|
||||||
|
#if targetEnvironment(macCatalyst)
|
||||||
|
self.activityItemsConfiguration = UIActivityItemsConfiguration(objects: [url as NSURL])
|
||||||
|
children.append(UICommand(title: "Share…", action: Selector(("unused")), propertyList: UICommandTagShare))
|
||||||
|
#else
|
||||||
children.append(UIAction(title: "Share", image: UIImage(systemName: "square.and.arrow.up"), handler: { [weak self] _ in
|
children.append(UIAction(title: "Share", image: UIImage(systemName: "square.and.arrow.up"), handler: { [weak self] _ in
|
||||||
self?.present(UIActivityViewController(activityItems: [url], applicationActivities: nil), animated: true)
|
self?.present(UIActivityViewController(activityItems: [url], applicationActivities: nil), animated: true)
|
||||||
}))
|
}))
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if item.read {
|
if item.read {
|
||||||
children.append(UIAction(title: "Mark as Unread", image: UIImage(systemName: "checkmark.circle"), handler: { [unowned self] _ in
|
children.append(UIAction(title: "Mark as Unread", image: UIImage(systemName: "checkmark.circle"), handler: { [unowned self] _ in
|
||||||
|
|
|
@ -22,6 +22,10 @@ class ReadViewController: UIViewController {
|
||||||
let fervorController: FervorController
|
let fervorController: FervorController
|
||||||
let item: Item
|
let item: Item
|
||||||
|
|
||||||
|
#if targetEnvironment(macCatalyst)
|
||||||
|
private var itemReadObservation: NSKeyValueObservation?
|
||||||
|
#endif
|
||||||
|
|
||||||
override var prefersStatusBarHidden: Bool {
|
override var prefersStatusBarHidden: Bool {
|
||||||
navigationController?.isNavigationBarHidden ?? false
|
navigationController?.isNavigationBarHidden ?? false
|
||||||
}
|
}
|
||||||
|
@ -68,6 +72,15 @@ class ReadViewController: UIViewController {
|
||||||
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
if let url = item.url {
|
||||||
|
activityItemsConfiguration = UIActivityItemsConfiguration(objects: [url as NSURL])
|
||||||
|
}
|
||||||
|
|
||||||
|
#if targetEnvironment(macCatalyst)
|
||||||
|
itemReadObservation = item.observe(\.read) { [unowned self] _, _ in
|
||||||
|
self.updateToggleReadToolbarImage()
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private static let css = try! String(contentsOf: Bundle.main.url(forResource: "read", withExtension: "css")!)
|
private static let css = try! String(contentsOf: Bundle.main.url(forResource: "read", withExtension: "css")!)
|
||||||
|
@ -125,6 +138,24 @@ class ReadViewController: UIViewController {
|
||||||
vc.preferredControlTintColor = .appTintColor
|
vc.preferredControlTintColor = .appTintColor
|
||||||
return vc
|
return vc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if targetEnvironment(macCatalyst)
|
||||||
|
@objc func toggleItemRead(_ item: NSToolbarItem) {
|
||||||
|
Task {
|
||||||
|
await fervorController.markItem(self.item, read: !self.item.read)
|
||||||
|
updateToggleReadToolbarImage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateToggleReadToolbarImage() {
|
||||||
|
guard let titlebar = view.window?.windowScene?.titlebar,
|
||||||
|
let item = titlebar.toolbar?.items.first(where: { $0.itemIdentifier == .toggleItemRead }) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
item.image = UIImage(systemName: self.item.read ? "checkmark.circle.fill" : "checkmark.circle")
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,18 +212,21 @@ extension ReadViewController: StretchyMenuInteractionDelegate {
|
||||||
guard let url = item.url else {
|
guard let url = item.url else {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
return [
|
var items = [
|
||||||
StretchyMenuItem(title: "Open in Safari", subtitle: nil, action: { [unowned self] in
|
StretchyMenuItem(title: "Open in Safari", subtitle: nil, action: { [unowned self] in
|
||||||
self.present(createSafariVC(url: url), animated: true)
|
self.present(createSafariVC(url: url), animated: true)
|
||||||
}),
|
}),
|
||||||
StretchyMenuItem(title: "Share", subtitle: nil, action: { [unowned self] in
|
|
||||||
self.present(UIActivityViewController(activityItems: [url], applicationActivities: nil), animated: true)
|
|
||||||
}),
|
|
||||||
StretchyMenuItem(title: item.read ? "Mark as Unread" : "Mark as Read", subtitle: nil, action: { [unowned self] in
|
StretchyMenuItem(title: item.read ? "Mark as Unread" : "Mark as Read", subtitle: nil, action: { [unowned self] in
|
||||||
Task {
|
Task {
|
||||||
await self.fervorController.markItem(item, read: !item.read)
|
await self.fervorController.markItem(item, read: !item.read)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
|
#if !targetEnvironment(macCatalyst)
|
||||||
|
items.insert(StretchyMenuItem(title: "Share", subtitle: nil, action: { [unowned self] in
|
||||||
|
self.present(UIActivityViewController(activityItems: [url], applicationActivities: nil), animated: true)
|
||||||
|
}), at: 1)
|
||||||
|
#endif
|
||||||
|
return items
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue