Skip to content

Commit bb11d05

Browse files
authored
Merge pull request #6535 from woocommerce/issue/2448-use-GhostTableViewController-everywhere-part1
Use GhostableViewController for all cases, part 1
2 parents 462691f + 305eac3 commit bb11d05

File tree

14 files changed

+69
-139
lines changed

14 files changed

+69
-139
lines changed

WooCommerce/Classes/ViewRelated/Coupons/CouponListViewController.swift

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import UIKit
33
import WordPressUI
44
import class SwiftUI.UIHostingController
55

6-
final class CouponListViewController: UIViewController {
6+
final class CouponListViewController: UIViewController, GhostableViewController {
77
@IBOutlet private weak var tableView: UITableView!
88
private let viewModel: CouponListViewModel
99
private let siteID: Int64
@@ -12,6 +12,12 @@ final class CouponListViewController: UIViewController {
1212
///
1313
private var emptyStateViewController: UIViewController?
1414

15+
lazy var ghostTableViewController = GhostTableViewController(options: GhostTableViewOptions(displaysSectionHeader: false,
16+
cellClass: TitleAndSubtitleAndStatusTableViewCell.self,
17+
rowsPerSection: Constants.placeholderRowsPerSection,
18+
estimatedRowHeight: Constants.estimatedRowHeight,
19+
backgroundColor: .basicBackground))
20+
1521
/// Pull To Refresh Support.
1622
///
1723
private lazy var refreshControl: UIRefreshControl = {
@@ -293,17 +299,13 @@ extension CouponListViewController {
293299
/// Renders the Placeholder Coupons
294300
///
295301
func displayPlaceholderCoupons() {
296-
let options = GhostOptions(displaysSectionHeader: false,
297-
reuseIdentifier: TitleAndSubtitleAndStatusTableViewCell.reuseIdentifier,
298-
rowsPerSection: Constants.placeholderRowsPerSection)
299-
tableView.displayGhostContent(options: options,
300-
style: .wooDefaultGhostStyle)
302+
displayGhostContent()
301303
}
302304

303305
/// Removes the Placeholder Coupons
304306
///
305307
func removePlaceholderCoupons() {
306-
tableView.removeGhostContent()
308+
removeGhostContent()
307309
}
308310
}
309311

WooCommerce/Classes/ViewRelated/Dashboard/MyStore/TopPerformerDataViewController.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ final class TopPerformerDataViewController: UIViewController, GhostableViewContr
2727
///
2828
lazy var ghostTableViewController = GhostTableViewController(options: GhostTableViewOptions(displaysSectionHeader: false,
2929
cellClass: ProductTableViewCell.self,
30-
estimatedRowHeight: Constants.estimatedRowHeight))
30+
estimatedRowHeight: Constants.estimatedRowHeight,
31+
backgroundColor: .basicBackground,
32+
separatorStyle: .none))
3133

3234
/// ResultsController: Loads TopEarnerStats for the current granularity from the Storage Layer
3335
///

WooCommerce/Classes/ViewRelated/Dashboard/Settings/Plugins/PluginListViewController.swift

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@ import WordPressUI
33

44
/// View Controller for the Plugin List Screen.
55
///
6-
final class PluginListViewController: UIViewController {
6+
final class PluginListViewController: UIViewController, GhostableViewController {
77

88
private let viewModel: PluginListViewModel
99

1010
@IBOutlet private var tableView: UITableView!
1111

12-
/// Separate table view for ghost animation.
13-
///
14-
private let ghostTableView = UITableView(frame: .zero, style: .grouped)
12+
lazy var ghostTableViewController = GhostTableViewController(options: GhostTableViewOptions(cellClass: HeadlineLabelTableViewCell.self,
13+
rowsPerSection: [10],
14+
tableViewStyle: .grouped,
15+
isScrollEnabled: false))
1516

1617
/// Pull To Refresh Support.
1718
///
@@ -42,7 +43,6 @@ final class PluginListViewController: UIViewController {
4243
super.viewDidLoad()
4344
configureNavigation()
4445
configureTableView()
45-
configureGhostTableView()
4646
configureViewModel()
4747
}
4848
}
@@ -63,30 +63,6 @@ private extension PluginListViewController {
6363
tableView.dataSource = self
6464
}
6565

66-
func configureGhostTableView() {
67-
ghostTableView.registerNib(for: HeadlineLabelTableViewCell.self)
68-
ghostTableView.translatesAutoresizingMaskIntoConstraints = false
69-
ghostTableView.backgroundColor = .listBackground
70-
ghostTableView.isScrollEnabled = false
71-
ghostTableView.isHidden = true
72-
73-
view.addSubview(ghostTableView)
74-
view.pinSubviewToAllEdges(ghostTableView)
75-
}
76-
77-
func startGhostAnimation() {
78-
let options = GhostOptions(reuseIdentifier: HeadlineLabelTableViewCell.reuseIdentifier, rowsPerSection: [10])
79-
ghostTableView.displayGhostContent(options: options, style: .wooDefaultGhostStyle)
80-
ghostTableView.startGhostAnimation()
81-
ghostTableView.isHidden = false
82-
}
83-
84-
func stopGhostAnimation() {
85-
ghostTableView.isHidden = true
86-
ghostTableView.stopGhostAnimation()
87-
ghostTableView.removeGhostContent()
88-
}
89-
9066
func configureViewModel() {
9167
viewModel.observePlugins { [weak self] in
9268
self?.tableView.reloadData()
@@ -105,12 +81,12 @@ private extension PluginListViewController {
10581
@objc func syncPlugins() {
10682
removeErrorStateView()
10783
if viewModel.numberOfSections == 0 {
108-
startGhostAnimation()
84+
displayGhostContent()
10985
}
11086
viewModel.syncPlugins { [weak self] result in
11187
guard let self = self else { return }
11288
self.refreshControl.endRefreshing()
113-
self.stopGhostAnimation()
89+
self.removeGhostContent()
11490
if result.isFailure {
11591
self.displayErrorStateView()
11692
}

WooCommerce/Classes/ViewRelated/ListSelector/PaginatedListSelectorViewController.swift

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,17 @@ extension PaginatedListSelectorDataSource {
5454
/// Displays a paginated list (implemented by table view) for the user to select a generic model.
5555
///
5656
final class PaginatedListSelectorViewController<DataSource: PaginatedListSelectorDataSource, Model, StorageModel, Cell>: UIViewController,
57-
UITableViewDataSource, UITableViewDelegate, UITableViewDragDelegate, PaginationTrackerDelegate
57+
UITableViewDataSource, UITableViewDelegate, UITableViewDragDelegate, PaginationTrackerDelegate, GhostableViewController
5858
where DataSource.StorageModel == StorageModel, Model == DataSource.StorageModel.ReadOnlyType, Model: Equatable, DataSource.Cell == Cell {
5959
private let viewProperties: PaginatedListSelectorViewProperties
6060
private var dataSource: DataSource
6161
private let onDismiss: (_ selected: Model?) -> Void
6262

6363
private let rowType = Cell.self
6464

65+
lazy var ghostTableViewController = GhostTableViewController(options: GhostTableViewOptions(cellClass: Cell.self,
66+
separatorStyle: viewProperties.separatorStyle))
67+
6568
private lazy var tableView: UITableView = UITableView(frame: .zero, style: viewProperties.tableViewStyle)
6669

6770
/// Pull To Refresh Support.
@@ -294,10 +297,6 @@ private extension PaginatedListSelectorViewController {
294297

295298
tableView.separatorStyle = viewProperties.separatorStyle
296299

297-
// Removes extra header spacing in ghost content view.
298-
tableView.estimatedSectionHeaderHeight = 0
299-
tableView.sectionHeaderHeight = 0
300-
301300
view.addSubview(tableView)
302301
tableView.translatesAutoresizingMaskIntoConstraints = false
303302
view.pinSubviewToAllEdges(tableView)
@@ -381,17 +380,15 @@ private extension PaginatedListSelectorViewController {
381380
/// Renders the Placeholder Orders: For safety reasons, we'll also halt ResultsController <> UITableView glue.
382381
///
383382
func displayPlaceholderProducts() {
384-
let options = GhostOptions(reuseIdentifier: Cell.reuseIdentifier, rowsPerSection: placeholderRowsPerSection)
385-
tableView.displayGhostContent(options: options,
386-
style: .wooDefaultGhostStyle)
383+
displayGhostContent()
387384

388385
resultsController.stopForwardingEvents()
389386
}
390387

391388
/// Removes the Placeholder Products (and restores the ResultsController <> UITableView link).
392389
///
393390
func removePlaceholderProducts() {
394-
tableView.removeGhostContent()
391+
removeGhostContent()
395392
resultsController.startForwardingEvents(to: tableView)
396393
tableView.reloadData()
397394
}

WooCommerce/Classes/ViewRelated/Orders/OrderListViewController.swift

Lines changed: 8 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ protocol OrderListViewControllerDelegate: AnyObject {
2727

2828
/// OrderListViewController: Displays the list of Orders associated to the active Store / Account.
2929
///
30-
final class OrderListViewController: UIViewController {
30+
final class OrderListViewController: UIViewController, GhostableViewController {
3131

3232
weak var delegate: OrderListViewControllerDelegate?
3333

@@ -51,9 +51,11 @@ final class OrderListViewController: UIViewController {
5151
return dataSource
5252
}()
5353

54-
/// Ghostable TableView.
55-
///
56-
private(set) var ghostableTableView = UITableView(frame: .zero, style: .grouped)
54+
lazy var ghostTableViewController = GhostTableViewController(options: GhostTableViewOptions(displaysSectionHeader: false,
55+
cellClass: OrderTableViewCell.self,
56+
estimatedRowHeight: Settings.estimatedRowHeight,
57+
tableViewStyle: .grouped,
58+
isScrollEnabled: false))
5759

5860
/// Pull To Refresh Support.
5961
///
@@ -152,7 +154,6 @@ final class OrderListViewController: UIViewController {
152154

153155
registerTableViewHeadersAndCells()
154156
configureTableView()
155-
configureGhostableTableView()
156157

157158
configureViewModel()
158159
configureSyncingCoordinator()
@@ -174,8 +175,6 @@ final class OrderListViewController: UIViewController {
174175
//
175176
// We can remove this once we've replaced XLPagerTabStrip.
176177
tableView.reloadData()
177-
178-
restartPlaceholderAnimation()
179178
}
180179

181180
override func viewDidLayoutSubviews() {
@@ -280,30 +279,10 @@ private extension OrderListViewController {
280279
view.pinSubviewToAllEdges(tableView)
281280
}
282281

283-
/// Setup: Ghostable TableView
284-
///
285-
func configureGhostableTableView() {
286-
view.addSubview(ghostableTableView)
287-
ghostableTableView.isHidden = true
288-
289-
ghostableTableView.translatesAutoresizingMaskIntoConstraints = false
290-
NSLayoutConstraint.activate([
291-
ghostableTableView.widthAnchor.constraint(equalTo: tableView.widthAnchor),
292-
ghostableTableView.heightAnchor.constraint(equalTo: tableView.heightAnchor),
293-
ghostableTableView.leadingAnchor.constraint(equalTo: tableView.leadingAnchor),
294-
ghostableTableView.topAnchor.constraint(equalTo: tableView.topAnchor)
295-
])
296-
297-
view.backgroundColor = .listBackground
298-
ghostableTableView.backgroundColor = .listBackground
299-
ghostableTableView.isScrollEnabled = false
300-
}
301-
302282
/// Registers all of the available table view cells and headers
303283
///
304284
func registerTableViewHeadersAndCells() {
305285
tableView.registerNib(for: OrderTableViewCell.self)
306-
ghostableTableView.registerNib(for: OrderTableViewCell.self)
307286

308287
let headerType = TwoColumnSectionHeaderView.self
309288
tableView.register(headerType.loadNib(), forHeaderFooterViewReuseIdentifier: headerType.reuseIdentifier)
@@ -452,33 +431,13 @@ private extension OrderListViewController {
452431
/// Renders the Placeholder Orders
453432
///
454433
func displayPlaceholderOrders() {
455-
let options = GhostOptions(displaysSectionHeader: false,
456-
reuseIdentifier: OrderTableViewCell.reuseIdentifier,
457-
rowsPerSection: Settings.placeholderRowsPerSection)
458-
459-
// If the ghostable table view gets stuck for any reason,
460-
// let's reset the state before using it again
461-
ghostableTableView.removeGhostContent()
462-
ghostableTableView.displayGhostContent(options: options,
463-
style: Constants.ghostStyle)
464-
ghostableTableView.startGhostAnimation()
465-
ghostableTableView.isHidden = false
434+
displayGhostContent()
466435
}
467436

468437
/// Removes the Placeholder Orders (and restores the ResultsController <> UITableView link).
469438
///
470439
func removePlaceholderOrders() {
471-
ghostableTableView.isHidden = true
472-
ghostableTableView.stopGhostAnimation()
473-
ghostableTableView.removeGhostContent()
474-
}
475-
476-
/// After returning to the screen, `restartGhostAnimation` is required to resume ghost animation.
477-
func restartPlaceholderAnimation() {
478-
guard ghostableTableView.isHidden == false else {
479-
return
480-
}
481-
ghostableTableView.restartGhostAnimation(style: Constants.ghostStyle)
440+
removeGhostContent()
482441
}
483442

484443
/// Shows the EmptyStateViewController
@@ -738,8 +697,4 @@ private extension OrderListViewController {
738697
case results
739698
case empty
740699
}
741-
742-
enum Constants {
743-
static let ghostStyle: GhostStyle = .wooDefaultGhostStyle
744-
}
745700
}

WooCommerce/Classes/ViewRelated/Products/Edit Product/Reviews/ProductReviewsDataSource.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ extension ProductReviewsDataSource: ReviewsInteractionDelegate {
172172
}
173173

174174

175-
private extension ProductReviewsDataSource {
175+
extension ProductReviewsDataSource {
176176
enum Settings {
177177
static let estimatedRowHeight = CGFloat(88)
178178
}

WooCommerce/Classes/ViewRelated/Products/Edit Product/Reviews/ProductReviewsViewController.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@ import UIKit
22
import Yosemite
33

44
/// The UI that shows the approved Reviews related to a specific product.
5-
final class ProductReviewsViewController: UIViewController {
5+
final class ProductReviewsViewController: UIViewController, GhostableViewController {
66

77
private let product: Product
88

99
private let viewModel: ProductReviewsViewModel
1010

11+
lazy var ghostTableViewController = GhostTableViewController(options: GhostTableViewOptions(cellClass: ProductReviewTableViewCell.self,
12+
estimatedRowHeight: ProductReviewsDataSource
13+
.Settings
14+
.estimatedRowHeight))
15+
1116
/// Pull To Refresh Support.
1217
///
1318
private lazy var refreshControl: UIRefreshControl = {
@@ -170,13 +175,15 @@ private extension ProductReviewsViewController {
170175
/// Renders Placeholder Reviews.
171176
///
172177
func displayPlaceholderReviews() {
173-
viewModel.displayPlaceholderReviews(tableView: tableView)
178+
displayGhostContent()
179+
viewModel.didDisplayPlaceholderReviews()
174180
}
175181

176182
/// Removes Placeholder Reviews.
177183
///
178184
func removePlaceholderReviews() {
179-
viewModel.removePlaceholderReviews(tableView: tableView)
185+
removeGhostContent()
186+
viewModel.didRemovePlaceholderReviews(tableView: tableView)
180187
}
181188

182189
/// Displays the EmptyStateViewController.

WooCommerce/Classes/ViewRelated/Products/Edit Product/Reviews/ProductReviewsViewModel.swift

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,13 @@ final class ProductReviewsViewModel {
2727
self.data = data
2828
}
2929

30-
func displayPlaceholderReviews(tableView: UITableView) {
31-
let options = GhostOptions(reuseIdentifier: ProductReviewTableViewCell.reuseIdentifier, rowsPerSection: Settings.placeholderRowsPerSection)
32-
tableView.displayGhostContent(options: options,
33-
style: .wooDefaultGhostStyle)
34-
30+
func didDisplayPlaceholderReviews() {
3531
data.stopForwardingEvents()
3632
}
3733

3834
/// Removes Placeholder Notes (and restores the ResultsController <> UITableView link).
3935
///
40-
func removePlaceholderReviews(tableView: UITableView) {
41-
tableView.removeGhostContent()
36+
func didRemovePlaceholderReviews(tableView: UITableView) {
4237
data.startForwardingEvents(to: tableView)
4338
}
4439

@@ -101,7 +96,6 @@ extension ProductReviewsViewModel {
10196

10297
private extension ProductReviewsViewModel {
10398
enum Settings {
104-
static let placeholderRowsPerSection = [3]
10599
static let firstPage = 1
106100
static let pageSize = 25
107101
}

WooCommerce/Classes/ViewRelated/ReusableViews/GhostTableViewController.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ struct GhostTableViewOptions {
1616
rowsPerSection: [Int] = [3],
1717
estimatedRowHeight: CGFloat = 44,
1818
tableViewStyle: UITableView.Style = .plain,
19-
backgroundColor: UIColor = .basicBackground,
20-
separatorStyle: UITableViewCell.SeparatorStyle = .none,
19+
backgroundColor: UIColor = .listBackground,
20+
separatorStyle: UITableViewCell.SeparatorStyle = .singleLine,
2121
isScrollEnabled: Bool = true) {
2222
// By just passing the cellClass in the initializer we enforce that the GhostOptions reuseIdentifier is always that of the cellClass
2323
ghostOptions = GhostOptions(displaysSectionHeader: displaysSectionHeader, reuseIdentifier: cellClass.reuseIdentifier, rowsPerSection: rowsPerSection)

0 commit comments

Comments
 (0)