Skip to content

Commit

Permalink
[Notifications Refresh] Replace tabs with dropdown in notifications s…
Browse files Browse the repository at this point in the history
…creen (#23054)
  • Loading branch information
salimbraksa authored Apr 25, 2024
2 parents 3a5728d + 96ddcb7 commit 7b25e64
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 84 deletions.
36 changes: 20 additions & 16 deletions WordPress/Classes/Extensions/UIButton+Extensions.swift
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
import UIKit

extension UIButton {

/// Creates a bar button item that looks like the native title menu
/// (see `navigationItem.titleMenuProvider`, iOS 16+).
static func makeMenu(title: String, menu: UIMenu) -> UIButton {
let button = UIButton(configuration: {
var configuration = UIButton.Configuration.plain()
configuration.title = title
configuration.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer {
var attributes = $0
attributes.font = WPStyleGuide.fontForTextStyle(.headline)
return attributes
}
configuration.image = UIImage(systemName: "chevron.down.circle.fill")?.withBaselineOffset(fromBottom: 4)
configuration.preferredSymbolConfigurationForImage = UIImage.SymbolConfiguration(paletteColors: [.secondaryLabel, .secondarySystemFill])
.applying(UIImage.SymbolConfiguration(font: WPStyleGuide.fontForTextStyle(.subheadline, fontWeight: .semibold)))
configuration.imagePlacement = .trailing
configuration.imagePadding = 4
configuration.baseForegroundColor = .label
return configuration
}())
let button = UIButton(configuration: menuButtonConfiguration(title: title))
button.menu = menu
button.showsMenuAsPrimaryAction = true
return button
}

/// The configuration of a bar button item that looks like the native title menu
static func menuButtonConfiguration(title: String) -> UIButton.Configuration {
var configuration = UIButton.Configuration.plain()
configuration.title = title
configuration.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer {
var attributes = $0
attributes.font = WPStyleGuide.fontForTextStyle(.headline)
return attributes
}
configuration.image = UIImage(systemName: "chevron.down.circle.fill")?.withBaselineOffset(fromBottom: 4)
configuration.preferredSymbolConfigurationForImage = UIImage.SymbolConfiguration(paletteColors: [.secondaryLabel, .secondarySystemFill])
.applying(UIImage.SymbolConfiguration(font: WPStyleGuide.fontForTextStyle(.subheadline, fontWeight: .semibold)))
configuration.imagePlacement = .trailing
configuration.imagePadding = 4
configuration.baseForegroundColor = .label
return configuration
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ extension NotificationsViewController {

enum Strings {
enum NavigationBar {
static let title = NSLocalizedString(
"notifications.navigationBar.title",
value: "Notifications",
comment: "Notifications View Controller title"
)
static let allNotificationsTitle = NSLocalizedString(
"notifications.navigationBar.filters.allNotifications",
value: "All Notifications",
comment: "The navigation bar title when 'All' filter is selected"
)
static let notificationSettingsActionTitle = NSLocalizedString(
"notificationsViewController.navigationBar.action.settings",
value: "Notification Settings",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ class NotificationsViewController: UIViewController, UITableViewDataSource, UITa
///
@IBOutlet var tableHeaderView: UIView!

/// Filtering Tab Bar
///
@IBOutlet weak var filterTabBar: FilterTabBar!

/// Jetpack Banner View
/// Only visible in WordPress
///
Expand Down Expand Up @@ -73,15 +69,41 @@ class NotificationsViewController: UIViewController, UITableViewDataSource, UITa
///
fileprivate var unreadNotificationIds = Set<NSManagedObjectID>()

/// Used to store (and restore) the currently selected filter segment.
///
fileprivate var restorableSelectedSegmentIndex: Int = 0

/// Used to keep track of the currently selected notification,
/// to restore it between table view reloads and state restoration.
///
fileprivate var selectedNotification: Notification? = nil

/// Menu listing the notifications filters.
///
fileprivate lazy var filtersMenuButton: UIButton = {
let firstSection = [Filter.none]
let secondSection = Filter.allCases.filter { $0 != .none }
let children: [UIMenuElement] = [firstSection, secondSection].map { section -> UIMenuElement in
let actions = section.map { filter in
UIAction(title: filter.title, image: nil) { [weak self] _ in
self?.filtersMenuTapped(filter: filter)
}
}
if actions.count == 1, let action = actions.first {
return action
} else {
return UIMenu(options: .displayInline, children: actions)
}
}
let menu = UIMenu(children: children)
return UIButton.makeMenu(title: filtersMenuButtonTitle(for: filter), menu: menu)
}()

/// Holds the current filter state, updating the filter's menu configuration and reloading results on change.
///
fileprivate var filter: Filter = .none {
didSet {
filtersMenuButton.configuration = UIButton.menuButtonConfiguration(title: filtersMenuButtonTitle(for: filter))
reloadResultsController()
}
}

/// JetpackLoginVC being presented.
///
internal var jetpackLoginViewController: JetpackLoginViewController? = nil
Expand Down Expand Up @@ -139,7 +161,6 @@ class NotificationsViewController: UIViewController, UITableViewDataSource, UITa
setupTableFooterView()
setupRefreshControl()
setupNoResultsView()
setupFilterBar()

tableView.tableHeaderView = tableHeaderView
setupConstraints()
Expand Down Expand Up @@ -452,10 +473,10 @@ private extension NotificationsViewController {
// we are using a space character because we need a non-empty string to ensure a smooth
// transition back, with large titles enabled.
navigationItem.backBarButtonItem = UIBarButtonItem(title: " ", style: .plain, target: nil, action: nil)
navigationItem.title = NSLocalizedString("Notifications", comment: "Notifications View Controller title")
navigationItem.title = Strings.NavigationBar.title
}

func updateNavigationItems() {
func configureNavigationItems() {
let moreMenuItems = UIDeferredMenuElement.uncached { [weak self] completion in
guard let self else {
completion([])
Expand All @@ -475,6 +496,13 @@ private extension NotificationsViewController {
}()
}

private func filtersMenuButtonTitle(for filter: Filter) -> String {
switch filter {
case .none: return Strings.NavigationBar.allNotificationsTitle
default: return filter.title
}
}

func makeMoreMenuElements() -> [UIAction] {
// Mark All As Read
let markAllAsRead: UIAction? = { () -> UIAction? in
Expand Down Expand Up @@ -516,7 +544,6 @@ private extension NotificationsViewController {
func setupConstraints() {
// Inline prompt is initially hidden!
inlinePromptView.translatesAutoresizingMaskIntoConstraints = false
filterTabBar.tabBarHeightConstraintPriority = 999

let leading = tableHeaderView.safeLeadingAnchor.constraint(equalTo: tableView.safeLeadingAnchor)
let trailing = tableHeaderView.safeTrailingAnchor.constraint(equalTo: tableView.safeTrailingAnchor)
Expand Down Expand Up @@ -575,15 +602,6 @@ private extension NotificationsViewController {
func setupNoResultsView() {
noResultsViewController.delegate = self
}

func setupFilterBar() {
WPStyleGuide.configureFilterTabBar(filterTabBar)
filterTabBar.superview?.backgroundColor = .systemBackground
filterTabBar.backgroundColor = .systemBackground

filterTabBar.items = Filter.allCases
filterTabBar.addTarget(self, action: #selector(selectedFilterDidChange(_:)), for: .valueChanged)
}
}

// MARK: - Jetpack banner UI Initialization
Expand Down Expand Up @@ -1282,21 +1300,19 @@ extension NotificationsViewController: NetworkStatusDelegate {
}
}

// MARK: - FilterTabBar Methods
// MARK: - Filters Menu Methods
//
extension NotificationsViewController {

@objc func selectedFilterDidChange(_ filterBar: FilterTabBar) {
selectedNotification = nil
private func filtersMenuTapped(filter: Filter) {
self.filter = filter
self.selectedNotification = nil

let properties = [Stats.selectedFilter: filter.analyticsTitle]
WPAnalytics.track(.notificationsTappedSegmentedControl, withProperties: properties)

updateUnreadNotificationsForFilterTabChange()

reloadResultsController()

selectFirstNotificationIfAppropriate()
self.updateUnreadNotificationsForFilterTabChange()
self.selectFirstNotificationIfAppropriate()
}

@objc func selectFirstNotificationIfAppropriate() {
Expand Down Expand Up @@ -1479,19 +1495,17 @@ extension NotificationsViewController: WPTableViewHandlerDelegate {
//
private extension NotificationsViewController {
func showFiltersSegmentedControlIfApplicable() {
guard filterTabBar.isHidden == true && shouldDisplayFilters == true else {
guard shouldDisplayFilters else {
return
}

UIView.animate(withDuration: WPAnimationDurationDefault, animations: {
self.filterTabBar.isHidden = false
})
self.navigationItem.titleView = filtersMenuButton
}

func hideFiltersSegmentedControlIfApplicable() {
if filterTabBar.isHidden == false && shouldDisplayFilters == false {
self.filterTabBar.isHidden = true
guard !shouldDisplayFilters else {
return
}
self.navigationItem.titleView = nil
}

var shouldDisplayFilters: Bool {
Expand All @@ -1508,7 +1522,7 @@ private extension NotificationsViewController {
func showNoResultsViewIfNeeded() {
noResultsViewController.removeFromView()
updateSplitViewAppearanceForNoResultsView()
updateNavigationItems()
configureNavigationItems()

// Hide the filter header if we're showing the Jetpack prompt
hideFiltersSegmentedControlIfApplicable()
Expand Down Expand Up @@ -1802,17 +1816,6 @@ private extension NotificationsViewController {
return UserPersistentStoreFactory.instance()
}

var filter: Filter {
get {
let selectedIndex = filterTabBar?.selectedIndex ?? Filter.none.rawValue
return Filter(rawValue: selectedIndex) ?? .none
}
set {
filterTabBar?.setSelectedIndex(newValue.rawValue)
reloadResultsController()
}
}

enum Filter: Int, FilterTabBarItem, CaseIterable {
case none = 0
case unread = 1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="aRr-Yu-ntD">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="aRr-Yu-ntD">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
Expand Down Expand Up @@ -47,7 +47,6 @@
</view>
<extendedEdge key="edgesForExtendedLayout" top="YES"/>
<connections>
<outlet property="filterTabBar" destination="XgY-0j-kFz" id="LlQ-Kc-Yyz"/>
<outlet property="inlinePromptView" destination="jc0-PX-EvN" id="yPU-Nj-hlp"/>
<outlet property="jetpackBannerView" destination="fx7-Fo-KUl" id="YYv-mK-dV3"/>
<outlet property="tableHeaderView" destination="9K7-oU-83Y" id="dac-fs-2oN"/>
Expand All @@ -66,23 +65,6 @@
<constraint firstAttribute="height" constant="100" placeholder="YES" id="pxu-yE-rHC"/>
</constraints>
</view>
<view contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" layoutMarginsFollowReadableWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rKm-gY-cFw" userLabel="Filters View">
<rect key="frame" x="0.0" y="100" width="600" height="44"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XgY-0j-kFz" customClass="FilterTabBar" customModule="WordPress" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="600" height="34"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="XgY-0j-kFz" secondAttribute="trailing" priority="999" id="7Mp-Sv-zuM"/>
<constraint firstItem="XgY-0j-kFz" firstAttribute="leading" secondItem="rKm-gY-cFw" secondAttribute="leading" priority="999" id="JVy-y6-rph"/>
<constraint firstAttribute="height" priority="999" constant="44" id="dte-R2-ISl"/>
<constraint firstAttribute="bottom" secondItem="XgY-0j-kFz" secondAttribute="bottom" constant="10" id="mxz-xp-47Y"/>
<constraint firstItem="XgY-0j-kFz" firstAttribute="top" secondItem="rKm-gY-cFw" secondAttribute="top" id="udW-ag-i42"/>
</constraints>
</view>
</subviews>
</stackView>
<placeholder placeholderIdentifier="IBFirstResponder" id="KJC-DS-ThZ" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
Expand Down

0 comments on commit 7b25e64

Please sign in to comment.