Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,60 +39,42 @@ public struct WMFNavigationBarBackButtonConfig {

/// Profile button config for navigation bar
public struct WMFNavigationBarProfileButtonConfig {
public let title: String
public let accessibilityLabelNoNotifications: String
public let accessibilityLabelHasNotifications: String
public let accessibilityHint: String
public let needsBadge: Bool
public let target: Any
public let action: Selector
public let leadingBarButtonItem: UIBarButtonItem?

public init(accessibilityLabelNoNotifications: String, accessibilityLabelHasNotifications: String, accessibilityHint: String, needsBadge: Bool, target: Any, action: Selector, leadingBarButtonItem: UIBarButtonItem?) {
public init(title: String, accessibilityLabelNoNotifications: String, accessibilityLabelHasNotifications: String, accessibilityHint: String, needsBadge: Bool, target: Any, action: Selector) {
self.title = title
self.accessibilityLabelNoNotifications = accessibilityLabelNoNotifications
self.accessibilityLabelHasNotifications = accessibilityLabelHasNotifications
self.accessibilityHint = accessibilityHint
self.needsBadge = needsBadge
self.target = target
self.action = action
self.leadingBarButtonItem = leadingBarButtonItem
}
}

public struct WMFNavigationBarTabsButtonConfig {
public let title: String
public let accessibilityLabel: String
public let accessibilityHint: String
public let target: Any
public let action: Selector
public let leadingBarButtonItem: UIBarButtonItem?
public let trailingBarButtonItem: UIBarButtonItem?
public let needsSeparateGlassContainer: Bool
public let leadingBarButtonItemTitle: String?

public init(accessibilityLabel: String, accessibilityHint: String, target: Any, action: Selector, leadingBarButtonItem: UIBarButtonItem?, trailingBarButtonItem: UIBarButtonItem?, needsSeparateGlassContainer: Bool) {
self.accessibilityLabel = accessibilityLabel
self.accessibilityHint = accessibilityHint
self.target = target
self.action = action
self.leadingBarButtonItem = leadingBarButtonItem
self.trailingBarButtonItem = trailingBarButtonItem
self.needsSeparateGlassContainer = needsSeparateGlassContainer
}
}

public struct WMFNavigationBarSearchButtonConfig {
public let accessibilityLabel: String
public let accessibilityHint: String
public let target: Any
public let action: Selector
public let leadingBarButtonItem: UIBarButtonItem?
public let trailingBarButtonItem: UIBarButtonItem?

public init(accessibilityLabel: String, accessibilityHint: String, target: Any, action: Selector, leadingBarButtonItem: UIBarButtonItem?, trailingBarButtonItem: UIBarButtonItem?) {
public init(title: String, accessibilityLabel: String, accessibilityHint: String, target: Any, action: Selector, leadingBarButtonItem: UIBarButtonItem?, leadingBarButtonItemTitle: String? = nil) {
self.title = title
self.accessibilityLabel = accessibilityLabel
self.accessibilityHint = accessibilityHint
self.target = target
self.action = action
self.leadingBarButtonItem = leadingBarButtonItem
self.trailingBarButtonItem = trailingBarButtonItem
self.leadingBarButtonItemTitle = leadingBarButtonItemTitle
}
}

Expand Down Expand Up @@ -137,7 +119,6 @@ public extension WMFNavigationBarConfiguring where Self: UIViewController {
closeButtonConfig: WMFLargeCloseButtonConfig?,
profileButtonConfig: WMFNavigationBarProfileButtonConfig?,
tabsButtonConfig: WMFNavigationBarTabsButtonConfig?,
searchButtonConfig: WMFNavigationBarSearchButtonConfig? = nil,
searchBarConfig: WMFNavigationBarSearchConfig?,
hideNavigationBarOnScroll: Bool) {

Expand Down Expand Up @@ -219,32 +200,76 @@ public extension WMFNavigationBarConfiguring where Self: UIViewController {

if let profileButtonConfig {

var rightBarButtonItems: [UIBarButtonItem] = []

let image = profileButtonImage(theme: WMFAppEnvironment.current.theme, needsBadge: profileButtonConfig.needsBadge)
let profileButton = UIBarButtonItem(image: image, style: .plain, target: profileButtonConfig.target, action: profileButtonConfig.action)

profileButton.accessibilityLabel = profileButtonAccessibilityStrings(config: profileButtonConfig)
profileButton.accessibilityIdentifier = profileButtonAccessibilityID

rightBarButtonItems.append(profileButton)

var trailingBarButtonItems: [UIBarButtonItem] = []
var specificMenu: UIMenu? = nil
var globalCollapsedActions: [UIAction] = []

if let tabsButtonConfig {

let image = WMFSFSymbolIcon.for(symbol: .tabsIcon)
let tabsButton = UIBarButtonItem(image: image, style: .plain, target: tabsButtonConfig.target, action: tabsButtonConfig.action)

rightBarButtonItems.append(tabsButton)

if let leadingBarButtonItem = tabsButtonConfig.leadingBarButtonItem {
if #available(iOS 26.0, *), tabsButtonConfig.needsSeparateGlassContainer {
leadingBarButtonItem.sharesBackground = false
trailingBarButtonItems.append(leadingBarButtonItem)
if let menu = leadingBarButtonItem.menu {
specificMenu = menu
} else {
specificMenu = UIMenu(title: "", options: .displayInline, children: [
UIAction(title: leadingBarButtonItem.title ?? tabsButtonConfig.leadingBarButtonItemTitle ?? "", image: leadingBarButtonItem.image) { _ in

if let target = leadingBarButtonItem.target,
let action = leadingBarButtonItem.action {
UIApplication.shared.sendAction(action, to: target, from: nil, for: nil)
}


}
])
}
rightBarButtonItems.append(leadingBarButtonItem)

}

trailingBarButtonItems.append(tabsButton)
globalCollapsedActions.append(UIAction(title: tabsButtonConfig.title, image: tabsButton.image) { _ in

let target = tabsButtonConfig.target
let action = tabsButtonConfig.action

UIApplication.shared.sendAction(action, to: target, from: nil, for: nil)
})
}

navigationItem.rightBarButtonItems = rightBarButtonItems
let image = profileButtonImage(theme: WMFAppEnvironment.current.theme, needsBadge: profileButtonConfig.needsBadge)
let profileButton = UIBarButtonItem(image: image, style: .plain, target: profileButtonConfig.target, action: profileButtonConfig.action)

profileButton.accessibilityLabel = profileButtonAccessibilityStrings(config: profileButtonConfig)
profileButton.accessibilityIdentifier = profileButtonAccessibilityID

trailingBarButtonItems.append(profileButton)
globalCollapsedActions.append(UIAction(title: profileButtonConfig.title, image: image) { _ in

let target = profileButtonConfig.target
let action = profileButtonConfig.action

UIApplication.shared.sendAction(action, to: target, from: nil, for: nil)
})

var menuChildren: [UIMenu] = [ UIMenu(title: "", options: .displayInline, children: globalCollapsedActions) ]
if let specificMenu {
menuChildren.insert(specificMenu, at: 0)
}

let collapsedMenu = UIMenu(title: "", children: menuChildren)

let representativeItem = UIBarButtonItem(title: nil, image: WMFSFSymbolIcon.for(symbol: .ellipsis), primaryAction: nil, menu: collapsedMenu)

let group = UIBarButtonItemGroup.optionalGroup(
customizationIdentifier: "trailing",
representativeItem: representativeItem,
items: trailingBarButtonItems
)

navigationItem.trailingItemGroups = [group]
}

// Setup close button if needed
Expand All @@ -260,39 +285,6 @@ public extension WMFNavigationBarConfiguring where Self: UIViewController {
}
}

if let searchButtonConfig {
var rightBarButtonItems: [UIBarButtonItem] = []

if let profileButtonConfig {
let profileImage = profileButtonImage(theme: WMFAppEnvironment.current.theme, needsBadge: profileButtonConfig.needsBadge)
let profileButton = UIBarButtonItem(image: profileImage, style: .plain, target: profileButtonConfig.target, action: profileButtonConfig.action)
profileButton.accessibilityLabel = profileButtonAccessibilityStrings(config: profileButtonConfig)
profileButton.accessibilityIdentifier = profileButtonAccessibilityID
rightBarButtonItems.append(profileButton)
}

if let tabsButtonConfig {
let tabsImage = WMFSFSymbolIcon.for(symbol: .tabsIcon)
let tabsButton = UIBarButtonItem(image: tabsImage, style: .plain, target: tabsButtonConfig.target, action: tabsButtonConfig.action)
tabsButton.accessibilityLabel = tabsButtonConfig.accessibilityLabel
tabsButton.accessibilityHint = tabsButtonConfig.accessibilityHint
rightBarButtonItems.append(tabsButton)
}

let image = WMFSFSymbolIcon.for(symbol: .magnifyingGlass)
let searchButton = UIBarButtonItem(image: image, style: .plain, target: searchButtonConfig.target, action: searchButtonConfig.action)
rightBarButtonItems.append(searchButton)

if let leadingBarButtonItem = searchButtonConfig.leadingBarButtonItem {
navigationItem.leftBarButtonItem = leadingBarButtonItem
}
if let trailingBarButtonItem = searchButtonConfig.trailingBarButtonItem {
rightBarButtonItems.append(trailingBarButtonItem)
}

navigationItem.rightBarButtonItems = rightBarButtonItems
}

if let searchBarConfig,
navigationItem.searchController == nil {
let searchController = UISearchController(searchResultsController: searchBarConfig.searchResultsController)
Expand Down
28 changes: 14 additions & 14 deletions Wikipedia/Code/ActivityTabViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ final class WMFActivityTabHostingController: WMFComponentHostingController<WMFAc
self.userDidTapCustomize()
})

let mainMenu = UIMenu(title: String(), children: [customizeAction, learnMoreAction, clearAction, reportIssueAction])
let mainMenu = UIMenu(title: String(), options: .displayInline, children: [customizeAction, learnMoreAction, clearAction, reportIssueAction])

return mainMenu
}
Expand Down Expand Up @@ -501,20 +501,20 @@ final class WMFActivityTabHostingController: WMFComponentHostingController<WMFAc
// MARK: - Navigation Bar
private func configureNavigationBar() {

let titleConfig: WMFNavigationBarTitleConfig = WMFNavigationBarTitleConfig(title: CommonStrings.activityTitle, customView: nil, alignment: .leadingCompact)
let titleConfig: WMFNavigationBarTitleConfig = WMFNavigationBarTitleConfig(title: CommonStrings.activityTitle, customView: nil, alignment: .leadingCompact)

let profileButtonConfig: WMFNavigationBarProfileButtonConfig?
let tabsButtonConfig: WMFNavigationBarTabsButtonConfig?
if let dataStore {
profileButtonConfig = self.profileButtonConfig(target: self, action: #selector(userDidTapProfile), dataStore: dataStore, yirDataController: yirDataController, leadingBarButtonItem: nil)
tabsButtonConfig = self.tabsButtonConfig(target: self, action: #selector(userDidTapTabs), dataStore: dataStore, leadingBarButtonItem: moreBarButtonItem, needsSeparateGlassContainer: true)
} else {
profileButtonConfig = nil
tabsButtonConfig = nil
}
let profileButtonConfig: WMFNavigationBarProfileButtonConfig?
let tabsButtonConfig: WMFNavigationBarTabsButtonConfig?
if let dataStore {
profileButtonConfig = self.profileButtonConfig(target: self, action: #selector(userDidTapProfile), dataStore: dataStore, yirDataController: yirDataController)
tabsButtonConfig = self.tabsButtonConfig(target: self, action: #selector(userDidTapTabs), dataStore: dataStore, leadingBarButtonItem: moreBarButtonItem)
} else {
profileButtonConfig = nil
tabsButtonConfig = nil
}

configureNavigationBar(titleConfig: titleConfig, closeButtonConfig: nil, profileButtonConfig: profileButtonConfig, tabsButtonConfig: tabsButtonConfig, searchBarConfig: nil, hideNavigationBarOnScroll: false)
}
configureNavigationBar(titleConfig: titleConfig, closeButtonConfig: nil, profileButtonConfig: profileButtonConfig, tabsButtonConfig: tabsButtonConfig, searchBarConfig: nil, hideNavigationBarOnScroll: false)
}

@objc func userDidTapTabs() {
tabsCoordinator?.start()
Expand All @@ -541,7 +541,7 @@ final class WMFActivityTabHostingController: WMFComponentHostingController<WMFAc
return
}

let config = self.profileButtonConfig(target: self, action: #selector(userDidTapProfile), dataStore: dataStore, yirDataController: yirDataController, leadingBarButtonItem: nil)
let config = self.profileButtonConfig(target: self, action: #selector(userDidTapProfile), dataStore: dataStore, yirDataController: yirDataController)
updateNavigationBarProfileButton(needsBadge: config.needsBadge, needsBadgeLabel: CommonStrings.profileButtonBadgeTitle, noBadgeLabel: CommonStrings.profileButtonTitle)
}

Expand Down
2 changes: 1 addition & 1 deletion Wikipedia/Code/ArticleToolbarController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class ArticleToolbarController: Themeable {
private func createMoreButton(needsWatchButton: Bool = false, needsUnwatchHalfButton: Bool = false, needsUnwatchFullButton: Bool = false, previousArticleTab: WMFArticleTabsDataController.WMFArticle? = nil, nextArticleTab: WMFArticleTabsDataController.WMFArticle? = nil) -> IconBarButtonItem {


let moreImage = WMFSFSymbolIcon.for(symbol: .ellipsisCircle)?.withConfiguration(UIImage.SymbolConfiguration(weight: .light))
let moreImage = WMFSFSymbolIcon.for(symbol: .ellipsis)?.withConfiguration(UIImage.SymbolConfiguration(weight: .light))

let menu = createMoreMenu(needsWatchButton: needsWatchButton, needsUnwatchHalfButton: needsUnwatchHalfButton, needsUnwatchFullButton: needsUnwatchFullButton, previousArticleTab: previousArticleTab, nextArticleTab: nextArticleTab)

Expand Down
27 changes: 16 additions & 11 deletions Wikipedia/Code/ArticleViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,13 @@ class ArticleViewController: ThemeableViewController, UIScrollViewDelegate, WMFN
}

// MARK: Navigation Bar

private var searchButtonItem: UIBarButtonItem {
let image = WMFSFSymbolIcon.for(symbol: .magnifyingGlass)
let searchButton = UIBarButtonItem(image: image, style: .plain, target: self, action: #selector(userDidTapSearch))
searchButton.accessibilityLabel = CommonStrings.searchButtonAccessibilityHint
return searchButton
}

private func configureNavigationBar() {

Expand All @@ -757,25 +764,23 @@ class ArticleViewController: ThemeableViewController, UIScrollViewDelegate, WMFN

let backButtonConfig = WMFNavigationBarBackButtonConfig(needsCustomTruncateBackButtonTitle: true)

var profileButtonConfig = profileButtonConfig(target: self, action: #selector(userDidTapProfile), dataStore: dataStore, yirDataController: yirDataController, leadingBarButtonItem: nil)

let tabsButtonConfig = tabsButtonConfig(target: self, action: #selector(userDidTapTabs), dataStore: dataStore)

var searchButtonConfig: WMFNavigationBarSearchButtonConfig? = nil
let profileButtonConfig = profileButtonConfig(target: self, action: #selector(userDidTapProfile), dataStore: dataStore, yirDataController: yirDataController)

var tabsLeadingButton: UIBarButtonItem?

if #available(iOS 18, *) {
if UIDevice.current.userInterfaceIdiom == .pad && traitCollection.horizontalSizeClass == .regular {
titleConfig = WMFNavigationBarTitleConfig(title: articleURL.wmf_title ?? "", customView: nil, alignment: .hidden)
profileButtonConfig = self.profileButtonConfig(target: self, action: #selector(userDidTapProfile), dataStore: dataStore, yirDataController: yirDataController, leadingBarButtonItem: nil)
searchButtonConfig = nil
} else if UIDevice.current.userInterfaceIdiom == .phone {
searchButtonConfig = self.searchButtonConfig(target: self, action: #selector(userDidTapSearch), dataStore: dataStore)
tabsLeadingButton = searchButtonItem
}
} else if UIDevice.current.userInterfaceIdiom == .phone {
searchButtonConfig = self.searchButtonConfig(target: self, action: #selector(userDidTapSearch), dataStore: dataStore)
tabsLeadingButton = searchButtonItem
}

let tabsButtonConfig = tabsButtonConfig(target: self, action: #selector(userDidTapTabs), dataStore: dataStore, leadingBarButtonItem: tabsLeadingButton)

configureNavigationBar(titleConfig: titleConfig, backButtonConfig: backButtonConfig, closeButtonConfig: nil, profileButtonConfig: profileButtonConfig, tabsButtonConfig: tabsButtonConfig, searchButtonConfig: searchButtonConfig, searchBarConfig: nil, hideNavigationBarOnScroll: true)
configureNavigationBar(titleConfig: titleConfig, backButtonConfig: backButtonConfig, closeButtonConfig: nil, profileButtonConfig: profileButtonConfig, tabsButtonConfig: tabsButtonConfig, searchBarConfig: nil, hideNavigationBarOnScroll: true)
}

@objc func userDidTapSearch() {
Expand All @@ -788,7 +793,7 @@ class ArticleViewController: ThemeableViewController, UIScrollViewDelegate, WMFN

private func updateProfileButton() {

let config = self.profileButtonConfig(target: self, action: #selector(userDidTapProfile), dataStore: dataStore, yirDataController: yirDataController, leadingBarButtonItem: nil)
let config = self.profileButtonConfig(target: self, action: #selector(userDidTapProfile), dataStore: dataStore, yirDataController: yirDataController)

updateNavigationBarProfileButton(needsBadge: config.needsBadge, needsBadgeLabel: CommonStrings.profileButtonBadgeTitle, noBadgeLabel: CommonStrings.profileButtonTitle)
}
Expand Down
Loading
Loading