Add Lottie global loading overlay and fix stuck loading states.

Replace per-VC activity indicators with a ref-counted GlobalLoadingManager, and resolve duplicate show/hide calls on Profile, Statistics, and Home tabs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-06 17:43:13 +08:00
parent 3b17b7f7f0
commit 39186cfe25
14 changed files with 281 additions and 75 deletions

View File

@ -75,7 +75,7 @@ final class ProfileViewController: BaseViewController {
override func bindActions() {
viewModel.onStateChange = { [weak self] in
self?.applyViewModel()
Task { @MainActor in self?.applyViewModel() }
}
refreshControl.addTarget(self, action: #selector(refreshPulled), for: .valueChanged)
@ -103,7 +103,7 @@ final class ProfileViewController: BaseViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
Task { await reloadProfile(showLoading: false) }
Task { await reloadProfile(showGlobalLoading: true) }
}
private let headerContainer = UIView()
@ -228,12 +228,6 @@ final class ProfileViewController: BaseViewController {
value: viewModel.currentScenicName,
badge: .scenic
)
if viewModel.isLoading, !refreshControl.isRefreshing {
showLoading()
} else {
hideLoading()
}
}
private func configureWithdrawalRow() {
@ -286,13 +280,13 @@ final class ProfileViewController: BaseViewController {
@objc private func refreshPulled() {
Task {
await reloadProfile(showLoading: false)
await reloadProfile(showGlobalLoading: false)
refreshControl.endRefreshing()
}
}
@objc private func handleAccountDidSwitch() {
Task { await reloadProfile(showLoading: true) }
Task { await reloadProfile(showGlobalLoading: true) }
}
@objc private func nicknameChanged() {
@ -370,13 +364,19 @@ final class ProfileViewController: BaseViewController {
present(alert, animated: true)
}
private func reloadProfile(showLoading: Bool) async {
if showLoading { self.showLoading() }
private func reloadProfile(showGlobalLoading: Bool) async {
let shouldShowOverlay = showGlobalLoading && !refreshControl.isRefreshing
if shouldShowOverlay {
showLoading()
}
defer {
if showLoading { hideLoading() }
if shouldShowOverlay {
hideLoading()
}
}
do {
try await viewModel.reload(api: profileAPI)
applyViewModel()
} catch {
showToast(error.localizedDescription)
}