Skip to content

Commit 3daf001

Browse files
committed
Create BottomButtonContainerView for a container component and add "+ More details" CTA to product form if M2 feature flag is enabled.
1 parent 5487f16 commit 3daf001

File tree

5 files changed

+157
-13
lines changed

5 files changed

+157
-13
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import UIKit
2+
3+
extension UIButton {
4+
/// Sets a spacing between button title and image.
5+
/// - Parameters:
6+
/// - spacing: spacing between the title and image.
7+
/// - layoutDirection: layout direction of the button (LTR/RTL).
8+
func distributeTitleAndImage(spacing: CGFloat, layoutDirection: UIUserInterfaceLayoutDirection = UIApplication.shared.userInterfaceLayoutDirection) {
9+
let insetAmount = spacing / 2.0
10+
11+
switch layoutDirection {
12+
case .rightToLeft:
13+
imageEdgeInsets = UIEdgeInsets(top: imageEdgeInsets.top, left: insetAmount, bottom: imageEdgeInsets.bottom, right: imageEdgeInsets.right)
14+
titleEdgeInsets = UIEdgeInsets(top: titleEdgeInsets.top, left: titleEdgeInsets.left, bottom: titleEdgeInsets.bottom, right: insetAmount)
15+
default:
16+
imageEdgeInsets = UIEdgeInsets(top: imageEdgeInsets.top, left: imageEdgeInsets.left, bottom: imageEdgeInsets.bottom, right: insetAmount)
17+
titleEdgeInsets = UIEdgeInsets(top: titleEdgeInsets.top, left: insetAmount, bottom: titleEdgeInsets.bottom, right: titleEdgeInsets.right)
18+
}
19+
}
20+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import UIKit
2+
3+
/// Contains a button with insets to be displayed at the bottom of a view.
4+
///
5+
final class BottomButtonContainerView: UIView {
6+
struct ViewModel {
7+
/// Allows the view model to configure and style the button.
8+
let configureButton: (UIButton) -> Void
9+
10+
/// Called when the button is tapped.
11+
let onButtonTapped: () -> Void
12+
}
13+
14+
private let button: UIButton = UIButton(type: .custom)
15+
16+
private let viewModel: ViewModel
17+
18+
init(viewModel: ViewModel) {
19+
self.viewModel = viewModel
20+
super.init(frame: .zero)
21+
22+
translatesAutoresizingMaskIntoConstraints = false
23+
configureContainerView()
24+
configureButton()
25+
}
26+
27+
required init?(coder: NSCoder) {
28+
fatalError("init(coder:) has not been implemented")
29+
}
30+
}
31+
32+
private extension BottomButtonContainerView {
33+
func configureContainerView() {
34+
backgroundColor = .basicBackground
35+
36+
let topBorderView = UIView.createBorderView()
37+
addSubview(topBorderView)
38+
NSLayoutConstraint.activate([
39+
topBorderView.leadingAnchor.constraint(equalTo: leadingAnchor),
40+
topBorderView.trailingAnchor.constraint(equalTo: trailingAnchor),
41+
topBorderView.topAnchor.constraint(equalTo: topAnchor)
42+
])
43+
}
44+
45+
func configureButton() {
46+
addSubview(button)
47+
button.translatesAutoresizingMaskIntoConstraints = false
48+
pinSubviewToAllEdges(button, insets: Constants.buttonMarginInsets)
49+
50+
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
51+
52+
viewModel.configureButton(button)
53+
}
54+
55+
@objc func buttonTapped() {
56+
viewModel.onButtonTapped()
57+
}
58+
}
59+
60+
private extension BottomButtonContainerView {
61+
enum Constants {
62+
static let buttonMarginInsets = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
63+
}
64+
}

WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewController.swift

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Yosemite
66
final class ProductFormViewController: UIViewController {
77

88
@IBOutlet private weak var tableView: UITableView!
9+
@IBOutlet private weak var moreDetailsContainerView: UIView!
910

1011
private lazy var keyboardFrameObserver: KeyboardFrameObserver = {
1112
let keyboardFrameObserver = KeyboardFrameObserver { [weak self] keyboardFrame in
@@ -54,9 +55,11 @@ final class ProductFormViewController: UIViewController {
5455
private let productUIImageLoader: ProductUIImageLoader
5556

5657
private let currency: String
58+
private let featureFlagService: FeatureFlagService
5759

58-
init(product: Product, currency: String) {
60+
init(product: Product, currency: String, featureFlagService: FeatureFlagService = ServiceLocator.featureFlagService) {
5961
self.currency = currency
62+
self.featureFlagService = featureFlagService
6063
self.originalProduct = product
6164
self.product = product
6265
self.viewModel = DefaultProductFormTableViewModel(product: product, currency: currency)
@@ -85,6 +88,7 @@ final class ProductFormViewController: UIViewController {
8588
configureNavigationBar()
8689
configureMainView()
8790
configureTableView()
91+
configureMoreDetailsContainerView()
8892

8993
startListeningToNotifications()
9094
handleSwipeBackGesture()
@@ -118,7 +122,7 @@ private extension ProductFormViewController {
118122
}
119123

120124
func configureMainView() {
121-
view.backgroundColor = .listBackground
125+
view.backgroundColor = .basicBackground
122126
}
123127

124128
func configureTableView() {
@@ -127,7 +131,7 @@ private extension ProductFormViewController {
127131
tableView.dataSource = tableViewDataSource
128132
tableView.delegate = self
129133

130-
tableView.backgroundColor = .listBackground
134+
tableView.backgroundColor = .listForeground
131135
tableView.removeLastCellSeparator()
132136

133137
tableView.reloadData()
@@ -149,6 +153,33 @@ private extension ProductFormViewController {
149153
}
150154
}
151155
}
156+
157+
func configureMoreDetailsContainerView() {
158+
guard featureFlagService.isFeatureFlagEnabled(.editProductsRelease2) else {
159+
moreDetailsContainerView.isHidden = true
160+
return
161+
}
162+
163+
let viewModel = BottomButtonContainerView.ViewModel(configureButton: { button in
164+
let title = NSLocalizedString("Add more details", comment: "")
165+
button.setTitle(title, for: .normal)
166+
167+
let icon = UIImage.plusImage
168+
button.setImage(icon, for: .normal)
169+
button.contentHorizontalAlignment = .leading
170+
button.applyLinkButtonStyle()
171+
button.contentEdgeInsets = .zero
172+
button.distributeTitleAndImage(spacing: 16)
173+
}, onButtonTapped: {
174+
// TODO-2053: show more details bottom sheet
175+
})
176+
let buttonContainerView = BottomButtonContainerView(viewModel: viewModel)
177+
178+
moreDetailsContainerView.addSubview(buttonContainerView)
179+
moreDetailsContainerView.pinSubviewToAllEdges(buttonContainerView)
180+
moreDetailsContainerView.setContentCompressionResistancePriority(.required, for: .vertical)
181+
moreDetailsContainerView.setContentHuggingPriority(.required, for: .vertical)
182+
}
152183
}
153184

154185
// MARK: Navigation actions
@@ -355,7 +386,7 @@ extension ProductFormViewController: UITableViewDelegate {
355386
switch section {
356387
case .settings:
357388
let clearView = UIView(frame: .zero)
358-
clearView.backgroundColor = .clear
389+
clearView.backgroundColor = .listBackground
359390
return clearView
360391
default:
361392
return nil

WooCommerce/Classes/ViewRelated/Products/Edit Product/ProductFormViewController.xib

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
2+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
33
<device id="retina6_1" orientation="portrait" appearance="light"/>
44
<dependencies>
55
<deployment identifier="iOS"/>
6-
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
6+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16086"/>
77
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
88
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
99
</dependencies>
1010
<objects>
1111
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ProductFormViewController" customModule="WooCommerce" customModuleProvider="target">
1212
<connections>
13+
<outlet property="moreDetailsContainerView" destination="wEZ-yI-3BV" id="t5o-n0-TNf"/>
1314
<outlet property="tableView" destination="jKS-9T-UtT" id="B2S-Hy-ugv"/>
1415
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
1516
</connections>
@@ -19,17 +20,29 @@
1920
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
2021
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
2122
<subviews>
22-
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="jKS-9T-UtT">
23+
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="lnJ-QS-EwA">
2324
<rect key="frame" x="0.0" y="44" width="414" height="818"/>
24-
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
25-
</tableView>
25+
<subviews>
26+
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="jKS-9T-UtT">
27+
<rect key="frame" x="0.0" y="0.0" width="414" height="768"/>
28+
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
29+
</tableView>
30+
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wEZ-yI-3BV">
31+
<rect key="frame" x="0.0" y="768" width="414" height="50"/>
32+
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
33+
<constraints>
34+
<constraint firstAttribute="height" constant="50" placeholder="YES" id="4De-Hk-k6R"/>
35+
</constraints>
36+
</view>
37+
</subviews>
38+
</stackView>
2639
</subviews>
2740
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
2841
<constraints>
29-
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="jKS-9T-UtT" secondAttribute="trailing" id="IAY-Ez-MeG"/>
30-
<constraint firstItem="jKS-9T-UtT" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="XNr-rD-CSG"/>
31-
<constraint firstItem="jKS-9T-UtT" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" id="XUS-aw-ncD"/>
32-
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="jKS-9T-UtT" secondAttribute="bottom" id="ki0-L9-nvX"/>
42+
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="lnJ-QS-EwA" secondAttribute="bottom" id="2pu-vl-eJo"/>
43+
<constraint firstItem="lnJ-QS-EwA" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" id="iSP-Yg-fhy"/>
44+
<constraint firstItem="lnJ-QS-EwA" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="lnT-av-lRI"/>
45+
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="lnJ-QS-EwA" secondAttribute="trailing" id="pRJ-Xx-P8D"/>
3346
</constraints>
3447
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
3548
<point key="canvasLocation" x="139" y="96"/>

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@
178178
02913E9523A774C500707A0C /* UnitInputFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02913E9423A774C500707A0C /* UnitInputFormatter.swift */; };
179179
02913E9723A774E600707A0C /* DecimalInputFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02913E9623A774E600707A0C /* DecimalInputFormatter.swift */; };
180180
029B0F57234197B80010C1F3 /* ProductSearchUICommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 029B0F56234197B80010C1F3 /* ProductSearchUICommand.swift */; };
181+
029BFD4D245970F600FDDEEC /* BottomButtonContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 029BFD4C245970F600FDDEEC /* BottomButtonContainerView.swift */; };
182+
029BFD4F24597D4B00FDDEEC /* UIButton+TitleAndImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 029BFD4E24597D4B00FDDEEC /* UIButton+TitleAndImage.swift */; };
181183
029D444922F13F8A00DEFA8A /* DashboardUIFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 029D444822F13F8A00DEFA8A /* DashboardUIFactory.swift */; };
182184
029D444E22F141CD00DEFA8A /* DashboardStatsV3ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 029D444D22F141CD00DEFA8A /* DashboardStatsV3ViewController.swift */; };
183185
02A275BA23FE50AA005C560F /* ProductUIImageLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A275B923FE50AA005C560F /* ProductUIImageLoader.swift */; };
@@ -997,6 +999,8 @@
997999
02913E9423A774C500707A0C /* UnitInputFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitInputFormatter.swift; sourceTree = "<group>"; };
9981000
02913E9623A774E600707A0C /* DecimalInputFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecimalInputFormatter.swift; sourceTree = "<group>"; };
9991001
029B0F56234197B80010C1F3 /* ProductSearchUICommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductSearchUICommand.swift; sourceTree = "<group>"; };
1002+
029BFD4C245970F600FDDEEC /* BottomButtonContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomButtonContainerView.swift; sourceTree = "<group>"; };
1003+
029BFD4E24597D4B00FDDEEC /* UIButton+TitleAndImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+TitleAndImage.swift"; sourceTree = "<group>"; };
10001004
029D444822F13F8A00DEFA8A /* DashboardUIFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardUIFactory.swift; sourceTree = "<group>"; };
10011005
029D444D22F141CD00DEFA8A /* DashboardStatsV3ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardStatsV3ViewController.swift; sourceTree = "<group>"; };
10021006
02A275B923FE50AA005C560F /* ProductUIImageLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductUIImageLoader.swift; sourceTree = "<group>"; };
@@ -2090,6 +2094,14 @@
20902094
path = Product;
20912095
sourceTree = "<group>";
20922096
};
2097+
029BFD4B2459702200FDDEEC /* BottomButtonContainer */ = {
2098+
isa = PBXGroup;
2099+
children = (
2100+
029BFD4C245970F600FDDEEC /* BottomButtonContainerView.swift */,
2101+
);
2102+
path = BottomButtonContainer;
2103+
sourceTree = "<group>";
2104+
};
20932105
029D444722F13F5C00DEFA8A /* Factories */ = {
20942106
isa = PBXGroup;
20952107
children = (
@@ -2732,6 +2744,7 @@
27322744
B56DB3EF2049C06D00D4AA8E /* ViewRelated */ = {
27332745
isa = PBXGroup;
27342746
children = (
2747+
029BFD4B2459702200FDDEEC /* BottomButtonContainer */,
27352748
0235594024496414004BE2B8 /* BottomSheet */,
27362749
02E262C3238D04DB00B79588 /* ListSelector */,
27372750
028296E9237D289900E84012 /* Text View Screen */,
@@ -3292,6 +3305,7 @@
32923305
02396250239948470096F34C /* UIImage+TintColor.swift */,
32933306
F997174323DC065900592D8E /* XLPagerStrip+AccessibilityIdentifier.swift */,
32943307
0215320A24231D5A003F2BBD /* UIStackView+Subviews.swift */,
3308+
029BFD4E24597D4B00FDDEEC /* UIButton+TitleAndImage.swift */,
32953309
);
32963310
path = Extensions;
32973311
sourceTree = "<group>";
@@ -4380,6 +4394,7 @@
43804394
D8C251D2230CA90200F49782 /* StoresManager.swift in Sources */,
43814395
02DD81FA242CAA400060E50B /* Media+WPMediaAsset.swift in Sources */,
43824396
024DF31F23743045006658FE /* Header+AztecFormatting.swift in Sources */,
4397+
029BFD4F24597D4B00FDDEEC /* UIButton+TitleAndImage.swift in Sources */,
43834398
B50911312049E27A007D25DC /* OrdersViewController.swift in Sources */,
43844399
B5A8F8AD20B88D9900D211DE /* LoginPrologueViewController.swift in Sources */,
43854400
B5D1AFC620BC7B7300DB0E8C /* StorePickerViewController.swift in Sources */,
@@ -4410,6 +4425,7 @@
44104425
D817586222BB64C300289CFE /* OrderDetailsNotices.swift in Sources */,
44114426
0282DD94233C9465006A5FDB /* SearchUICommand.swift in Sources */,
44124427
028BAC4722F3B550008BB4AF /* StatsTimeRangeV4+UI.swift in Sources */,
4428+
029BFD4D245970F600FDDEEC /* BottomButtonContainerView.swift in Sources */,
44134429
024DF32123744798006658FE /* AztecFormatBarCommandCoordinator.swift in Sources */,
44144430
B5AA7B3F20ED81C2004DA14F /* UserDefaults+Woo.swift in Sources */,
44154431
0274C25423162FB200EF1E40 /* DashboardTopBannerFactory.swift in Sources */,

0 commit comments

Comments
 (0)