Advance UIKit rewrite with AMap integration and core UI modules.

Integrate高德 SDK with simulator-safe build flags, add map views for operating area and punch points, refactor main tabs and key feature screens to UIKit with Diffable lists, and document Swift concurrency defaults in AGENTS.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-26 15:16:12 +08:00
parent 9edf993432
commit d99a5b1bf8
124 changed files with 5195 additions and 1536 deletions

View File

@ -7,64 +7,81 @@ import SnapKit
import UIKit
import WebKit
// MARK: - Diffable
///
private enum SettingsRowID {
static let about = "settings:about"
static let version = "settings:version"
static let download = "settings:download"
static let userAgreement = "settings:userAgreement"
static let privacyPolicy = "settings:privacyPolicy"
}
///
private enum SettingsRowAction {
case agreement(AgreementPage)
case version
case download
}
///
final class SettingsViewController: UIViewController {
final class SettingsViewController: SimpleTableDiffableViewController {
private var copiedDownloadLink = false
private lazy var tableView: UITableView = {
let table = UITableView(frame: .zero, style: .insetGrouped)
table.dataSource = self
table.delegate = self
return table
}()
private let rows: [(title: String, action: SettingsRowAction)] = [
("关于我们", .agreement(.about)),
("系统版本", .version),
("App下载", .download),
("用户协议", .agreement(.userAgreement)),
("隐私政策", .agreement(.privacyPolicy))
private let rowActions: [String: SettingsRowAction] = [
SettingsRowID.about: .agreement(.about),
SettingsRowID.version: .version,
SettingsRowID.download: .download,
SettingsRowID.userAgreement: .agreement(.userAgreement),
SettingsRowID.privacyPolicy: .agreement(.privacyPolicy)
]
private enum SettingsRowAction {
case agreement(AgreementPage)
case version
case download
}
private let rowTitles: [String: String] = [
SettingsRowID.about: "关于我们",
SettingsRowID.version: "系统版本",
SettingsRowID.download: "App下载",
SettingsRowID.userAgreement: "用户协议",
SettingsRowID.privacyPolicy: "隐私政策"
]
/// UI
override func viewDidLoad() {
super.viewDidLoad()
title = "设置"
view.addSubview(tableView)
tableView.snp.makeConstraints { make in make.edges.equalToSuperview() }
}
private var downloadLink: String {
APIEnvironment.current.baseURL.appending(path: "/h5/app/download").absoluteString
/// Diffable snapshot
override func buildSnapshot() -> NSDiffableDataSourceSnapshot<SimpleTableSection, SimpleTableRow> {
var snapshot = NSDiffableDataSourceSnapshot<SimpleTableSection, SimpleTableRow>()
snapshot.appendSections([0])
snapshot.appendItems([
SettingsRowID.about,
SettingsRowID.version,
SettingsRowID.download,
SettingsRowID.userAgreement,
SettingsRowID.privacyPolicy
], toSection: 0)
return snapshot
}
private func copyDownloadLink() {
UIPasteboard.general.string = downloadLink
copiedDownloadLink = true
showToast("下载链接已复制")
tableView.reloadRows(at: [IndexPath(row: 2, section: 0)], with: .none)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [weak self] in
self?.copiedDownloadLink = false
self?.tableView.reloadRows(at: [IndexPath(row: 2, section: 0)], with: .none)
}
/// section
override func sectionFooter(for section: SimpleTableSection) -> String? {
"Copyright © 2025 All Rights Reserved\n苏ICP备2025157647号"
}
}
extension SettingsViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { rows.count }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
let row = rows[indexPath.row]
cell.textLabel?.text = row.title
/// Cell
override func configureCell(_ cell: UITableViewCell, row: SimpleTableRow, at indexPath: IndexPath) {
cell.textLabel?.text = rowTitles[row]
cell.textLabel?.textColor = UIColor(hex: 0x4B5563)
switch row.action {
cell.detailTextLabel?.text = nil
cell.detailTextLabel?.textColor = nil
cell.accessoryType = .none
cell.selectionStyle = .default
guard let action = rowActions[row] else { return }
switch action {
case .version:
cell.detailTextLabel?.text = SettingsDisplayPolicy.versionText()
cell.selectionStyle = .none
@ -74,12 +91,12 @@ extension SettingsViewController: UITableViewDataSource, UITableViewDelegate {
case .agreement:
cell.accessoryType = .disclosureIndicator
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
switch rows[indexPath.row].action {
///
override func didSelectRow(_ row: SimpleTableRow, at indexPath: IndexPath) {
guard let action = rowActions[row] else { return }
switch action {
case .agreement(let page):
HomeMenuRouting.pushProfile(.agreement(page), from: self)
case .download:
@ -89,8 +106,25 @@ extension SettingsViewController: UITableViewDataSource, UITableViewDelegate {
}
}
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
"Copyright © 2025 All Rights Reserved\n苏ICP备2025157647号"
private var downloadLink: String {
APIEnvironment.current.baseURL.appending(path: "/h5/app/download").absoluteString
}
///
private func copyDownloadLink() {
UIPasteboard.general.string = downloadLink
copiedDownloadLink = true
showToast("下载链接已复制")
var snapshot = tableDataSource.snapshot()
snapshot.reconfigureItems([SettingsRowID.download])
tableDataSource.apply(snapshot, animatingDifferences: false)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [weak self] in
guard let self else { return }
self.copiedDownloadLink = false
var snapshot = self.tableDataSource.snapshot()
snapshot.reconfigureItems([SettingsRowID.download])
self.tableDataSource.apply(snapshot, animatingDifferences: false)
}
}
}
@ -101,6 +135,7 @@ final class AgreementViewController: UIViewController {
private let webView = WKWebView(frame: .zero)
private let loadingIndicator = UIActivityIndicatorView(style: .large)
///
init(page: AgreementPage) {
self.page = page
super.init(nibName: nil, bundle: nil)
@ -109,6 +144,7 @@ final class AgreementViewController: UIViewController {
@available(*, unavailable)
required init?(coder: NSCoder) { fatalError() }
/// UI
override func viewDidLoad() {
super.viewDidLoad()
title = page.title
@ -124,10 +160,12 @@ final class AgreementViewController: UIViewController {
}
extension AgreementViewController: WKNavigationDelegate {
/// web
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
loadingIndicator.stopAnimating()
}
/// web
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
loadingIndicator.stopAnimating()
showToast(error.localizedDescription)