// // 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 } } }