mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Adds filtering and search to Notification Manager
This commit is contained in:
@@ -11,16 +11,46 @@ import Account
|
||||
import UserNotifications
|
||||
|
||||
class NotificationsViewController: UIViewController {
|
||||
|
||||
|
||||
@IBOutlet weak var notificationsTableView: UITableView!
|
||||
|
||||
private lazy var searchController: UISearchController = {
|
||||
let searchController = UISearchController(searchResultsController: nil)
|
||||
searchController.searchBar.placeholder = NSLocalizedString("Find a feed", comment: "Find a feed")
|
||||
searchController.searchBar.searchBarStyle = .minimal
|
||||
searchController.delegate = self
|
||||
searchController.searchBar.delegate = self
|
||||
searchController.searchBar.sizeToFit()
|
||||
searchController.obscuresBackgroundDuringPresentation = false
|
||||
searchController.hidesNavigationBarDuringPresentation = false
|
||||
self.definesPresentationContext = true
|
||||
return searchController
|
||||
}()
|
||||
private var status: UNAuthorizationStatus = .notDetermined
|
||||
private var newArticleNotificationFilter: Bool = false {
|
||||
didSet {
|
||||
filterButton.menu = notificationFilterMenu()
|
||||
}
|
||||
}
|
||||
private var filterButton: UIBarButtonItem!
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
title = NSLocalizedString("New Article Notifications", comment: "Notifications")
|
||||
|
||||
notificationsTableView.prefetchDataSource = self
|
||||
self.title = NSLocalizedString("New Article Notifications", comment: "Notifications")
|
||||
navigationItem.searchController = searchController
|
||||
|
||||
filterButton = UIBarButtonItem(
|
||||
title: nil,
|
||||
image: AppAssets.filterInactiveImage,
|
||||
primaryAction: nil,
|
||||
menu: notificationFilterMenu())
|
||||
|
||||
navigationItem.rightBarButtonItem = filterButton
|
||||
|
||||
reloadNotificationTableView()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(reloadNotificationTableView(_:)), name: UIScene.willEnterForegroundNotification, object: nil)
|
||||
}
|
||||
|
||||
@@ -29,18 +59,65 @@ class NotificationsViewController: UIViewController {
|
||||
UNUserNotificationCenter.current().getNotificationSettings { settings in
|
||||
DispatchQueue.main.async {
|
||||
self.status = settings.authorizationStatus
|
||||
if self.status != .authorized {
|
||||
self.filterButton.isEnabled = false
|
||||
self.newArticleNotificationFilter = false
|
||||
}
|
||||
self.notificationsTableView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func notificationFilterMenu() -> UIMenu {
|
||||
|
||||
if let filterButton = filterButton {
|
||||
if newArticleNotificationFilter == true {
|
||||
filterButton.image = AppAssets.filterActiveImage
|
||||
} else {
|
||||
filterButton.image = AppAssets.filterInactiveImage
|
||||
}
|
||||
}
|
||||
|
||||
let menu = UIMenu(title: "",
|
||||
image: nil,
|
||||
identifier: nil,
|
||||
options: [.displayInline],
|
||||
children: [
|
||||
UIAction(
|
||||
title: NSLocalizedString("Show Feeds with Notifications Enabled", comment: "Feeds with Notifications"),
|
||||
image: UIImage(systemName: "app.badge"),
|
||||
identifier: nil,
|
||||
discoverabilityTitle: nil,
|
||||
attributes: [],
|
||||
state: newArticleNotificationFilter ? .on : .off,
|
||||
handler: { [weak self] _ in
|
||||
self?.newArticleNotificationFilter.toggle()
|
||||
self?.notificationsTableView.reloadData()
|
||||
})])
|
||||
return menu
|
||||
}
|
||||
|
||||
// MARK: - Feed Filtering
|
||||
|
||||
private func sortedWebFeedsForAccount(_ account: Account) -> [WebFeed] {
|
||||
return Array(account.flattenedWebFeeds()).sorted(by: { $0.nameForDisplay.caseInsensitiveCompare($1.nameForDisplay) == .orderedAscending })
|
||||
}
|
||||
|
||||
|
||||
private func filteredWebFeeds(_ searchText: String? = "", account: Account) -> [WebFeed] {
|
||||
sortedWebFeedsForAccount(account).filter { feed in
|
||||
return feed.nameForDisplay.lowercased().contains(searchText!.lowercased())
|
||||
}
|
||||
}
|
||||
|
||||
private func feedsWithNotificationsEnabled(_ account: Account) -> [WebFeed] {
|
||||
sortedWebFeedsForAccount(account).filter { feed in
|
||||
return feed.isNotifyAboutNewArticles == true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
// MARK: - UITableViewDataSource
|
||||
extension NotificationsViewController: UITableViewDataSource {
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
@@ -53,7 +130,14 @@ extension NotificationsViewController: UITableViewDataSource {
|
||||
if status == .denied { return 1 }
|
||||
return 0
|
||||
}
|
||||
return AccountManager.shared.sortedActiveAccounts[section - 1].flattenedWebFeeds().count
|
||||
if searchController.isActive {
|
||||
return filteredWebFeeds(searchController.searchBar.text, account: AccountManager.shared.sortedActiveAccounts[section - 1]).count
|
||||
} else if newArticleNotificationFilter == true {
|
||||
return feedsWithNotificationsEnabled(AccountManager.shared.sortedActiveAccounts[section - 1]).count
|
||||
} else {
|
||||
return AccountManager.shared.sortedActiveAccounts[section - 1].flattenedWebFeeds().count
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
@@ -61,14 +145,25 @@ extension NotificationsViewController: UITableViewDataSource {
|
||||
let openSettingsCell = tableView.dequeueReusableCell(withIdentifier: "OpenSettingsCell") as! VibrantBasicTableViewCell
|
||||
return openSettingsCell
|
||||
} else {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "NotificationsCell") as! NotificationsTableViewCell
|
||||
let account = AccountManager.shared.sortedActiveAccounts[indexPath.section - 1]
|
||||
cell.configure(sortedWebFeedsForAccount(account)[indexPath.row])
|
||||
return cell
|
||||
if searchController.isActive {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "NotificationsCell") as! NotificationsTableViewCell
|
||||
let account = AccountManager.shared.sortedActiveAccounts[indexPath.section - 1]
|
||||
cell.configure(filteredWebFeeds(searchController.searchBar.text, account: account)[indexPath.row])
|
||||
return cell
|
||||
} else if newArticleNotificationFilter == true {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "NotificationsCell") as! NotificationsTableViewCell
|
||||
let account = AccountManager.shared.sortedActiveAccounts[indexPath.section - 1]
|
||||
cell.configure(feedsWithNotificationsEnabled(account)[indexPath.row])
|
||||
return cell
|
||||
} else {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "NotificationsCell") as! NotificationsTableViewCell
|
||||
let account = AccountManager.shared.sortedActiveAccounts[indexPath.section - 1]
|
||||
cell.configure(sortedWebFeedsForAccount(account)[indexPath.row])
|
||||
return cell
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
if section == 0 { return nil }
|
||||
return AccountManager.shared.sortedActiveAccounts[section - 1].nameForDisplay
|
||||
@@ -84,6 +179,8 @@ extension NotificationsViewController: UITableViewDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UITableViewDelegate
|
||||
extension NotificationsViewController: UITableViewDelegate {
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
@@ -107,3 +204,30 @@ extension NotificationsViewController: UITableViewDataSourcePrefetching {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UISearchControllerDelegate
|
||||
extension NotificationsViewController: UISearchControllerDelegate {
|
||||
|
||||
func didDismissSearchController(_ searchController: UISearchController) {
|
||||
print(#function)
|
||||
searchController.isActive = false
|
||||
notificationsTableView.reloadData()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - UISearchBarDelegate
|
||||
extension NotificationsViewController: UISearchBarDelegate {
|
||||
|
||||
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
|
||||
searchController.isActive = true
|
||||
newArticleNotificationFilter = false
|
||||
notificationsTableView.reloadData()
|
||||
}
|
||||
|
||||
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
|
||||
notificationsTableView.reloadData()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1110,7 +1110,7 @@
|
||||
<!--Notifications View Controller-->
|
||||
<scene sceneID="Brh-C7-mfB">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="NotificationsViewController" extendedLayoutIncludesOpaqueBars="YES" id="vak-Sx-5aB" customClass="NotificationsViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController storyboardIdentifier="NotificationsViewController" extendedLayoutIncludesOpaqueBars="YES" modalPresentationStyle="overCurrentContext" id="vak-Sx-5aB" customClass="NotificationsViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="2EC-mY-aSE">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
@@ -1189,14 +1189,15 @@
|
||||
</tableView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="32c-qn-nBM"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<color key="backgroundColor" systemColor="secondarySystemGroupedBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="dsQ-vy-iVG" firstAttribute="top" secondItem="32c-qn-nBM" secondAttribute="top" constant="-88" id="3o7-Oa-Qhq"/>
|
||||
<constraint firstItem="dsQ-vy-iVG" firstAttribute="top" secondItem="2EC-mY-aSE" secondAttribute="top" id="3o7-Oa-Qhq"/>
|
||||
<constraint firstItem="dsQ-vy-iVG" firstAttribute="leading" secondItem="32c-qn-nBM" secondAttribute="leading" id="V01-Fb-OvO"/>
|
||||
<constraint firstItem="32c-qn-nBM" firstAttribute="trailing" secondItem="dsQ-vy-iVG" secondAttribute="trailing" id="WTV-jU-eAU"/>
|
||||
<constraint firstItem="dsQ-vy-iVG" firstAttribute="bottom" secondItem="2EC-mY-aSE" secondAttribute="bottom" id="nQh-bT-XE2"/>
|
||||
<constraint firstItem="dsQ-vy-iVG" firstAttribute="bottom" secondItem="32c-qn-nBM" secondAttribute="bottom" constant="34" id="nQh-bT-XE2"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="sdU-Jy-5dq"/>
|
||||
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
|
||||
<connections>
|
||||
<outlet property="notificationsTableView" destination="dsQ-vy-iVG" id="Maw-PU-kb4"/>
|
||||
@@ -1371,6 +1372,9 @@
|
||||
<systemColor name="secondaryLabelColor">
|
||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="secondarySystemGroupedBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
|
||||
Reference in New Issue
Block a user