Skip to content

Commit b633b66

Browse files
authored
Merge pull request #2283 from woocommerce/issue/2042-banner-message
Show different copy in Products tab banner based on Products feature switch in settings
2 parents eb7503f + 905b0c8 commit b633b66

File tree

5 files changed

+110
-28
lines changed

5 files changed

+110
-28
lines changed

WooCommerce/Classes/ViewRelated/BottomButtonContainer/BottomButtonContainerView.swift renamed to WooCommerce/Classes/ViewRelated/Containers/BottomButtonContainer/BottomButtonContainerView.swift

File renamed without changes.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import UIKit
2+
3+
/// Container view for a swappable subview.
4+
final class SwappableSubviewContainerView: UIView {
5+
private var subview: UIView?
6+
7+
init() {
8+
super.init(frame: .zero)
9+
translatesAutoresizingMaskIntoConstraints = false
10+
}
11+
12+
required init?(coder: NSCoder) {
13+
fatalError("init(coder:) has not been implemented")
14+
}
15+
16+
func updateSubview(_ view: UIView) {
17+
subview?.removeFromSuperview()
18+
19+
addSubview(view)
20+
subview = view
21+
pinSubviewToAllEdges(view, insets: .zero)
22+
}
23+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import UIKit
2+
import Yosemite
3+
4+
struct ProductsTopBannerFactory {
5+
/// Creates a products tab top banner asynchronously based on the app settings.
6+
/// - Parameters:
7+
/// - expandedStateChangeHandler: called when the top banner expanded state changes.
8+
/// - onCompletion: called when the view controller is created and ready for display.
9+
static func topBanner(expandedStateChangeHandler: @escaping () -> Void,
10+
onCompletion: @escaping (TopBannerView) -> Void) {
11+
let action = AppSettingsAction.loadProductsFeatureSwitch { isEditProductsRelease2Enabled in
12+
let title = isEditProductsRelease2Enabled ? Strings.titleWhenEditProductsRelease2IsEnabled: Strings.titleWhenEditProductsRelease2IsDisabled
13+
let infoText = isEditProductsRelease2Enabled ? Strings.infoWhenEditProductsRelease2IsEnabled: Strings.infoWhenEditProductsRelease2IsDisabled
14+
let viewModel = TopBannerViewModel(title: title,
15+
infoText: infoText,
16+
icon: .workInProgressBanner,
17+
expandedStateChangeHandler: expandedStateChangeHandler)
18+
let topBannerView = TopBannerView(viewModel: viewModel)
19+
topBannerView.translatesAutoresizingMaskIntoConstraints = false
20+
onCompletion(topBannerView)
21+
}
22+
ServiceLocator.stores.dispatch(action)
23+
}
24+
}
25+
26+
private extension ProductsTopBannerFactory {
27+
enum Strings {
28+
static let titleWhenEditProductsRelease2IsEnabled =
29+
NSLocalizedString("New editing options available",
30+
comment: "The title of the Work In Progress top banner on the Products tab when the Products release 2 feature switch is on.")
31+
static let titleWhenEditProductsRelease2IsDisabled =
32+
NSLocalizedString("Limited editing available",
33+
comment: "The title of the Work In Progress top banner on the Products tab when the Products release 2 feature switch is off.")
34+
static let infoWhenEditProductsRelease2IsEnabled =
35+
NSLocalizedString(
36+
"We've added more editing functionalities to products. You can now update images, see previews and sort, filter & share products!",
37+
comment: "The info of the Work In Progress top banner on the Products tab when the Products release 2 feature switch is on.")
38+
static let infoWhenEditProductsRelease2IsDisabled =
39+
NSLocalizedString("We've added editing functionality to simple products. Keep an eye out for more options soon!",
40+
comment: "The info of the Work In Progress top banner on the Products tab when the Products release 2 feature switch is off.")
41+
}
42+
}

WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ final class ProductsViewController: UIViewController {
3434
/// Top stack view that is shown above the table view as the table header view.
3535
///
3636
private lazy var topStackView: UIStackView = {
37-
let subviews = ServiceLocator.featureFlagService.isFeatureFlagEnabled(.editProductsRelease2) ? [topBannerView, toolbar]: [topBannerView]
37+
let subviews = [topBannerContainerView, toolbar]
3838
let stackView = UIStackView(arrangedSubviews: subviews)
3939
stackView.axis = .vertical
4040
stackView.spacing = 0
@@ -51,11 +51,9 @@ final class ProductsViewController: UIViewController {
5151
/// The filter CTA in the top toolbar.
5252
private lazy var filterButton: UIButton = UIButton(frame: .zero)
5353

54-
/// Top banner that shows that the Products feature is still work in progress.
54+
/// Container of the top banner that shows that the Products feature is still work in progress.
5555
///
56-
private lazy var topBannerView: TopBannerView = {
57-
return createTopBannerView()
58-
}()
56+
private lazy var topBannerContainerView: SwappableSubviewContainerView = SwappableSubviewContainerView()
5957

6058
/// ResultsController: Surrounds us. Binds the galaxy together. And also, keeps the UITableView <> (Stored) Products in sync.
6159
///
@@ -120,6 +118,10 @@ final class ProductsViewController: UIViewController {
120118
}
121119
}
122120

121+
deinit {
122+
NotificationCenter.default.removeObserver(self)
123+
}
124+
123125
// MARK: - View Lifecycle
124126

125127
override func viewDidLoad() {
@@ -131,6 +133,9 @@ final class ProductsViewController: UIViewController {
131133
configureSyncingCoordinator()
132134
registerTableViewCells()
133135

136+
updateTopBannerView()
137+
observeProductsFeatureSwitchChange()
138+
134139
startListeningToNotifications()
135140
syncingCoordinator.resynchronize()
136141
}
@@ -299,25 +304,6 @@ private extension ProductsViewController {
299304
return toolbar
300305
}
301306

302-
func createTopBannerView() -> TopBannerView {
303-
let title: String
304-
let infoText: String
305-
306-
title = NSLocalizedString("Limited editing available",
307-
comment: "The title of the Work In Progress top banner on the Products tab")
308-
infoText = NSLocalizedString("We’ve added editing functionality to simple products. Keep an eye out for more options soon!",
309-
comment: "The info of the Work In Progress top banner on the Products tab")
310-
311-
let viewModel = TopBannerViewModel(title: title,
312-
infoText: infoText,
313-
icon: .workInProgressBanner) { [weak self] in
314-
self?.tableView.updateHeaderHeight()
315-
}
316-
let topBannerView = TopBannerView(viewModel: viewModel)
317-
topBannerView.translatesAutoresizingMaskIntoConstraints = false
318-
return topBannerView
319-
}
320-
321307
/// Setup: Sync'ing Coordinator
322308
///
323309
func configureSyncingCoordinator() {
@@ -334,6 +320,21 @@ private extension ProductsViewController {
334320
// MARK: - Updates
335321
//
336322
private extension ProductsViewController {
323+
func observeProductsFeatureSwitchChange() {
324+
NotificationCenter.default.addObserver(forName: .ProductsFeatureSwitchDidChange, object: nil, queue: nil) { [weak self] _ in
325+
self?.updateTopBannerView()
326+
}
327+
}
328+
329+
func updateTopBannerView() {
330+
ProductsTopBannerFactory.topBanner(expandedStateChangeHandler: { [weak self] in
331+
self?.tableView.updateHeaderHeight()
332+
}, onCompletion: { [weak self] topBannerView in
333+
self?.topBannerContainerView.updateSubview(topBannerView)
334+
self?.tableView.updateHeaderHeight()
335+
})
336+
}
337+
337338
func updateResultsController(siteID: Int64) {
338339
resultsController = createResultsController(siteID: siteID)
339340
configureResultsController(resultsController) { [weak self] in

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@
129129
024EFA6923FCC10B00F36918 /* Product+Media.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024EFA6823FCC10B00F36918 /* Product+Media.swift */; };
130130
02521E11243DC3C400DC7810 /* CancellableMedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02521E10243DC3C400DC7810 /* CancellableMedia.swift */; };
131131
02564A88246C047C00D6DB2A /* Optional+StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02564A87246C047C00D6DB2A /* Optional+StringTests.swift */; };
132+
02564A8A246CDF6100D6DB2A /* ProductsTopBannerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02564A89246CDF6100D6DB2A /* ProductsTopBannerFactory.swift */; };
133+
02564A8C246CE38E00D6DB2A /* SwappableSubviewContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02564A8B246CE38E00D6DB2A /* SwappableSubviewContainerView.swift */; };
132134
0257285C230ACC7E00A288C4 /* StoreStatsV4ChartAxisHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0257285B230ACC7E00A288C4 /* StoreStatsV4ChartAxisHelperTests.swift */; };
133135
0259EF77246BF4EC00B84FDF /* ProductDetailsFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0259EF76246BF4EC00B84FDF /* ProductDetailsFactoryTests.swift */; };
134136
0259EF79246BF66000B84FDF /* MockProductsAppSettingsStoresManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0259EF78246BF66000B84FDF /* MockProductsAppSettingsStoresManager.swift */; };
@@ -194,8 +196,8 @@
194196
02A275C423FE5B64005C560F /* MockPHAssetImageLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A275C323FE5B64005C560F /* MockPHAssetImageLoader.swift */; };
195197
02A275C623FE9EFC005C560F /* MockFeatureFlagService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A275C523FE9EFC005C560F /* MockFeatureFlagService.swift */; };
196198
02A275C823FEA102005C560F /* DefaultProductFormTableViewModel+EditProductsM2Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A275C723FEA102005C560F /* DefaultProductFormTableViewModel+EditProductsM2Tests.swift */; };
197-
02A65301246AA63600755A01 /* ProductDetailsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A65300246AA63600755A01 /* ProductDetailsFactory.swift */; };
198199
02A652FF246A908D00755A01 /* BottomSheetListSelectorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A652FE246A908D00755A01 /* BottomSheetListSelectorPresenter.swift */; };
200+
02A65301246AA63600755A01 /* ProductDetailsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A65300246AA63600755A01 /* ProductDetailsFactory.swift */; };
199201
02A9A496244D84AB00757B99 /* ProductsSortOrderBottomSheetListSelectorCommandTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A9A495244D84AB00757B99 /* ProductsSortOrderBottomSheetListSelectorCommandTests.swift */; };
200202
02ADC7CC239762E0008D4BED /* PaginatedListSelectorViewProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02ADC7CB239762E0008D4BED /* PaginatedListSelectorViewProperties.swift */; };
201203
02ADC7CE23978EAA008D4BED /* PaginatedProductShippingClassListSelectorDataSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02ADC7CD23978EAA008D4BED /* PaginatedProductShippingClassListSelectorDataSourceTests.swift */; };
@@ -978,6 +980,8 @@
978980
024EFA6823FCC10B00F36918 /* Product+Media.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Product+Media.swift"; sourceTree = "<group>"; };
979981
02521E10243DC3C400DC7810 /* CancellableMedia.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CancellableMedia.swift; sourceTree = "<group>"; };
980982
02564A87246C047C00D6DB2A /* Optional+StringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+StringTests.swift"; sourceTree = "<group>"; };
983+
02564A89246CDF6100D6DB2A /* ProductsTopBannerFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductsTopBannerFactory.swift; sourceTree = "<group>"; };
984+
02564A8B246CE38E00D6DB2A /* SwappableSubviewContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwappableSubviewContainerView.swift; sourceTree = "<group>"; };
981985
0257285B230ACC7E00A288C4 /* StoreStatsV4ChartAxisHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreStatsV4ChartAxisHelperTests.swift; sourceTree = "<group>"; };
982986
0259EF76246BF4EC00B84FDF /* ProductDetailsFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductDetailsFactoryTests.swift; sourceTree = "<group>"; };
983987
0259EF78246BF66000B84FDF /* MockProductsAppSettingsStoresManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockProductsAppSettingsStoresManager.swift; sourceTree = "<group>"; };
@@ -1043,8 +1047,8 @@
10431047
02A275C323FE5B64005C560F /* MockPHAssetImageLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPHAssetImageLoader.swift; sourceTree = "<group>"; };
10441048
02A275C523FE9EFC005C560F /* MockFeatureFlagService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFeatureFlagService.swift; sourceTree = "<group>"; };
10451049
02A275C723FEA102005C560F /* DefaultProductFormTableViewModel+EditProductsM2Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DefaultProductFormTableViewModel+EditProductsM2Tests.swift"; sourceTree = "<group>"; };
1046-
02A65300246AA63600755A01 /* ProductDetailsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductDetailsFactory.swift; sourceTree = "<group>"; };
10471050
02A652FE246A908D00755A01 /* BottomSheetListSelectorPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomSheetListSelectorPresenter.swift; sourceTree = "<group>"; };
1051+
02A65300246AA63600755A01 /* ProductDetailsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductDetailsFactory.swift; sourceTree = "<group>"; };
10481052
02A9A495244D84AB00757B99 /* ProductsSortOrderBottomSheetListSelectorCommandTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductsSortOrderBottomSheetListSelectorCommandTests.swift; sourceTree = "<group>"; };
10491053
02ADC7CB239762E0008D4BED /* PaginatedListSelectorViewProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginatedListSelectorViewProperties.swift; sourceTree = "<group>"; };
10501054
02ADC7CD23978EAA008D4BED /* PaginatedProductShippingClassListSelectorDataSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginatedProductShippingClassListSelectorDataSourceTests.swift; sourceTree = "<group>"; };
@@ -1974,6 +1978,15 @@
19741978
path = Command;
19751979
sourceTree = "<group>";
19761980
};
1981+
02564A8F246CEBCB00D6DB2A /* Containers */ = {
1982+
isa = PBXGroup;
1983+
children = (
1984+
02564A8B246CE38E00D6DB2A /* SwappableSubviewContainerView.swift */,
1985+
02C8876F245027F200E4470F /* BottomButtonContainer */,
1986+
);
1987+
path = Containers;
1988+
sourceTree = "<group>";
1989+
};
19771990
025FDD3023717D1A00824006 /* Editor */ = {
19781991
isa = PBXGroup;
19791992
children = (
@@ -2659,6 +2672,7 @@
26592672
74EC34A7225FE69C004BBC2E /* ProductDetailsViewController.xib */,
26602673
0260F40023224E8100EDA10A /* ProductsViewController.swift */,
26612674
020DD49023239DD6005822B1 /* PaginatedListViewControllerStateCoordinator.swift */,
2675+
02564A89246CDF6100D6DB2A /* ProductsTopBannerFactory.swift */,
26622676
);
26632677
path = Products;
26642678
sourceTree = "<group>";
@@ -2883,9 +2897,9 @@
28832897
B56DB3EF2049C06D00D4AA8E /* ViewRelated */ = {
28842898
isa = PBXGroup;
28852899
children = (
2886-
027D67CF245ADDCC0036B8DB /* Filters */,
2887-
02C8876F245027F200E4470F /* BottomButtonContainer */,
28882900
0235594024496414004BE2B8 /* BottomSheet */,
2901+
02564A8F246CEBCB00D6DB2A /* Containers */,
2902+
027D67CF245ADDCC0036B8DB /* Filters */,
28892903
02E262C3238D04DB00B79588 /* ListSelector */,
28902904
028296E9237D289900E84012 /* Text View Screen */,
28912905
025FDD3023717D1A00824006 /* Editor */,
@@ -4708,6 +4722,7 @@
47084722
D82DFB4A225F22D400EFE2CB /* UISearchBar+Appearance.swift in Sources */,
47094723
7441E1D221503F77004E6ECE /* IntrinsicTableView.swift in Sources */,
47104724
B517EA1D218B41F200730EC4 /* String+Woo.swift in Sources */,
4725+
02564A8C246CE38E00D6DB2A /* SwappableSubviewContainerView.swift in Sources */,
47114726
024DF31223742B18006658FE /* AztecItalicFormatBarCommand.swift in Sources */,
47124727
D83F5933225B2EB900626E75 /* ManualTrackingViewController.swift in Sources */,
47134728
B57C744A20F5649300EEFC87 /* EmptyStoresTableViewCell.swift in Sources */,
@@ -4900,6 +4915,7 @@
49004915
CE1CCB4B20570B1F000EE3AC /* OrderTableViewCell.swift in Sources */,
49014916
748AD087219F481B00023535 /* UIView+Animation.swift in Sources */,
49024917
748D34DF214828DD00E21A2F /* TopPerformersViewController.swift in Sources */,
4918+
02564A8A246CDF6100D6DB2A /* ProductsTopBannerFactory.swift in Sources */,
49034919
B509FED321C05121000076A9 /* SupportManagerAdapter.swift in Sources */,
49044920
B5AA7B3D20ED5D15004DA14F /* SessionManager.swift in Sources */,
49054921
74C6FEA521C2F1FA009286B6 /* AboutViewController.swift in Sources */,

0 commit comments

Comments
 (0)