Compare commits

...

4 Commits

7 changed files with 112 additions and 16 deletions

View File

@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
<key>NSUserActivityTypes</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).activity.activate-account</string>

View File

@ -71,6 +71,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
NotificationCenter.default.addObserver(self, selector: #selector(updateAppearance), name: .appearanceChanged, object: nil)
updateAppearance()
NotificationCenter.default.addObserver(self, selector: #selector(logoutIfNecessary), name: .logoutAccount, object: nil)
}
func sceneDidDisconnect(_ scene: UIScene) {
@ -256,6 +257,21 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
createAppUI()
syncFromServer()
}
@objc private func logoutIfNecessary(_ notification: Notification) {
guard let account = notification.object as? LocalData.Account else {
return
}
if fervorController.account?.id == account.id {
if let next = LocalData.mostRecentAccount() ?? LocalData.accounts.first {
Task {
await switchToAccount(next)
}
} else {
createLoginUI()
}
}
}
}
@ -307,3 +323,7 @@ extension SceneDelegate: NSToolbarDelegate {
}
}
#endif
extension Notification.Name {
static let logoutAccount = Notification.Name("logoutAccount")
}

View File

@ -12,6 +12,14 @@ class AppNavigationController: UINavigationController, UINavigationControllerDel
private var statusBarBlockingView: UIView!
static let panRecognizerName = "AppNavPanRecognizer"
override var childForStatusBarHidden: UIViewController? {
topViewController
}
override var childForStatusBarStyle: UIViewController? {
topViewController
}
override func viewDidLoad() {
super.viewDidLoad()
@ -24,6 +32,7 @@ class AppNavigationController: UINavigationController, UINavigationControllerDel
let recognizer = UIPanGestureRecognizer(target: self, action: #selector(panGestureRecognized))
recognizer.allowedScrollTypesMask = .continuous
recognizer.name = AppNavigationController.panRecognizerName
recognizer.delegate = self
view.addGestureRecognizer(recognizer)
isNavigationBarHidden = true
@ -44,7 +53,12 @@ class AppNavigationController: UINavigationController, UINavigationControllerDel
}
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
statusBarBlockingView.isHidden = viewController.prefersStatusBarHidden
statusBarBlockingView.layer.opacity = viewController.prefersStatusBarHidden ? 0 : 1
}
override func setNeedsStatusBarAppearanceUpdate() {
super.setNeedsStatusBarAppearanceUpdate()
statusBarBlockingView?.layer.opacity = childForStatusBarHidden!.prefersStatusBarHidden ? 0 : 1
}
private var poppingViewController: UIViewController?
@ -127,3 +141,13 @@ class AppNavigationController: UINavigationController, UINavigationControllerDel
}
}
extension AppNavigationController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if String(describing: type(of: otherGestureRecognizer)) == "_UISwipeActionPanGestureRecognizer" {
return true
} else {
return false
}
}
}

View File

@ -17,6 +17,14 @@ class AppSplitViewController: UISplitViewController {
private var secondaryNav: UINavigationController!
override var childForStatusBarHidden: UIViewController? {
if traitCollection.horizontalSizeClass == .compact {
return viewController(for: .compact)
} else {
return nil
}
}
init(fervorController: FervorController) {
self.fervorController = fervorController

View File

@ -306,12 +306,21 @@ extension HomeViewController: StretchyMenuInteractionDelegate {
title += ":\(port)"
}
let subtitle = account.id == fervorController.account!.id ? "Currently logged in" : nil
return StretchyMenuItem(title: title, subtitle: subtitle) { [unowned self] in
let menu = UIMenu(children: [
UIAction(title: "Log Out", image: UIImage(systemName: "door.left.hand.open"), handler: { _ in
guard let index = LocalData.accounts.firstIndex(where: { $0.id == account.id }) else {
return
}
LocalData.accounts.remove(at: index)
NotificationCenter.default.post(name: .logoutAccount, object: account)
})
])
return StretchyMenuItem(title: title, subtitle: subtitle, menu: menu) { [unowned self] in
guard account.id != self.fervorController.account!.id else { return }
self.delegate?.switchToAccount(account)
}
}
items.append(StretchyMenuItem(title: "Add Account", subtitle: nil, action: { [unowned self] in
items.append(StretchyMenuItem(title: "Add Account", action: { [unowned self] in
let login = LoginViewController()
login.delegate = self
login.navigationItem.leftBarButtonItem = UIBarButtonItem(systemItem: .cancel, primaryAction: UIAction(handler: { (_) in

View File

@ -30,12 +30,14 @@ class ReadViewController: UIViewController {
private var webView: WKWebView!
#if targetEnvironment(macCatalyst)
private var itemReadObservation: NSKeyValueObservation?
#endif
override var prefersStatusBarHidden: Bool {
navigationController?.isNavigationBarHidden ?? false
if navigationController?.isNavigationBarHidden == true,
let webView,
webView.scrollView.contentOffset.y > -webView.scrollView.safeAreaInsets.top {
return true
} else {
return false
}
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
@ -72,10 +74,7 @@ class ReadViewController: UIViewController {
webView.isOpaque = false
webView.backgroundColor = .clear
if #available(iOS 16.0, *) {
// TODO: Xcode 14 RC doesn't have the macOS 13 SDK, so we can't use this
#if !targetEnvironment(macCatalyst)
webView.isFindInteractionEnabled = true
#endif
}
if let content = itemContentHTML() {
webView.loadHTMLString(content, baseURL: item.url)
@ -98,6 +97,18 @@ class ReadViewController: UIViewController {
activityItemsConfiguration = UIActivityItemsConfiguration(objects: [url as NSURL])
}
webView.scrollView.publisher(for: \.contentOffset)
.map { [unowned self] _ in
self.prefersStatusBarHidden
}
.removeDuplicates()
.sink { [unowned self] _ in
UIView.animate(withDuration: 0.2, delay: 0) {
self.setNeedsStatusBarAppearanceUpdate()
}
}
.store(in: &cancellables)
scrollPositionChangedSubject
.debounce(for: .milliseconds(500), scheduler: RunLoop.main)
.sink { [unowned self] in
@ -106,9 +117,11 @@ class ReadViewController: UIViewController {
.store(in: &cancellables)
#if targetEnvironment(macCatalyst)
itemReadObservation = item.observe(\.read) { [unowned self] _, _ in
self.updateToggleReadToolbarImage()
}
item.publisher(for: \.read)
.sink { [unowned self] _ in
self.updateToggleReadToolbarImage()
}
.store(in: &cancellables)
#endif
}
@ -380,7 +393,7 @@ extension ReadViewController: StretchyMenuInteractionDelegate {
return []
}
var items = [
StretchyMenuItem(title: "Open in Safari", subtitle: nil, action: { [unowned self] in
StretchyMenuItem(title: "Open in Safari", action: { [unowned self] in
self.present(createSafariVC(url: url), animated: true)
}),
StretchyMenuItem(title: item.read ? "Mark as Unread" : "Mark as Read", subtitle: nil, action: { [unowned self] in
@ -390,7 +403,7 @@ extension ReadViewController: StretchyMenuInteractionDelegate {
}),
]
#if !targetEnvironment(macCatalyst)
items.insert(StretchyMenuItem(title: "Share", subtitle: nil, action: { [unowned self] in
items.insert(StretchyMenuItem(title: "Share", action: { [unowned self] in
self.present(UIActivityViewController(activityItems: [url], applicationActivities: nil), animated: true)
}), at: 1)
#endif

View File

@ -10,7 +10,15 @@ import UIKit
struct StretchyMenuItem {
let title: String
let subtitle: String?
let menu: UIMenu?
let action: () -> Void
init(title: String, subtitle: String? = nil, menu: UIMenu? = nil, action: @escaping () -> Void) {
self.title = title
self.subtitle = subtitle
self.menu = menu
self.action = action
}
}
protocol StretchyMenuInteractionDelegate: AnyObject {
@ -350,6 +358,10 @@ private class MenuItemView: UIView {
])
}
if item.menu != nil {
addInteraction(UIContextMenuInteraction(delegate: self))
}
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(itemTapped)))
}
@ -403,3 +415,11 @@ private class MenuItemView: UIView {
}
}
extension MenuItemView: UIContextMenuInteractionDelegate {
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
return UIContextMenuConfiguration(actionProvider: { [unowned self] _ in
return self.item.menu!
})
}
}