diff --git a/Reader/SceneDelegate.swift b/Reader/SceneDelegate.swift index 7a14268..9f7e5af 100644 --- a/Reader/SceneDelegate.swift +++ b/Reader/SceneDelegate.swift @@ -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") +} diff --git a/Reader/Screens/Home/HomeViewController.swift b/Reader/Screens/Home/HomeViewController.swift index 49efe91..e6fcf21 100644 --- a/Reader/Screens/Home/HomeViewController.swift +++ b/Reader/Screens/Home/HomeViewController.swift @@ -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 diff --git a/Reader/Screens/Read/ReadViewController.swift b/Reader/Screens/Read/ReadViewController.swift index 3c86faf..30aff00 100644 --- a/Reader/Screens/Read/ReadViewController.swift +++ b/Reader/Screens/Read/ReadViewController.swift @@ -393,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 @@ -403,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 diff --git a/Reader/StretchyMenuInteraction.swift b/Reader/StretchyMenuInteraction.swift index 841af89..6a46cea 100644 --- a/Reader/StretchyMenuInteraction.swift +++ b/Reader/StretchyMenuInteraction.swift @@ -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! + }) + } +}