Skip to content

Commit 4678118

Browse files
authored
Merge pull request #5913 from woocommerce/issue/5874-notification-badge-in-the-Hub-Menu-and-inside-the-hub-menu-cell-in-case-there-is-a-new-notification
Hub Menu: managed notification badge in the hub menu tab
2 parents 51d7333 + 35d3524 commit 4678118

File tree

5 files changed

+75
-32
lines changed

5 files changed

+75
-32
lines changed

WooCommerce/Classes/ServiceLocator/PushNotesManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ protocol PushNotesManager {
6161
///
6262
func registerDeviceToken(with tokenData: Data, defaultStoreID: Int64)
6363

64-
/// Handles a Remote Push Notifican Payload. On completion the `completionHandler` will be executed.
64+
/// Handles a Remote Push Notification Payload. On completion the `completionHandler` will be executed.
6565
///
6666
func handleNotification(_ userInfo: [AnyHashable: Any],
6767
onBadgeUpdateCompletion: @escaping () -> Void,

WooCommerce/Classes/ViewRelated/Hub Menu/HubMenu.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ struct HubMenu: View {
3030

3131
LazyVGrid(columns: gridItemLayout, spacing: Constants.itemSpacing) {
3232
ForEach(viewModel.menuElements, id: \.self) { menu in
33-
HubMenuElement(image: menu.icon, imageColor: menu.iconColor, text: menu.title, onTapGesture: {
33+
// Currently the badge is always zero, because we are not handling push notifications count
34+
// correctly due to the first behavior described here p91TBi-66O:
35+
// AppDelegate’s `application(_:didReceiveRemoteNotification:fetchCompletionHandler:)`
36+
// can be called twice for the same push notification when receiving it
37+
// and tapping on it to open the app. This means that some push notifications are incrementing the badge number by 2, and some by 1.
38+
HubMenuElement(image: menu.icon, imageColor: menu.iconColor, text: menu.title, badge: 0, onTapGesture: {
3439
switch menu {
3540
case .woocommerceAdmin:
3641
ServiceLocator.analytics.track(.hubMenuOptionTapped, withProperties: [Constants.option: "admin_menu"])

WooCommerce/Classes/ViewRelated/Hub Menu/HubMenuElement.swift

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ struct HubMenuElement: View {
66
let image: UIImage
77
let imageColor: UIColor
88
let text: String
9+
let badge: Int
910
let onTapGesture: (() -> Void)
1011

1112
@ScaledMetric var imageSize: CGFloat = 58
@@ -15,30 +16,56 @@ struct HubMenuElement: View {
1516
Button {
1617
onTapGesture()
1718
} label: {
18-
VStack {
19-
ZStack {
20-
Color(UIColor(light: .listBackground,
21-
dark: .secondaryButtonBackground))
22-
Image(uiImage: image)
23-
.renderingMode(.template)
24-
.resizable()
25-
.scaledToFit()
26-
.foregroundColor(Color(imageColor))
27-
.frame(width: iconSize, height: iconSize)
19+
ZStack(alignment: .topTrailing) {
20+
21+
VStack {
22+
ZStack {
23+
Color(UIColor(light: .listBackground,
24+
dark: .secondaryButtonBackground))
25+
Image(uiImage: image)
26+
.renderingMode(.template)
27+
.resizable()
28+
.scaledToFit()
29+
.foregroundColor(Color(imageColor))
30+
.frame(width: iconSize, height: iconSize)
31+
}
32+
.frame(width: imageSize, height: imageSize, alignment: .center)
33+
.cornerRadius(imageSize/2)
34+
.padding(.bottom, Constants.paddingBetweenElements)
35+
Text(text)
36+
.bodyStyle()
2837
}
29-
.frame(width: imageSize, height: imageSize, alignment: .center)
30-
.cornerRadius(imageSize/2)
31-
.padding(.bottom, Constants.paddingBetweenElements)
32-
Text(text)
38+
.frame(width: Constants.itemSize, height: Constants.itemSize)
39+
HubMenuBadge(value: badge)
40+
.padding([.top, .trailing], 8)
41+
.renderedIf(badge > 0)
42+
}
43+
}
44+
}
45+
46+
private struct HubMenuBadge: View {
47+
let value: Int
48+
49+
var body: some View {
50+
ZStack (alignment: .center) {
51+
Rectangle()
52+
.fill(.purple)
53+
.cornerRadius(Constants.cornerRadius)
54+
Text(String(value))
55+
.foregroundColor(.white)
3356
.bodyStyle()
57+
.padding([.leading, .trailing], Constants.paddingBetweenElements)
3458
}
35-
.frame(width: Constants.itemSize, height: Constants.itemSize)
59+
.frame(height: Constants.badgeSize)
60+
.fixedSize()
3661
}
3762
}
3863

3964
enum Constants {
4065
static let paddingBetweenElements: CGFloat = 8
4166
static let itemSize: CGFloat = 160
67+
static let badgeSize: CGFloat = 24
68+
static let cornerRadius: CGFloat = badgeSize/2
4269
}
4370
}
4471

@@ -47,6 +74,7 @@ struct HubMenuElement_Previews: PreviewProvider {
4774
HubMenuElement(image: .starOutlineImage(),
4875
imageColor: .blue,
4976
text: "Menu",
77+
badge: 1,
5078
onTapGesture: {})
5179
.previewLayout(.fixed(width: 160, height: 160))
5280
.previewDisplayName("Hub Menu Element")

WooCommerce/Classes/ViewRelated/MainTabBarController.swift

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ final class MainTabBarController: UITabBarController {
123123
configureTabViewControllers()
124124
observeSiteIDForViewControllers()
125125

126-
loadReviewsTabNotificationCountAndUpdateBadge()
126+
loadHubMenuTabNotificationCountAndUpdateBadge()
127127
}
128128

129129
override func viewWillAppear(_ animated: Bool) {
@@ -133,7 +133,7 @@ final class MainTabBarController: UITabBarController {
133133
/// We hook up KVO in this spot... because at the point in which `viewDidLoad` fires, we haven't really fully
134134
/// loaded the childViewControllers, and the tabBar isn't fully initialized.
135135
///
136-
startListeningToReviewsTabBadgeUpdates()
136+
startListeningToHubMenuTabBadgeUpdates()
137137
startListeningToOrdersBadge()
138138
}
139139

@@ -467,40 +467,43 @@ private extension MainTabBarController {
467467
}
468468
}
469469

470-
// MARK: - Reviews Tab Badge Updates
470+
// MARK: - Hub Menu Tab Badge Updates
471471
//
472472
private extension MainTabBarController {
473473

474474
/// Setup: KVO Hooks.
475475
///
476-
func startListeningToReviewsTabBadgeUpdates() {
476+
func startListeningToHubMenuTabBadgeUpdates() {
477477
NotificationCenter.default.addObserver(self,
478-
selector: #selector(loadReviewsTabNotificationCountAndUpdateBadge),
478+
selector: #selector(loadHubMenuTabNotificationCountAndUpdateBadge),
479479
name: .reviewsBadgeReloadRequired,
480480
object: nil)
481481
}
482482

483-
@objc func loadReviewsTabNotificationCountAndUpdateBadge() {
483+
@objc func loadHubMenuTabNotificationCountAndUpdateBadge() {
484484
guard let siteID = stores.sessionManager.defaultStoreID else {
485485
return
486486
}
487487

488488
let action = NotificationCountAction.load(siteID: siteID, type: .kind(.comment)) { [weak self] count in
489-
self?.updateReviewsTabBadge(count: count)
489+
self?.updateHubMenuTabBadge(count: count)
490490
}
491491
stores.dispatch(action)
492492
}
493493

494-
/// Displays or Hides the Dot on the Reviews tab, depending on the notification count
494+
/// Displays or Hides the Dot on the Hub Menu tab, depending on the notification count
495495
///
496-
func updateReviewsTabBadge(count: Int) {
497-
//TODO-5509: handle reviews badge
498-
guard !isHubMenuFeatureFlagOn else {
499-
return
496+
func updateHubMenuTabBadge(count: Int) {
497+
if isHubMenuFeatureFlagOn {
498+
let tab = WooTab.hubMenu
499+
let tabIndex = tab.visibleIndex(isHubMenuFeatureFlagOn)
500+
notificationsBadge.badgeCountWasUpdated(newValue: count, tab: tab, in: tabBar, tabIndex: tabIndex)
501+
}
502+
else {
503+
let tab = WooTab.reviews
504+
let tabIndex = tab.visibleIndex(isHubMenuFeatureFlagOn)
505+
notificationsBadge.badgeCountWasUpdated(newValue: count, tab: tab, in: tabBar, tabIndex: tabIndex)
500506
}
501-
let tab = WooTab.reviews
502-
let tabIndex = tab.visibleIndex(isHubMenuFeatureFlagOn)
503-
notificationsBadge.badgeCountWasUpdated(newValue: count, tab: tab, in: tabBar, tabIndex: tabIndex)
504507
}
505508
}
506509

WooCommerce/Classes/ViewRelated/Reviews/ReviewDetailsViewController.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ final class ReviewDetailsViewController: UIViewController {
7575
override func viewWillAppear(_ animated: Bool) {
7676
super.viewWillAppear(animated)
7777
markAsReadIfNeeded(notification)
78+
resetApplicationBadge()
7879
}
7980

8081
override var shouldShowOfflineBanner: Bool {
@@ -127,6 +128,12 @@ private extension ReviewDetailsViewController {
127128
func reloadRows() {
128129
rows = [.header, .content]
129130
}
131+
132+
/// Nukes the BadgeCount
133+
///
134+
func resetApplicationBadge() {
135+
ServiceLocator.pushNotesManager.resetBadgeCount(type: .comment)
136+
}
130137
}
131138

132139

0 commit comments

Comments
 (0)