feat(ios): unify list cards and loading states
This commit is contained in:
@@ -15,26 +15,18 @@ struct MessagesView: View {
|
||||
LazyVStack(spacing: 12) {
|
||||
filterBar
|
||||
if let errorMessage = model.errorMessage {
|
||||
AICard {
|
||||
Text(errorMessage)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(AITheme.warning)
|
||||
}
|
||||
AIStatusBanner(errorMessage, tint: AITheme.warning, systemImage: "exclamationmark.triangle")
|
||||
}
|
||||
if model.isLoading && model.filteredRows.isEmpty {
|
||||
AILoadingCard("正在同步消息")
|
||||
}
|
||||
if model.filteredRows.isEmpty && !model.isLoading {
|
||||
AICard {
|
||||
VStack(spacing: 10) {
|
||||
Image(systemName: "message")
|
||||
.font(.system(size: 28))
|
||||
.foregroundStyle(AITheme.muted)
|
||||
Text("暂无消息")
|
||||
.font(.headline)
|
||||
Text("刷新后从实例同步短信。")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(AITheme.muted)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, 18)
|
||||
AIEmptyState(
|
||||
systemImage: "message",
|
||||
title: "暂无消息",
|
||||
message: "刷新后从实例同步短信。"
|
||||
)
|
||||
}
|
||||
}
|
||||
ForEach(model.filteredRows) { message in
|
||||
@@ -45,15 +37,13 @@ struct MessagesView: View {
|
||||
}
|
||||
}
|
||||
.navigationTitle("消息中心")
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .primaryAction) {
|
||||
Button {
|
||||
model.showingSendForm = true
|
||||
} label: {
|
||||
Label("发送", systemImage: "paperplane")
|
||||
}
|
||||
.buttonStyle(AIButtonStyle(kind: .primary, size: .regular))
|
||||
.aiBottomActionBar {
|
||||
Button {
|
||||
model.showingSendForm = true
|
||||
} label: {
|
||||
Label("发送消息", systemImage: "paperplane")
|
||||
}
|
||||
.buttonStyle(AIButtonStyle(kind: .primary, size: .regular, fillsWidth: true))
|
||||
}
|
||||
.confirmationDialog(
|
||||
"删除这条消息?操作不可恢复。",
|
||||
@@ -97,6 +87,7 @@ struct MessagesView: View {
|
||||
}
|
||||
}
|
||||
.pickerStyle(.menu)
|
||||
.aiSelectSurface()
|
||||
|
||||
AISearchField("搜索号码或内容", text: $model.searchText)
|
||||
}
|
||||
@@ -115,15 +106,25 @@ struct MessagesView: View {
|
||||
Text(message.content)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(AITheme.ink)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
HStack {
|
||||
Text(message.instanceName)
|
||||
.font(.caption)
|
||||
.foregroundStyle(AITheme.muted)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.middle)
|
||||
.layoutPriority(1)
|
||||
Spacer()
|
||||
Button("删除") {
|
||||
pendingDeleteMessage = message
|
||||
}
|
||||
.buttonStyle(AIButtonStyle(kind: .danger, size: .compact))
|
||||
.buttonStyle(
|
||||
AIButtonStyle(
|
||||
kind: .danger,
|
||||
size: .compact,
|
||||
fixedWidth: AITheme.listActionButtonWidth
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,18 +27,27 @@ struct SendMessageFormView: View {
|
||||
VStack(spacing: 12) {
|
||||
AICard {
|
||||
VStack(alignment: .leading, spacing: 14) {
|
||||
Picker("实例", selection: Binding(
|
||||
get: { model.selectedInstanceID ?? model.instances.first?.id },
|
||||
set: { model.selectedInstanceID = $0 }
|
||||
)) {
|
||||
ForEach(model.instances) { instance in
|
||||
Text(instance.name).tag(Optional(instance.id))
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text("实例")
|
||||
.font(.subheadline.weight(.semibold))
|
||||
.foregroundStyle(AITheme.ink)
|
||||
Picker("实例", selection: Binding(
|
||||
get: { model.selectedInstanceID ?? model.instances.first?.id },
|
||||
set: { model.selectedInstanceID = $0 }
|
||||
)) {
|
||||
ForEach(model.instances) { instance in
|
||||
Text(instance.name).tag(Optional(instance.id))
|
||||
}
|
||||
}
|
||||
.pickerStyle(.menu)
|
||||
.aiSelectSurface()
|
||||
}
|
||||
.pickerStyle(.menu)
|
||||
|
||||
TextField("收件号码", text: $phoneNumber)
|
||||
.textFieldStyle(AIFieldStyle())
|
||||
#if os(iOS)
|
||||
.keyboardType(.phonePad)
|
||||
#endif
|
||||
|
||||
TextField("消息内容", text: $content, axis: .vertical)
|
||||
.textFieldStyle(.plain)
|
||||
@@ -54,24 +63,26 @@ struct SendMessageFormView: View {
|
||||
}
|
||||
}
|
||||
if let validationMessage {
|
||||
Text(validationMessage)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(AITheme.danger)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
AIStatusBanner(validationMessage, tint: AITheme.danger, systemImage: "exclamationmark.triangle")
|
||||
}
|
||||
}
|
||||
.padding(16)
|
||||
}
|
||||
}
|
||||
.navigationTitle("发送消息")
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
.aiBottomActionBar {
|
||||
HStack(spacing: 10) {
|
||||
Button("取消") { dismiss() }
|
||||
.buttonStyle(AIButtonStyle(kind: .secondary, size: .regular))
|
||||
}
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
.buttonStyle(
|
||||
AIButtonStyle(
|
||||
kind: .secondary,
|
||||
size: .regular,
|
||||
fixedWidth: AITheme.footerSecondaryButtonWidth
|
||||
)
|
||||
)
|
||||
|
||||
Button("发送") { send() }
|
||||
.buttonStyle(AIButtonStyle(kind: .primary, size: .regular))
|
||||
.buttonStyle(AIButtonStyle(kind: .primary, size: .regular, fillsWidth: true))
|
||||
.disabled(!canSend)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user