jsdw_ios/QuickLocation/Component/PhotoPicker/PhotoPickerAlbumView.swift

113 lines
4.2 KiB
Swift

//
// PhotoPickerAlbumView.swift
// QuickLocation
//
import UIKit
import Photos
final class PhotoPickerAlbumView: UIView, UITableViewDataSource, UITableViewDelegate {
var onSelect: ((Int) -> Void)?
private var albums: [PhotoAlbum] = []
private var selectedIndex = 0
private var store: PhotoPickerStore?
private lazy var tableView: UITableView = {
let tv = UITableView(frame: .zero, style: .plain)
tv.backgroundColor = UIColor(hexStr: "#2C2C2E")
tv.separatorColor = UIColor.white.withAlphaComponent(0.12)
tv.separatorInset = UIEdgeInsets(top: 0, left: 76, bottom: 0, right: 0)
tv.rowHeight = 64
tv.dataSource = self
tv.delegate = self
tv.tableFooterView = UIView()
tv.register(PhotoPickerAlbumCell.self, forCellReuseIdentifier: "cell")
return tv
}()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor(hexStr: "#2C2C2E")
addSubview(tableView)
tableView.layoutChain.edges()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
func reload(albums: [PhotoAlbum], selectedIndex: Int) {
self.albums = albums
self.selectedIndex = selectedIndex
tableView.reloadData()
}
func bindStore(_ store: PhotoPickerStore) {
self.store = store
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
albums.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! PhotoPickerAlbumCell
let album = albums[indexPath.row]
cell.configure(album: album, selected: indexPath.row == selectedIndex, store: store)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedIndex = indexPath.row
tableView.reloadData()
onSelect?(indexPath.row)
}
}
private final class PhotoPickerAlbumCell: UITableViewCell {
private let coverView = UIImageView()
private let titleLab = UILabel()
private let tickView = UIImageView()
private var assetId = ""
private var requestId: PHImageRequestID = PHInvalidImageRequestID
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = UIColor(hexStr: "#2C2C2E")
selectionStyle = .none
coverView.contentMode = .scaleAspectFill
coverView.clipsToBounds = true
coverView.cornerRadius = 4
coverView.backgroundColor = UIColor.white.withAlphaComponent(0.08)
titleLab.font = .systemFont(ofSize: 16)
titleLab.textColor = .white
let config = UIImage.SymbolConfiguration(pointSize: 15, weight: .semibold)
tickView.image = UIImage(systemName: "checkmark", withConfiguration: config)
tickView.tintColor = UIColor(hexStr: "#007AFF")
tickView.contentMode = .scaleAspectFit
contentView.addSubview(coverView)
contentView.addSubview(titleLab)
contentView.addSubview(tickView)
coverView.layoutChain.left(16).centerY().width(48).height(48)
titleLab.layoutChain.leftToRightOfView(coverView, offset: 12).centerY().right(40)
tickView.layoutChain.right(16).centerY().width(18).height(18)
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
func configure(album: PhotoAlbum, selected: Bool, store: PhotoPickerStore?) {
titleLab.text = "\(album.title) (\(album.count))"
tickView.isHidden = !selected
coverView.image = nil
assetId = album.coverAsset?.localIdentifier ?? ""
guard let store, let asset = album.coverAsset else { return }
if requestId != PHInvalidImageRequestID {
store.cancelRequest(requestId)
}
requestId = store.requestThumbnail(for: asset, size: CGSize(width: 48, height: 48)) { [weak self] image in
guard let self, self.assetId == asset.localIdentifier else { return }
self.coverView.image = image
}
}
}