added paging
Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
427e862b6b
commit
7e0c2fd310
@ -31,6 +31,9 @@ class EmployeesViewController: UIViewController {
|
|||||||
/// Will show specific state of the viewModel
|
/// Will show specific state of the viewModel
|
||||||
private var footerView: TableFooterView?
|
private var footerView: TableFooterView?
|
||||||
|
|
||||||
|
// Prevents multiple calls during rapid scrolling
|
||||||
|
private var isFetchingNextPage: Bool = false
|
||||||
|
|
||||||
// MARK: - Public Methods
|
// MARK: - Public Methods
|
||||||
|
|
||||||
public override func viewDidLoad() {
|
public override func viewDidLoad() {
|
||||||
@ -49,6 +52,7 @@ class EmployeesViewController: UIViewController {
|
|||||||
// Configure TableView
|
// Configure TableView
|
||||||
tableView.register(EmployeeTableViewCell.self, forCellReuseIdentifier: EmployeeTableViewCell.identifier)
|
tableView.register(EmployeeTableViewCell.self, forCellReuseIdentifier: EmployeeTableViewCell.identifier)
|
||||||
tableView.dataSource = self
|
tableView.dataSource = self
|
||||||
|
tableView.delegate = self
|
||||||
view.addSubview(tableView)
|
view.addSubview(tableView)
|
||||||
tableView.frame = view.bounds
|
tableView.frame = view.bounds
|
||||||
|
|
||||||
@ -98,26 +102,55 @@ class EmployeesViewController: UIViewController {
|
|||||||
|
|
||||||
/// Show state in specific use-cases for the EmployeesViewModel
|
/// Show state in specific use-cases for the EmployeesViewModel
|
||||||
private func updateFooter() {
|
private func updateFooter() {
|
||||||
var message: String? {
|
var footerMessage: String?
|
||||||
guard !viewModel.isLoading else { return nil }
|
|
||||||
return viewModel.errorMessage ?? (viewModel.employees.isEmpty ? "No employees found, please try to refresh." : nil)
|
// Check for error messages or empty state first
|
||||||
|
if let message = viewModel.errorMessage ?? (viewModel.employees.isEmpty && !viewModel.isLoading ? "No employees found, please try to refresh." : nil) {
|
||||||
|
footerMessage = message
|
||||||
|
|
||||||
|
}
|
||||||
|
// Show loading footer if there are more pages to load
|
||||||
|
else if (viewModel.isLoading || isFetchingNextPage) && viewModel.hasMorePages {
|
||||||
|
footerMessage = "Loading more employees..."
|
||||||
}
|
}
|
||||||
|
|
||||||
if let message, !viewModel.isLoading {
|
if let footerMessage {
|
||||||
// Lazy initialize footerView if needed
|
// Lazy initialize footerView if needed
|
||||||
if footerView == nil {
|
if footerView == nil {
|
||||||
footerView = TableFooterView(message: message)
|
footerView = TableFooterView(message: footerMessage)
|
||||||
} else { // Update the message
|
} else {
|
||||||
footerView?.update(message: message)
|
footerView?.update(message: footerMessage)
|
||||||
}
|
}
|
||||||
footerView?.frame = CGRect(x: 0, y: 0, width: tableView.frame.width, height: 150)
|
footerView?.frame = CGRect(x: 0, y: 0, width: tableView.frame.width, height: 150)
|
||||||
tableView.tableFooterView = footerView
|
tableView.tableFooterView = footerView
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
tableView.tableFooterView = nil
|
tableView.tableFooterView = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - UITableViewDelegate
|
||||||
|
extension EmployeesViewController: UITableViewDelegate {
|
||||||
|
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||||
|
let offsetY = scrollView.contentOffset.y
|
||||||
|
let contentHeight = scrollView.contentSize.height
|
||||||
|
let scrollViewHeight = scrollView.frame.size.height
|
||||||
|
|
||||||
|
if offsetY > contentHeight - scrollViewHeight - 100 && !isFetchingNextPage {
|
||||||
|
isFetchingNextPage = true
|
||||||
|
updateFooter()
|
||||||
|
viewModel.loadNextPage()
|
||||||
|
|
||||||
|
// Reset the flag after a short delay to allow new fetches
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
||||||
|
self?.isFetchingNextPage = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Mark: - Objective-C Methods
|
// Mark: - Objective-C Methods
|
||||||
extension EmployeesViewController {
|
extension EmployeesViewController {
|
||||||
|
|
||||||
|
|||||||
@ -16,36 +16,57 @@ public class EmployeesViewModel: ObservableObject {
|
|||||||
@Published public private(set) var employees: [Employee] = []
|
@Published public private(set) var employees: [Employee] = []
|
||||||
@Published public private(set) var errorMessage: String? = nil
|
@Published public private(set) var errorMessage: String? = nil
|
||||||
@Published public private(set) var isLoading: Bool = false
|
@Published public private(set) var isLoading: Bool = false
|
||||||
|
@Published public private(set) var hasMorePages: Bool = true
|
||||||
|
|
||||||
|
private var currentPage = 1
|
||||||
|
private let perPage = 10
|
||||||
|
private var totalEmployees = 0
|
||||||
|
|
||||||
public init() {}
|
public init() {}
|
||||||
|
|
||||||
public func fetchEmployees() {
|
/// Fetch employees for the given page
|
||||||
// resetting values out the values before fetching new data
|
public func fetchEmployees(page: Int = 1) {
|
||||||
errorMessage = nil
|
// Prevent duplicate calls
|
||||||
|
guard !isLoading else { return }
|
||||||
isLoading = true
|
isLoading = true
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
do {
|
do {
|
||||||
// Fetch employees using the async method
|
// Fetch employees using the paginated API
|
||||||
let wrapper = try await EmployeeService.shared.getEmployees(serviceMode)
|
let wrapper = try await MockEmployeeService.shared.getEmployees(.empty ,page: page, perPage: perPage)
|
||||||
|
|
||||||
// Update published properties
|
// Update published properties
|
||||||
employees = wrapper.employees
|
if page == 1 {
|
||||||
|
employees = wrapper.employees // Replace list for the first page
|
||||||
|
} else {
|
||||||
|
employees.append(contentsOf: wrapper.employees) // Append for subsequent pages
|
||||||
|
}
|
||||||
|
|
||||||
|
totalEmployees = wrapper.total
|
||||||
|
currentPage = page
|
||||||
|
hasMorePages = employees.count < totalEmployees
|
||||||
isLoading = false
|
isLoading = false
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
// Handle errors
|
// Handle errors
|
||||||
employees = []
|
|
||||||
isLoading = false
|
isLoading = false
|
||||||
errorMessage = "An unexpected error occurred, please try to refresh"
|
errorMessage = "An unexpected error occurred, please try to refresh."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load the next page of employees
|
||||||
|
public func loadNextPage() {
|
||||||
|
guard hasMorePages else { return }
|
||||||
|
fetchEmployees(page: currentPage + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change the service mode (e.g., production, malformed, empty)
|
||||||
public func changeMode(to mode: EmployeeServiceMode) {
|
public func changeMode(to mode: EmployeeServiceMode) {
|
||||||
serviceMode = mode
|
serviceMode = mode
|
||||||
fetchEmployees()
|
currentPage = 1
|
||||||
|
employees = []
|
||||||
|
hasMorePages = true
|
||||||
|
fetchEmployees(page: 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user