From e138941293ddf05fbefcd4a029aa8db992872ff1 Mon Sep 17 00:00:00 2001 From: Leandro Alonso Date: Wed, 12 Jan 2022 21:37:57 -0300 Subject: [PATCH 1/4] add: sync posts when showing the card for the first time --- .../Cards/Posts/PostsCardViewController.swift | 48 ++++++++++++++++++- .../Cards/Posts/PostsCardViewModel.swift | 42 ++++++++++++++-- 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewController.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewController.swift index 8976c13ec95e..ee301ec87d86 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewController.swift @@ -10,6 +10,7 @@ import UIKit private let postsTableView = IntrinsicTableView() private var viewModel: PostsCardViewModel! + private var ghostableTableView: UITableView? @objc init(blog: Blog) { self.blog = blog @@ -23,7 +24,7 @@ import UIKit override func viewDidLoad() { super.viewDidLoad() configureView() - viewModel = PostsCardViewModel(tableView: postsTableView, blog: blog) + viewModel = PostsCardViewModel(blog: blog, viewController: self, tableView: postsTableView) viewModel.viewDidLoad() } @@ -34,12 +35,57 @@ import UIKit } } +extension PostsCardViewController: PostsCardView { + func showLoading() { + configureGhostableTableView() + } + + func hideLoading() { + removeGhostableTableView() + } +} + private extension PostsCardViewController { func configureView() { + configureTableView() + } + + func configureTableView() { view.addSubview(postsTableView) postsTableView.translatesAutoresizingMaskIntoConstraints = false view.pinSubviewToAllEdges(postsTableView) let postCompactCellNib = PostCompactCell.defaultNib postsTableView.register(postCompactCellNib, forCellReuseIdentifier: PostCompactCell.defaultReuseID) } + + func configureGhostableTableView() { + let ghostableTableView = IntrinsicTableView() + + view.addSubview(ghostableTableView) + + ghostableTableView.translatesAutoresizingMaskIntoConstraints = false + view.pinSubviewToAllEdges(ghostableTableView) + + ghostableTableView.isScrollEnabled = false + + let postCompactCellNib = PostCompactCell.defaultNib + ghostableTableView.register(postCompactCellNib, forCellReuseIdentifier: PostCompactCell.defaultReuseID) + + let ghostOptions = GhostOptions(displaysSectionHeader: false, reuseIdentifier: PostCompactCell.defaultReuseID, rowsPerSection: [Constants.numberOfPosts]) + let style = GhostStyle(beatDuration: GhostStyle.Defaults.beatDuration, + beatStartColor: .placeholderElement, + beatEndColor: .placeholderElementFaded) + ghostableTableView.removeGhostContent() + ghostableTableView.displayGhostContent(options: ghostOptions, style: style) + + self.ghostableTableView = ghostableTableView + } + + func removeGhostableTableView() { + ghostableTableView?.removeFromSuperview() + } + + enum Constants { + static let numberOfPosts = 3 + } } diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift index 92d675bbcc02..f68f96d1e36f 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift @@ -2,6 +2,11 @@ import Foundation import CoreData import UIKit +protocol PostsCardView: AnyObject { + func showLoading() + func hideLoading() +} + /// Responsible for populating a table view with posts /// class PostsCardViewModel: NSObject { @@ -10,21 +15,26 @@ class PostsCardViewModel: NSObject { private let managedObjectContext: NSManagedObjectContext private let tableView: UITableView + + private let postService: PostService lazy var filterSettings: PostListFilterSettings = { PostListFilterSettings(blog: blog, postType: .post) }() private var fetchedResultsController: NSFetchedResultsController! + + private weak var viewController: PostsCardView? - init(tableView: UITableView, blog: Blog, managedObjectContext: NSManagedObjectContext = ContextManager.shared.mainContext) { + init(blog: Blog, viewController: PostsCardView, tableView: UITableView, managedObjectContext: NSManagedObjectContext = ContextManager.shared.mainContext) { self.blog = blog - self.managedObjectContext = managedObjectContext + self.viewController = viewController self.tableView = tableView + self.managedObjectContext = managedObjectContext + self.postService = PostService(managedObjectContext: managedObjectContext) super.init() } - /// Refresh the results and reload the data on the table view func refresh() { do { @@ -37,7 +47,9 @@ class PostsCardViewModel: NSObject { /// Set up the view model to be ready for use func viewDidLoad() { + viewController?.showLoading() createFetchedResultsController() + sync() } } @@ -82,9 +94,31 @@ private extension PostsCardViewModel { func sortDescriptorsForFetchRequest() -> [NSSortDescriptor] { return filterSettings.currentPostListFilter().sortDescriptors } + + func sync() { + let filter = filterSettings.currentPostListFilter() + let author = filterSettings.shouldShowOnlyMyPosts() ? blog.userID : nil + + let options = PostServiceSyncOptions() + options.statuses = filter.statuses.strings + options.authorID = author + options.number = Constants.numberOfPostsToSync + options.purgesLocalSync = true + + postService.syncPosts( + ofType: .post, + with: options, + for: blog, + success: { _ in + + }, failure: { (error: Error?) -> () in + + }) + } enum Constants { static let numberOfPosts = 3 + static let numberOfPostsToSync: NSNumber = 4 } } @@ -97,6 +131,8 @@ extension PostsCardViewModel: UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: PostCompactCell.defaultReuseID, for: indexPath) + + viewController?.hideLoading() configureCell(cell, at: indexPath) From 9b619a1f49befa4d7e89a549d02439cf25143237 Mon Sep 17 00:00:00 2001 From: Leandro Alonso Date: Wed, 12 Jan 2022 21:47:15 -0300 Subject: [PATCH 2/4] fix: trailing_whitespace --- .../Cards/Posts/PostsCardViewController.swift | 14 +++++++------- .../Cards/Posts/PostsCardViewModel.swift | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewController.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewController.swift index ee301ec87d86..d55214974571 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewController.swift @@ -39,7 +39,7 @@ extension PostsCardViewController: PostsCardView { func showLoading() { configureGhostableTableView() } - + func hideLoading() { removeGhostableTableView() } @@ -49,7 +49,7 @@ private extension PostsCardViewController { func configureView() { configureTableView() } - + func configureTableView() { view.addSubview(postsTableView) postsTableView.translatesAutoresizingMaskIntoConstraints = false @@ -57,10 +57,10 @@ private extension PostsCardViewController { let postCompactCellNib = PostCompactCell.defaultNib postsTableView.register(postCompactCellNib, forCellReuseIdentifier: PostCompactCell.defaultReuseID) } - + func configureGhostableTableView() { let ghostableTableView = IntrinsicTableView() - + view.addSubview(ghostableTableView) ghostableTableView.translatesAutoresizingMaskIntoConstraints = false @@ -77,14 +77,14 @@ private extension PostsCardViewController { beatEndColor: .placeholderElementFaded) ghostableTableView.removeGhostContent() ghostableTableView.displayGhostContent(options: ghostOptions, style: style) - + self.ghostableTableView = ghostableTableView } - + func removeGhostableTableView() { ghostableTableView?.removeFromSuperview() } - + enum Constants { static let numberOfPosts = 3 } diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift index f68f96d1e36f..2d32aa4c8d00 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift @@ -15,7 +15,7 @@ class PostsCardViewModel: NSObject { private let managedObjectContext: NSManagedObjectContext private let tableView: UITableView - + private let postService: PostService lazy var filterSettings: PostListFilterSettings = { @@ -23,7 +23,7 @@ class PostsCardViewModel: NSObject { }() private var fetchedResultsController: NSFetchedResultsController! - + private weak var viewController: PostsCardView? init(blog: Blog, viewController: PostsCardView, tableView: UITableView, managedObjectContext: NSManagedObjectContext = ContextManager.shared.mainContext) { @@ -94,7 +94,7 @@ private extension PostsCardViewModel { func sortDescriptorsForFetchRequest() -> [NSSortDescriptor] { return filterSettings.currentPostListFilter().sortDescriptors } - + func sync() { let filter = filterSettings.currentPostListFilter() let author = filterSettings.shouldShowOnlyMyPosts() ? blog.userID : nil @@ -131,7 +131,7 @@ extension PostsCardViewModel: UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: PostCompactCell.defaultReuseID, for: indexPath) - + viewController?.hideLoading() configureCell(cell, at: indexPath) From 369c2fc561603354e443cf58e852f6861b66f5b8 Mon Sep 17 00:00:00 2001 From: Leandro Alonso Date: Wed, 12 Jan 2022 21:53:26 -0300 Subject: [PATCH 3/4] refactor: remove the tableView from the viewModel constructor --- .../Cards/Posts/PostsCardViewController.swift | 14 +++++------ .../Cards/Posts/PostsCardViewModel.swift | 25 +++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewController.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewController.swift index d55214974571..73506c19aff8 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewController.swift @@ -7,7 +7,7 @@ import UIKit @objc class PostsCardViewController: UIViewController { var blog: Blog - private let postsTableView = IntrinsicTableView() + let tableView: UITableView = IntrinsicTableView() private var viewModel: PostsCardViewModel! private var ghostableTableView: UITableView? @@ -24,13 +24,13 @@ import UIKit override func viewDidLoad() { super.viewDidLoad() configureView() - viewModel = PostsCardViewModel(blog: blog, viewController: self, tableView: postsTableView) + viewModel = PostsCardViewModel(blog: blog, viewController: self) viewModel.viewDidLoad() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - postsTableView.dataSource = viewModel + tableView.dataSource = viewModel viewModel.refresh() } } @@ -51,11 +51,11 @@ private extension PostsCardViewController { } func configureTableView() { - view.addSubview(postsTableView) - postsTableView.translatesAutoresizingMaskIntoConstraints = false - view.pinSubviewToAllEdges(postsTableView) + view.addSubview(tableView) + tableView.translatesAutoresizingMaskIntoConstraints = false + view.pinSubviewToAllEdges(tableView) let postCompactCellNib = PostCompactCell.defaultNib - postsTableView.register(postCompactCellNib, forCellReuseIdentifier: PostCompactCell.defaultReuseID) + tableView.register(postCompactCellNib, forCellReuseIdentifier: PostCompactCell.defaultReuseID) } func configureGhostableTableView() { diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift index 2d32aa4c8d00..ca2ffa0a745c 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift @@ -3,6 +3,8 @@ import CoreData import UIKit protocol PostsCardView: AnyObject { + var tableView: UITableView { get } + func showLoading() func hideLoading() } @@ -14,8 +16,6 @@ class PostsCardViewModel: NSObject { private let managedObjectContext: NSManagedObjectContext - private let tableView: UITableView - private let postService: PostService lazy var filterSettings: PostListFilterSettings = { @@ -26,10 +26,9 @@ class PostsCardViewModel: NSObject { private weak var viewController: PostsCardView? - init(blog: Blog, viewController: PostsCardView, tableView: UITableView, managedObjectContext: NSManagedObjectContext = ContextManager.shared.mainContext) { + init(blog: Blog, viewController: PostsCardView, managedObjectContext: NSManagedObjectContext = ContextManager.shared.mainContext) { self.blog = blog self.viewController = viewController - self.tableView = tableView self.managedObjectContext = managedObjectContext self.postService = PostService(managedObjectContext: managedObjectContext) super.init() @@ -39,7 +38,7 @@ class PostsCardViewModel: NSObject { func refresh() { do { try fetchedResultsController.performFetch() - tableView.reloadData() + viewController?.tableView.reloadData() } catch { print("Fetch failed") } @@ -156,18 +155,18 @@ extension PostsCardViewModel: UITableViewDataSource { extension PostsCardViewModel: NSFetchedResultsControllerDelegate { func controllerWillChangeContent(_ controller: NSFetchedResultsController) { - tableView.beginUpdates() + viewController?.tableView.beginUpdates() } func controllerDidChangeContent(_ controller: NSFetchedResultsController) { - tableView.endUpdates() + viewController?.tableView.endUpdates() // When going to the post list all displayed posts there will be displayed // here too. This check ensures that we never display more than what // is specified on the `fetchLimit` property if fetchedResultsController.fetchRequest.fetchLimit > 0 && fetchedResultsController.fetchRequest.fetchLimit < fetchedResultsController.fetchedObjects?.count ?? 0 { try? fetchedResultsController.performFetch() - tableView.reloadData() + viewController?.tableView.reloadData() } } @@ -175,26 +174,26 @@ extension PostsCardViewModel: NSFetchedResultsControllerDelegate { switch type { case .insert: if let indexPath = newIndexPath { - tableView.insertRows(at: [indexPath], with: .fade) + viewController?.tableView.insertRows(at: [indexPath], with: .fade) } break case .delete: if let indexPath = indexPath { - tableView.deleteRows(at: [indexPath], with: .fade) + viewController?.tableView.deleteRows(at: [indexPath], with: .fade) } break case .update: - if let indexPath = indexPath, let cell = tableView.cellForRow(at: indexPath) { + if let indexPath = indexPath, let cell = viewController?.tableView.cellForRow(at: indexPath) { configureCell(cell, at: indexPath) } break case .move: if let indexPath = indexPath { - tableView.deleteRows(at: [indexPath], with: .fade) + viewController?.tableView.deleteRows(at: [indexPath], with: .fade) } if let newIndexPath = newIndexPath { - tableView.insertRows(at: [newIndexPath], with: .fade) + viewController?.tableView.insertRows(at: [newIndexPath], with: .fade) } break @unknown default: From 87fe089aff88f804ee5d728a8b69605ed68f477c Mon Sep 17 00:00:00 2001 From: Leandro Alonso Date: Wed, 12 Jan 2022 21:56:57 -0300 Subject: [PATCH 4/4] refactor: remove unnecessary properties --- .../Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift index ca2ffa0a745c..83d325f30d32 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/PostsCardViewModel.swift @@ -96,11 +96,9 @@ private extension PostsCardViewModel { func sync() { let filter = filterSettings.currentPostListFilter() - let author = filterSettings.shouldShowOnlyMyPosts() ? blog.userID : nil let options = PostServiceSyncOptions() options.statuses = filter.statuses.strings - options.authorID = author options.number = Constants.numberOfPostsToSync options.purgesLocalSync = true