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

@ -26,6 +26,7 @@ final class LoginViewController: UIViewController {
private let privacyPolicyButton = UIButton(type: .system)
private let loginButton = UIButton(type: .system)
///
init(services: AppServices) {
self.services = services
super.init(nibName: nil, bundle: nil)
@ -36,6 +37,7 @@ final class LoginViewController: UIViewController {
fatalError("init(coder:) has not been implemented")
}
/// UI
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(hex: 0x0B1220)
@ -44,6 +46,7 @@ final class LoginViewController: UIViewController {
viewModel.applyPreferences(services.authSessionCoordinator.loginPreferences())
}
/// Views
private func configureViews() {
backgroundImageView.contentMode = .scaleAspectFill
backgroundImageView.clipsToBounds = true
@ -161,6 +164,7 @@ final class LoginViewController: UIViewController {
view.addGestureRecognizer(tap)
}
/// AgreementText
private func configureAgreementText() {
privacyLabel.numberOfLines = 0
privacyLabel.font = .systemFont(ofSize: AppMetrics.FontSize.subheadline)
@ -197,6 +201,7 @@ final class LoginViewController: UIViewController {
}
}
/// ViewModel
private func bindViewModel() {
viewModel.onChange = { [weak self] in
self?.renderViewModel()
@ -204,6 +209,7 @@ final class LoginViewController: UIViewController {
renderViewModel()
}
/// render
private func renderViewModel() {
if usernameField.textField.text != viewModel.username {
usernameField.textField.text = viewModel.username
@ -241,38 +247,46 @@ final class LoginViewController: UIViewController {
private weak var accountSelectionController: AccountSelectionViewController?
/// username
@objc private func usernameChanged() {
viewModel.username = usernameField.textField.text ?? ""
viewModel.normalizeUsernameCountryCodeIfNeeded()
services.toastCenter.dismiss()
}
/// password
@objc private func passwordChanged() {
viewModel.password = passwordField.textField.text ?? ""
services.toastCenter.dismiss()
}
/// togglePrivacy
@objc private func togglePrivacy() {
viewModel.privacyChecked.toggle()
}
/// openUserAgreement
@objc private func openUserAgreement() {
showToast("用户协议页面待接入")
}
/// openPrivacyPolicy
@objc private func openPrivacyPolicy() {
showToast("隐私政策页面待接入")
}
/// login
@objc private func loginTapped() {
view.endEditing(true)
performLogin()
}
/// dismiss
@objc private func dismissKeyboard() {
view.endEditing(true)
}
/// perform
private func performLogin() {
if let validationError = viewModel.validateForLogin() {
if validationError == .privacyUnchecked {
@ -307,6 +321,7 @@ final class LoginViewController: UIViewController {
}
}
/// AgreementSheet
private func presentAgreementSheet() {
let controller = LoginAgreementConsentViewController(
onOpenAgreement: { [weak self] title in
@ -324,6 +339,7 @@ final class LoginViewController: UIViewController {
present(controller, animated: true)
}
/// AccountSelection
private func presentAccountSelection(_ payload: AccountSelectionPayload) {
let controller = AccountSelectionViewController(
payload: payload,
@ -342,6 +358,7 @@ final class LoginViewController: UIViewController {
present(navigation, animated: true)
}
/// select
private func selectAccount(_ account: AccountSwitchAccount) {
Task {
do {
@ -359,6 +376,7 @@ final class LoginViewController: UIViewController {
}
}
/// complete
private func completeLogin(with response: V9AuthResponse) async {
do {
try await services.authSessionCoordinator.completeLogin(
@ -378,6 +396,7 @@ final class LoginViewController: UIViewController {
}
extension LoginViewController: UITextFieldDelegate {
/// textShouldReturn
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField === usernameField.textField {
passwordField.textField.becomeFirstResponder()
@ -396,6 +415,7 @@ private final class LoginInputField: UIView {
private let toggleButton = UIButton(type: .custom)
private var isSecure = false
///
init(iconName: String, placeholder: String, isSecure: Bool) {
self.isSecure = isSecure
super.init(frame: .zero)
@ -450,12 +470,14 @@ private final class LoginInputField: UIView {
nil
}
/// setSecureEntry
func setSecureEntry(_ secure: Bool) {
textField.isSecureTextEntry = secure
let imageName = secure ? "LoginPwdInvisible" : "LoginPwdVisible"
toggleButton.setImage(UIImage(named: imageName), for: .normal)
}
/// toggleVisibility
@objc private func toggleVisibility() {
onToggleVisibility?()
}
@ -467,6 +489,7 @@ private final class LoginAgreementConsentViewController: UIViewController {
private let onOpenAgreement: (String) -> Void
private let onAgreeAndContinue: () -> Void
///
init(onOpenAgreement: @escaping (String) -> Void, onAgreeAndContinue: @escaping () -> Void) {
self.onOpenAgreement = onOpenAgreement
self.onAgreeAndContinue = onAgreeAndContinue
@ -477,6 +500,7 @@ private final class LoginAgreementConsentViewController: UIViewController {
nil
}
/// UI
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
@ -524,6 +548,7 @@ private final class LoginAgreementConsentViewController: UIViewController {
}
}
/// continue
@objc private func continueTapped() {
dismiss(animated: true) { [onAgreeAndContinue] in
onAgreeAndContinue()