// // SelectActivityVC.swift // QuickLocation // import UIKit import RxSwift import RxCocoa import Kingfisher final class SelectActivityCell: UITableViewCell { static let reuseId = "SelectActivityCell" private let iconView = UIImageView() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) iconView.contentMode = .scaleAspectFill iconView.layer.cornerRadius = 10 iconView.clipsToBounds = true contentView.addSubview(iconView) iconView.layoutChain.left(16).centerY().width(40).height(40) textLabel?.layoutChain.leftToRightOfView(iconView, offset: 12).centerY().right(16) selectionStyle = .default } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func configure(item: AppCatalogItem) { textLabel?.text = item.name textLabel?.font = .systemFont(ofSize: 16, weight: .medium) textLabel?.textColor = UIColor(hexStr: "#293445") AppCatalogStore.setIcon(for: iconView, item: item) } override func prepareForReuse() { super.prepareForReuse() iconView.kf.cancelDownloadTask() iconView.image = nil } } final class SelectActivityVC: BaseViewController { var onSelect: ((AppCatalogItem) -> Void)? private let searchField = UITextField() private let tableView = UITableView(frame: .zero, style: .plain) private let activityIndicator = UIActivityIndicatorView(style: .medium) private var items: [AppCatalogItem] = AppCatalogStore.sharedItems private var searchTask: Task? override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white title = "选取应用" navigationItem.leftBarButtonItem = UIBarButtonItem(title: "取消", style: .plain, target: self, action: #selector(cancel)) searchField.placeholder = "搜索应用" searchField.borderStyle = .roundedRect searchField.font = .systemFont(ofSize: 15) searchField.clearButtonMode = .whileEditing searchField.returnKeyType = .search searchField.addTarget(self, action: #selector(searchChanged), for: .editingChanged) view.addSubview(searchField) searchField.layoutChain.top(12).left(16).right(16).height(40) activityIndicator.hidesWhenStopped = true view.addSubview(activityIndicator) activityIndicator.layoutChain.centerX().topToBottomOfView(searchField, offset: 8) tableView.register(SelectActivityCell.self, forCellReuseIdentifier: SelectActivityCell.reuseId) tableView.dataSource = self tableView.delegate = self tableView.rowHeight = 56 tableView.keyboardDismissMode = .onDrag view.addSubview(tableView) tableView.layoutChain.topToBottomOfView(searchField, offset: 12).edgesHorzontal().bottom() } @objc private func cancel() { dismiss(animated: true) } @objc private func searchChanged() { let query = searchField.text ?? "" searchTask?.cancel() let trimmed = query.trimmingCharacters(in: .whitespacesAndNewlines) if trimmed.isEmpty { activityIndicator.stopAnimating() items = AppCatalogStore.sharedItems tableView.reloadData() return } let localHits = AppCatalogStore.search(query) items = localHits tableView.reloadData() activityIndicator.startAnimating() searchTask = Task { [weak self] in try? await Task.sleep(nanoseconds: 300_000_000) guard let self, !Task.isCancelled else { return } do { let remote = try await ITunesSearchService.search(term: trimmed) guard !Task.isCancelled else { return } await MainActor.run { self.activityIndicator.stopAnimating() self.items = ITunesSearchService.mergedResults(local: localHits, remote: remote) self.tableView.reloadData() } } catch { await MainActor.run { self.activityIndicator.stopAnimating() if self.items.isEmpty { self.items = localHits self.tableView.reloadData() } DLToast.show(text: "搜索失败,请检查网络") } } } } } extension SelectActivityVC: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { items.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: SelectActivityCell.reuseId, for: indexPath) as! SelectActivityCell cell.configure(item: items[indexPath.row]) return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let item = items[indexPath.row] onSelect?(item) dismiss(animated: true) } }