@@ -15,12 +15,14 @@ final class ReviewsViewController: UIViewController {
1515 /// Mark all as read nav bar button
1616 ///
1717 private lazy var rightBarButton : UIBarButtonItem = {
18- let item = UIBarButtonItem ( image: . checkmarkImage ,
18+ let item = UIBarButtonItem ( image: . ellipsisImage ,
1919 style: . plain,
2020 target: self ,
21- action: #selector( markAllAsRead) )
22- item. accessibilityIdentifier = " reviews-mark-all-as-read-button "
23-
21+ action: #selector( presentMoreActions) )
22+ item. accessibilityIdentifier = " reviews-open-menu-button "
23+ item. accessibilityTraits = . button
24+ item. accessibilityLabel = Localization . MenuButton. accessibilityLabel
25+ item. accessibilityHint = Localization . MenuButton. accessibilityHint
2426 return item
2527 } ( )
2628
@@ -132,7 +134,6 @@ final class ReviewsViewController: UIViewController {
132134 refreshTitle ( )
133135
134136 configureSyncingCoordinator ( )
135- configureNavigationBarButtons ( )
136137 configureTableView ( )
137138 configureTableViewCells ( )
138139 configureResultsController ( )
@@ -183,21 +184,11 @@ private extension ReviewsViewController {
183184 /// Setup: TabBar
184185 ///
185186 func configureTabBarItem( ) {
186- tabBarItem. title = NSLocalizedString ( " Reviews " , comment : " Title of the Reviews tab — plural form of Review " )
187+ tabBarItem. title = Localization . tabBarItemTitle
187188 tabBarItem. image = . starOutlineImage( )
188189 tabBarItem. accessibilityIdentifier = " tab-bar-reviews-item "
189190 }
190191
191- /// Setup: NavigationBar Buttons
192- ///
193- func configureNavigationBarButtons( ) {
194- rightBarButton. accessibilityTraits = . button
195- rightBarButton. accessibilityLabel = NSLocalizedString ( " Mark All as Read " , comment: " Accessibility label for the Mark All Reviews as Read Button " )
196- rightBarButton. accessibilityHint = NSLocalizedString ( " Marks Every Review as Read " ,
197- comment: " VoiceOver accessibility hint for the Mark All Reviews as Read Action " )
198- navigationItem. rightBarButtonItem = rightBarButton
199- }
200-
201192 /// Setup: TableView
202193 ///
203194 func configureTableView( ) {
@@ -232,10 +223,7 @@ private extension ReviewsViewController {
232223 }
233224
234225 func refreshTitle( ) {
235- title = NSLocalizedString (
236- " Reviews " ,
237- comment: " Title that appears on top of the main Reviews screen (plural form of the word Review). "
238- )
226+ title = Localization . title
239227 }
240228}
241229
@@ -251,6 +239,20 @@ private extension ReviewsViewController {
251239 }
252240 }
253241
242+ /// Presents an action sheet on tapping the menu right bar button item.
243+ ///
244+ @IBAction func presentMoreActions( ) {
245+ let actionSheet = UIAlertController ( title: nil , message: nil , preferredStyle: . actionSheet)
246+ actionSheet. view. tintColor = . text
247+
248+ actionSheet. addCancelActionWithTitle ( Localization . ActionSheet. cancelAction)
249+ actionSheet. addDefaultActionWithTitle ( Localization . ActionSheet. markAsReadAction) { [ weak self] _ in
250+ self ? . presentMarkAllAsReadConfirmationAlert ( )
251+ }
252+
253+ present ( actionSheet, animated: true )
254+ }
255+
254256 @IBAction func markAllAsRead( ) {
255257 ServiceLocator . analytics. track ( . reviewsListReadAllTapped)
256258
@@ -274,7 +276,7 @@ private extension ReviewsViewController {
274276 tracks. track ( . reviewsMarkAllReadSuccess)
275277 }
276278
277- self . updateMarkAllReadButtonState ( )
279+ self . updateRightBarButtonItem ( )
278280 self . tableView. reloadData ( )
279281 }
280282 }
@@ -336,11 +338,11 @@ private extension ReviewsViewController {
336338 ///
337339 func displayEmptyViewController( ) {
338340 let childController = emptyStateViewController
339- let emptyStateConfig = EmptyStateViewController . Config. withLink ( message: NSAttributedString ( string: Localization . emptyStateMessage ) ,
340- image: . emptyReviewsImage,
341- details: Localization . emptyStateDetail ,
342- linkTitle: Localization . emptyStateAction ,
343- linkURL: WooConstants . URLs. productReviewInfo. asURL ( ) )
341+ let emptyStateConfig = EmptyStateViewController . Config. withLink ( message: NSAttributedString ( string: Localization . EmptyState . message ) ,
342+ image: . emptyReviewsImage,
343+ details: Localization . EmptyState . detail ,
344+ linkTitle: Localization . EmptyState . action ,
345+ linkURL: WooConstants . URLs. productReviewInfo. asURL ( ) )
344346
345347 // Abort if we are already displaying this childController
346348 guard childController. parent == nil ,
@@ -412,7 +414,7 @@ private extension ReviewsViewController {
412414 /// Note: Just because this func runs does not guarantee `didEnter()` or `didLeave()` will run as well.
413415 ///
414416 func willEnter( state: State ) {
415- updateNavBarButtonsState ( )
417+ updateRightBarButtonItem ( )
416418 }
417419
418420 /// Runs whenever the FSM enters a State.
@@ -478,16 +480,10 @@ private extension ReviewsViewController {
478480//
479481private extension ReviewsViewController {
480482
481- /// Enables/disables the navbar buttons if needed
482- ///
483- /// - Parameter filterEnabled: If true, the filter navbar buttons is enabled; if false, it's disabled
483+ /// Show the rightBarButtonItem only if there are unread reviews available.
484484 ///
485- func updateNavBarButtonsState( ) {
486- updateMarkAllReadButtonState ( )
487- }
488-
489- func updateMarkAllReadButtonState( ) {
490- rightBarButton. isEnabled = viewModel. hasUnreadNotifications
485+ func updateRightBarButtonItem( ) {
486+ navigationItem. rightBarButtonItem = viewModel. hasUnreadNotifications ? rightBarButton : nil
491487 }
492488
493489 /// Displays the `Mark all as read` Notice if the number of times it was previously displayed is lower than the
@@ -499,10 +495,26 @@ private extension ReviewsViewController {
499495 }
500496
501497 markAsReadCount += 1
502- let message = NSLocalizedString ( " All reviews marked as read " , comment: " Mark all reviews as read notice " )
503- let notice = Notice ( title: message, feedbackType: . success)
498+ let notice = Notice ( title: Localization . Notice. allReviewsMarkedAsRead, feedbackType: . success)
504499 ServiceLocator . noticePresenter. enqueue ( notice: notice)
505500 }
501+
502+ /// Presents an alert which asks the user for confirmation
503+ /// before marking all reviews as read.
504+ ///
505+ func presentMarkAllAsReadConfirmationAlert( ) {
506+ let alertController = UIAlertController ( title: Localization . MarkAllAsReadAlert. title,
507+ message: Localization . MarkAllAsReadAlert. message,
508+ preferredStyle: . alert)
509+ alertController. view. tintColor = . text
510+
511+ alertController. addActionWithTitle ( Localization . MarkAllAsReadAlert. cancelButtonTitle, style: . destructive)
512+ alertController. addDefaultActionWithTitle ( Localization . MarkAllAsReadAlert. markAllButtonTitle) { [ weak self] _ in
513+ self ? . markAllAsRead ( )
514+ }
515+
516+ present ( alertController, animated: true )
517+ }
506518}
507519
508520
@@ -602,9 +614,53 @@ private extension ReviewsViewController {
602614//
603615private extension ReviewsViewController {
604616 enum Localization {
605- static let emptyStateMessage = NSLocalizedString ( " Get your first reviews " , comment: " Message shown in the Reviews tab if the list is empty " )
606- static let emptyStateDetail = NSLocalizedString ( " Capture high-quality product reviews for your store. " ,
607- comment: " Detailed message shown in the Reviews tab if the list is empty " )
608- static let emptyStateAction = NSLocalizedString ( " Learn more " , comment: " Title of button shown in the Reviews tab if the list is empty " )
617+ static let title = NSLocalizedString ( " Reviews " ,
618+ comment: " Title that appears on top of the main Reviews screen (plural form of the word Review). " )
619+
620+ static let tabBarItemTitle = NSLocalizedString ( " Reviews " ,
621+ comment: " Title of the Reviews tab — plural form of Review " )
622+
623+ enum MenuButton {
624+ static let accessibilityLabel = NSLocalizedString ( " Open menu " ,
625+ comment: " Accessibility label for the Menu button " )
626+ static let accessibilityHint = NSLocalizedString ( " Menu button which opens an action sheet with option to mark all reviews as read. " ,
627+ comment: " VoiceOver accessibility hint for the Menu button action " )
628+ }
629+
630+ enum ActionSheet {
631+ static let markAsReadAction = NSLocalizedString ( " Mark all reviews as read " ,
632+ comment: " Option to mark all reviews as read from the action sheet in Reviews screen. " )
633+
634+ static let cancelAction = NSLocalizedString ( " Cancel " ,
635+ comment: " Cancel the more menu action sheet in Reviews screen. " )
636+ }
637+
638+ enum MarkAllAsReadAlert {
639+ static let title = NSLocalizedString ( " Mark all as read " ,
640+ comment: " Title of Alert which asks user for confirmation before marking all reviews as read. " )
641+
642+ static let message = NSLocalizedString ( " Are you sure you want to mark all reviews as read? " ,
643+ comment: " Alert message to confirm a user meant to mark all reviews as read. " )
644+
645+ static let cancelButtonTitle = NSLocalizedString ( " Cancel " ,
646+ comment: " Alert button title - dismisses alert, which cancels marking all as read attempt. " )
647+
648+ static let markAllButtonTitle = NSLocalizedString ( " Mark all " ,
649+ comment: " Alert button title - confirms and marks all reviews as read " )
650+ }
651+
652+ enum Notice {
653+ static let allReviewsMarkedAsRead = NSLocalizedString ( " All reviews marked as read " ,
654+ comment: " Mark all reviews as read notice " )
655+ }
656+
657+ enum EmptyState {
658+ static let message = NSLocalizedString ( " Get your first reviews " ,
659+ comment: " Message shown in the Reviews tab if the list is empty " )
660+ static let detail = NSLocalizedString ( " Capture high-quality product reviews for your store. " ,
661+ comment: " Detailed message shown in the Reviews tab if the list is empty " )
662+ static let action = NSLocalizedString ( " Learn more " ,
663+ comment: " Title of button shown in the Reviews tab if the list is empty " )
664+ }
609665 }
610666}
0 commit comments