Add Lottie-based global loading overlay across key flows.

Introduce GlobalLoadingCenter with reference counting, wire it through RootView and major auth/order/profile screens, and add the loading animation asset plus unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-23 11:25:56 +08:00
parent 1d1eb46ed8
commit 7fd964fe19
17 changed files with 514 additions and 139 deletions

View File

@ -14,6 +14,7 @@ struct PaymentCollectionView: View {
@Environment(AccountContext.self) private var accountContext
@Environment(PaymentAPI.self) private var paymentAPI
@Environment(ToastCenter.self) private var toastCenter
@Environment(\.globalLoading) private var globalLoading
@State private var viewModel = PaymentCollectionViewModel()
@State private var showingAmountSheet = false
@ -44,7 +45,9 @@ struct PaymentCollectionView: View {
}
}
.task(id: accountContext.currentScenic?.id) {
await viewModel.loadPayCode(api: paymentAPI, scenicId: accountContext.currentScenic?.id)
await globalLoading.withOptionalLoading(viewModel.qrImage == nil, message: "加载中...") {
await viewModel.loadPayCode(api: paymentAPI, scenicId: accountContext.currentScenic?.id)
}
}
.sheet(isPresented: $showingAmountSheet) {
amountSheet
@ -87,10 +90,7 @@ struct PaymentCollectionView: View {
///
private var qrCard: some View {
VStack(spacing: AppMetrics.Spacing.medium) {
if viewModel.isLoading {
ProgressView()
.frame(width: 220, height: 220)
} else if let image = viewModel.qrImage {
if let image = viewModel.qrImage {
Image(uiImage: image)
.interpolation(.none)
.resizable()
@ -129,7 +129,11 @@ struct PaymentCollectionView: View {
saveQRCode()
}
paymentActionButton(title: "刷新", icon: "arrow.clockwise") {
Task { await viewModel.loadPayCode(api: paymentAPI, scenicId: accountContext.currentScenic?.id) }
Task {
await globalLoading.withLoading(message: "刷新中...") {
await viewModel.loadPayCode(api: paymentAPI, scenicId: accountContext.currentScenic?.id)
}
}
}
}
}
@ -255,14 +259,11 @@ struct PaymentCollectionRecordView: View {
@Environment(AccountContext.self) private var accountContext
@Environment(PaymentAPI.self) private var paymentAPI
@Environment(ToastCenter.self) private var toastCenter
@Environment(\.globalLoading) private var globalLoading
@State private var viewModel = PaymentCollectionRecordViewModel()
var body: some View {
List {
if viewModel.isLoading {
ProgressView()
.frame(maxWidth: .infinity)
}
ForEach(viewModel.groups) { group in
Section {
ForEach(group.items) { item in
@ -299,7 +300,9 @@ struct PaymentCollectionRecordView: View {
await viewModel.load(api: paymentAPI, scenicId: accountContext.currentScenic?.id)
}
.task(id: accountContext.currentScenic?.id) {
await viewModel.load(api: paymentAPI, scenicId: accountContext.currentScenic?.id)
await globalLoading.withOptionalLoading(viewModel.groups.isEmpty, message: "加载中...") {
await viewModel.load(api: paymentAPI, scenicId: accountContext.currentScenic?.id)
}
}
.onChange(of: viewModel.errorMessage) { _, message in
if let message {