Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions WooCommerce/Classes/Extensions/UIButton+Helpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ extension UIButton {

setTitleColor(.accent, for: .normal)
setTitleColor(.accentDark, for: .highlighted)
setTitleColor(.buttonDisabledTitle, for: .disabled)
}

/// Applies the Modal Cancel Button Style
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ class ProductListViewModel {
selectedProducts.count
}

var bulkEditActionIsEnabled: Bool {
!selectedProducts.isEmpty
}

func productIsSelected(_ productToCheck: Product) -> Bool {
return selectedProducts.contains(productToCheck)
}
Expand Down
102 changes: 96 additions & 6 deletions WooCommerce/Classes/ViewRelated/Products/ProductsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,44 @@ final class ProductsViewController: UIViewController, GhostableViewController {
///
@IBOutlet private weak var toolbar: ToolbarView!

/// Top toolbar that shows the bulk edit CTA.
///
@IBOutlet private weak var bottomToolbar: ToolbarView! {
didSet {
bottomToolbar.isHidden = true
bottomToolbar.backgroundColor = .systemColor(.secondarySystemGroupedBackground)
bottomToolbar.setSubviews(leftViews: [], rightViews: [bulkEditButton])
bottomToolbar.addDividerOnTop()
}
}

/// Bottom placeholder inside StackView to cover the safe area gap below the bottom toolbar.
///
@IBOutlet private weak var bottomPlaceholder: UIView! {
didSet {
bottomPlaceholder.backgroundColor = .systemColor(.secondarySystemGroupedBackground)
}
}

// Used to trick the navigation bar for large title (ref: issue 3 in p91TBi-45c-p2).
private let hiddenScrollView = UIScrollView()

/// The filter CTA in the top toolbar.
private lazy var filterButton: UIButton = UIButton(frame: .zero)

/// The bulk edit CTA in the bottom toolbar.
private lazy var bulkEditButton: UIButton = {
let button = UIButton(frame: .zero)
button.setTitle(Localization.bulkEditingToolbarButtonTitle, for: .normal)
button.addTarget(self, action: #selector(openBulkEditingOptions(sender:)), for: .touchUpInside)
button.applyLinkButtonStyle()
var configuration = UIButton.Configuration.plain()
configuration.contentInsets = Constants.toolbarButtonInsets
button.configuration = configuration
button.isEnabled = false
return button
}()

/// Container of the top banner that shows that the Products feature is still work in progress.
///
private lazy var topBannerContainerView: SwappableSubviewContainerView = SwappableSubviewContainerView()
Expand Down Expand Up @@ -273,6 +305,7 @@ private extension ProductsViewController {

configureNavigationBarForEditing()
showOrHideToolbar()
showBottomToolbar()
}

@objc func finishBulkEditing() {
Expand All @@ -284,6 +317,35 @@ private extension ProductsViewController {

configureNavigationBar()
showOrHideToolbar()
hideBottomToolbar()
}

func updatedSelectedItems() {
updateNavigationBarTitleForEditing()
bulkEditButton.isEnabled = viewModel.bulkEditActionIsEnabled
}

@objc func openBulkEditingOptions(sender: UIButton) {
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

let updateStatus = UIAlertAction(title: Localization.bulkEditingStatusOption, style: .default) { _ in
// TODO-8519: show UI for status update
}
let updatePrice = UIAlertAction(title: Localization.bulkEditingPriceOption, style: .default) { _ in
// TODO-8520: show UI for price update
}
let cancelAction = UIAlertAction(title: Localization.cancel, style: .cancel)

actionSheet.addAction(updateStatus)
actionSheet.addAction(updatePrice)
actionSheet.addAction(cancelAction)

if let popoverController = actionSheet.popoverPresentationController {
popoverController.sourceView = sender
popoverController.sourceRect = sender.bounds
}

present(actionSheet, animated: true)
}
}

Expand Down Expand Up @@ -361,11 +423,11 @@ private extension ProductsViewController {
}

func configureNavigationBarForEditing() {
configureNavigationBarTitleForEditing()
updateNavigationBarTitleForEditing()
configureNavigationBarRightButtonItemsForEditing()
}

func configureNavigationBarTitleForEditing() {
func updateNavigationBarTitleForEditing() {
let selectedProducts = viewModel.selectedProductsCount
if selectedProducts == 0 {
navigationItem.title = Localization.bulkEditingTitle
Expand Down Expand Up @@ -459,7 +521,9 @@ private extension ProductsViewController {

[sortButton, filterButton].forEach {
$0.applyLinkButtonStyle()
$0.contentEdgeInsets = Constants.toolbarButtonInsets
var configuration = UIButton.Configuration.plain()
configuration.contentInsets = Constants.toolbarButtonInsets
$0.configuration = configuration
}

toolbar.backgroundColor = .systemColor(.secondarySystemGroupedBackground)
Expand Down Expand Up @@ -491,6 +555,24 @@ private extension ProductsViewController {

toolbar.isHidden = filters.numberOfActiveFilters == 0 ? isEmpty : false
}

func showBottomToolbar() {
tabBarController?.tabBar.isHidden = true

// trigger safe area update
if let tabBarController {
let currentFrame = tabBarController.view.frame
tabBarController.view.frame = currentFrame.insetBy(dx: 0, dy: 1)
tabBarController.view.frame = currentFrame
}
Comment on lines +562 to +567
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice trick, maybe we can wrap this in a small extension helper!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll keep it inline for now and hope safe areas will "just work" going forward 🙂
But feel free to convert it to extension if you spot similar issue in other views.


bottomToolbar.isHidden = false
}

func hideBottomToolbar() {
tabBarController?.tabBar.isHidden = false
bottomToolbar.isHidden = true
}
}

// MARK: - Updates
Expand Down Expand Up @@ -673,7 +755,7 @@ extension ProductsViewController: UITableViewDelegate {

if tableView.isEditing {
viewModel.selectProduct(product)
configureNavigationBarTitleForEditing()
updatedSelectedItems()
} else {
tableView.deselectRow(at: indexPath, animated: true)

Expand All @@ -690,7 +772,7 @@ extension ProductsViewController: UITableViewDelegate {

let product = resultsController.object(at: indexPath)
viewModel.deselectProduct(product)
configureNavigationBarTitleForEditing()
updatedSelectedItems()
}

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
Expand Down Expand Up @@ -1109,7 +1191,7 @@ private extension ProductsViewController {
static let placeholderRowsPerSection = [3]
static let headerDefaultHeight = CGFloat(130)
static let headerContainerInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
static let toolbarButtonInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16)
static let toolbarButtonInsets = NSDirectionalEdgeInsets(top: 12, leading: 16, bottom: 12, trailing: 16)
}

enum Localization {
Expand All @@ -1120,6 +1202,14 @@ private extension ProductsViewController {
comment: "VoiceOver accessibility hint, informing the user the button can be used to bulk edit products"
)

static let bulkEditingToolbarButtonTitle = NSLocalizedString(
"Bulk update",
comment: "Title of a button that presents a menu with possible products bulk update options"
)
static let bulkEditingStatusOption = NSLocalizedString("Update status", comment: "Title of an option that opens bulk products status update flow")
static let bulkEditingPriceOption = NSLocalizedString("Update price", comment: "Title of an option that opens bulk products price update flow")
static let cancel = NSLocalizedString("Cancel", comment: "Title of an option to dismiss the bulk edit action sheet")

static let bulkEditingTitle = NSLocalizedString(
"Select items",
comment: "Title that appears on top of the Product List screen when bulk editing starts."
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ProductsViewController" customModule="WooCommerce" customModuleProvider="target">
<connections>
<outlet property="bottomPlaceholder" destination="xLN-As-fgq" id="bwi-vq-EvS"/>
<outlet property="bottomToolbar" destination="pNN-uJ-nMs" id="Z6G-Im-KE6"/>
<outlet property="tableView" destination="1mE-SE-uK9" id="ogX-nu-l5x"/>
<outlet property="toolbar" destination="9eA-hc-k15" id="V2c-iT-WpM"/>
<outlet property="view" destination="iN0-l3-epB" id="Jh9-wF-LZg"/>
Expand All @@ -22,21 +24,32 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="tDW-j0-dUT">
<rect key="frame" x="0.0" y="44" width="414" height="818"/>
<rect key="frame" x="0.0" y="48" width="414" height="848"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9eA-hc-k15" userLabel="Filter Bar" customClass="ToolbarView" customModule="WooCommerce" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="414" height="50"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="sEi-OR-bvb"/>
<constraint firstAttribute="height" priority="995" constant="50" id="sEi-OR-bvb"/>
</constraints>
</view>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="1mE-SE-uK9">
<rect key="frame" x="0.0" y="50" width="414" height="768"/>
<rect key="frame" x="0.0" y="50" width="414" height="714"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="orders-table-view"/>
</userDefinedRuntimeAttributes>
</tableView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pNN-uJ-nMs" userLabel="Bulk Edit Bar" customClass="ToolbarView" customModule="WooCommerce" customModuleProvider="target">
<rect key="frame" x="0.0" y="764" width="414" height="50"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="height" priority="995" constant="50" id="mXV-oU-3bM"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xLN-As-fgq" userLabel="Safe Area Placeholder">
<rect key="frame" x="0.0" y="814" width="414" height="34"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
</subviews>
<constraints>
<constraint firstItem="9eA-hc-k15" firstAttribute="leading" secondItem="tDW-j0-dUT" secondAttribute="leading" id="2Md-DN-FrJ"/>
Expand All @@ -45,7 +58,7 @@
<constraint firstItem="1mE-SE-uK9" firstAttribute="trailing" secondItem="9eA-hc-k15" secondAttribute="trailing" id="g0z-q4-rFD"/>
<constraint firstItem="1mE-SE-uK9" firstAttribute="leading" secondItem="9eA-hc-k15" secondAttribute="leading" id="i2H-MX-SoN"/>
<constraint firstItem="9eA-hc-k15" firstAttribute="top" secondItem="tDW-j0-dUT" secondAttribute="top" id="ilw-mJ-v1G"/>
<constraint firstAttribute="bottom" secondItem="1mE-SE-uK9" secondAttribute="bottom" id="jCv-iK-SJb"/>
<constraint firstItem="pNN-uJ-nMs" firstAttribute="top" secondItem="1mE-SE-uK9" secondAttribute="bottom" id="mlT-bM-H2X"/>
</constraints>
</stackView>
</subviews>
Expand All @@ -54,8 +67,10 @@
<constraints>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="tDW-j0-dUT" secondAttribute="trailing" id="3MC-6D-nnm"/>
<constraint firstItem="tDW-j0-dUT" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" id="9UK-Qy-FXd"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="tDW-j0-dUT" secondAttribute="bottom" id="AQF-qF-3wt"/>
<constraint firstAttribute="bottom" secondItem="tDW-j0-dUT" secondAttribute="bottom" id="AQF-qF-3wt"/>
<constraint firstItem="xLN-As-fgq" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="Iu8-XK-w4W"/>
<constraint firstItem="tDW-j0-dUT" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="KSv-iL-NFv"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="pNN-uJ-nMs" secondAttribute="bottom" id="xJE-yf-lID"/>
</constraints>
<point key="canvasLocation" x="100.00000000000001" y="48.883928571428569"/>
</view>
Expand Down
14 changes: 14 additions & 0 deletions WooCommerce/Classes/ViewRelated/Toolbar/ToolbarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@ final class ToolbarView: UIView {
pinSubviewToAllEdges(stackView)
}

func addDividerOnTop() {
let divider = UIView()
divider.backgroundColor = .divider
divider.translatesAutoresizingMaskIntoConstraints = false
addSubview(divider)

NSLayoutConstraint.activate([
divider.heightAnchor.constraint(equalToConstant: 1/UIScreen.main.scale),
divider.topAnchor.constraint(equalTo: topAnchor),
divider.leadingAnchor.constraint(equalTo: leadingAnchor),
divider.trailingAnchor.constraint(equalTo: trailingAnchor)
])
}

func setSubviews(leftViews: [UIView], rightViews: [UIView]) {
stackView.removeAllArrangedSubviews()

Expand Down