iOS/Sources/CarPlay/Templates/CarPlayPaginatedListTemplat...

133 lines
4.1 KiB
Swift

import CarPlay
import Foundation
import Shared
final class CarPlayPaginatedListTemplate {
enum PaginationStyle {
case inline
case navigation
}
enum GridPage {
case next
case previous
}
private var items: [CPListItem]
private var currentPage: Int
private let title: String
private let paginationStyle: PaginationStyle
private(set) var template: CPListTemplate
init(title: String, items: [CPListItem], paginationStyle: PaginationStyle = .navigation) {
self.title = title
self.items = items
self.paginationStyle = paginationStyle
self.currentPage = 0
self.template = CPListTemplate(title: title, sections: [])
}
func updateItems(items: [CPListItem]) {
DispatchQueue.main.async { [weak self] in
guard let self else { return }
self.items = items
updateTemplate()
}
}
func updateTemplate() {
let totalItems = items.count
var itemsPerPage = CPListTemplate.maximumItemCount
if paginationStyle == .inline, items.count > itemsPerPage {
itemsPerPage = CPListTemplate.maximumItemCount - 2
}
let startIndex = currentPage * itemsPerPage
let endIndex = min(startIndex + itemsPerPage, totalItems)
var pageItems = Array(items[startIndex ..< endIndex])
if paginationStyle == .inline {
if currentPage > 0 {
let previousItem = CPListItem(text: nil, detailText: nil)
previousItem.setImage(MaterialDesignIcons.arrowLeftIcon.carPlayIcon())
previousItem.handler = { [weak self] _, completion in
self?.changePage(to: .previous)
completion()
}
pageItems.insert(previousItem, at: 0)
}
if endIndex < totalItems {
let nextItem = CPListItem(text: nil, detailText: nil)
nextItem.setImage(MaterialDesignIcons.arrowRightIcon.carPlayIcon())
nextItem.handler = { [weak self] _, completion in
self?.changePage(to: .next)
completion()
}
pageItems.insert(nextItem, at: pageItems.endIndex)
}
} else {
template.trailingNavigationBarButtons = getPageButtons(
endIndex: endIndex,
currentPage: currentPage,
totalCount: totalItems
)
}
let section = CPListSection(items: pageItems)
template.updateSections([section])
}
private func getPageButtons(endIndex: Int, currentPage: Int, totalCount: Int) -> [CPBarButton] {
var barButtons: [CPBarButton] = []
guard let forwardImage = UIImage(systemName: "arrow.forward"),
let backwardImage = UIImage(systemName: "arrow.backward") else { return [] }
if endIndex < totalCount {
barButtons.append(CPBarButton(
image: forwardImage,
handler: { [weak self] _ in
self?.changePage(to: .next)
}
))
} else {
barButtons
.append(CPBarButton(
image: UIImage(size: forwardImage.size, color: UIColor.clear),
handler: nil
))
}
if currentPage > 0 {
barButtons.append(CPBarButton(
image: backwardImage,
handler: { [weak self] _ in
self?.changePage(to: .previous)
}
))
} else {
barButtons
.append(CPBarButton(
image: UIImage(size: backwardImage.size, color: UIColor.clear),
handler: nil
))
}
return barButtons
}
private func changePage(to: GridPage) {
var newCurrentPage = currentPage
switch to {
case .next:
newCurrentPage += 1
case .previous:
newCurrentPage -= 1
}
guard newCurrentPage >= 0 else { return }
currentPage = newCurrentPage
updateTemplate()
}
}