Skip to content

Commit 3844ff2

Browse files
committed
💄 UI: Add empty state view for app list
1 parent 12d528b commit 3844ff2

2 files changed

Lines changed: 109 additions & 8 deletions

File tree

Core/View/Apps/AppList.swift

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import SwiftUI
66
* 应用列表视图
77
*
88
* 显示和管理应用列表,支持根据显示类型过滤应用。
9-
* 当防火墙未运行或列表为空时显示引导视图。
9+
* 当防火墙未运行或需要升级时显示引导视图。
10+
* 当列表为空时显示优雅的空视图。
1011
*/
1112
struct AppList: View, SuperLog {
1213
/// UI状态提供者
@@ -51,23 +52,35 @@ struct AppList: View, SuperLog {
5152
/// 构建应用列表视图
5253
var body: some View {
5354
ZStack {
54-
ScrollView {
55-
VStack(spacing: 0) {
56-
ForEach(Array((filtedApps.isNotEmpty ? filtedApps : SmartApp.samples).enumerated()), id: \.element.id) { index, app in
57-
AppLine(app: app)
58-
if index < (allApps.isNotEmpty ? allApps : SmartApp.samples).count - 1 {
59-
Divider()
55+
if filtedApps.isEmpty && !shouldShowGuide {
56+
// 显示空视图:当列表为空且不需要显示引导视图时
57+
AppListEmptyView(displayType: ui.displayType)
58+
} else {
59+
ScrollView {
60+
VStack(spacing: 0) {
61+
ForEach(Array((filtedApps.isNotEmpty ? filtedApps : SmartApp.samples).enumerated()), id: \.element.id) { index, app in
62+
AppLine(app: app)
63+
if index < (allApps.isNotEmpty ? allApps : SmartApp.samples).count - 1 {
64+
Divider()
65+
}
6066
}
6167
}
6268
}
6369
}
6470

65-
if firewall.status.isNotRunning() || filtedApps.isEmpty || ui.shouldShowUpgradeGuide {
71+
if shouldShowGuide {
6672
GuideView()
6773
}
6874
}
6975
.onAppear(perform: handleOnAppear)
7076
}
77+
78+
/// 是否需要显示引导视图
79+
///
80+
/// 当防火墙未运行或需要升级时显示引导视图。
81+
private var shouldShowGuide: Bool {
82+
firewall.status.isNotRunning() || ui.shouldShowUpgradeGuide
83+
}
7184
}
7285

7386
// MARK: - Setter
@@ -149,6 +162,12 @@ extension AppList {
149162

150163
// MARK: - Preview
151164
#Preview("App") {
165+
ContentView()
166+
.inRootView()
167+
.frame(width: 600, height: 600)
168+
}
169+
170+
#Preview("AppList") {
152171
AppList()
153172
.inRootView()
154173
.frame(width: 600, height: 800)
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import SwiftUI
2+
import MagicCore
3+
4+
/**
5+
* 应用列表空视图
6+
*
7+
* 当应用列表为空时显示的空状态视图。
8+
* 根据显示类型(全部/允许/拒绝)显示相应的提示信息。
9+
*/
10+
struct AppListEmptyView: View {
11+
/// 显示类型
12+
let displayType: DisplayType
13+
14+
/// 构建空视图
15+
var body: some View {
16+
VStack(spacing: 16) {
17+
Image(systemName: "app.badge")
18+
.font(.system(size: 48))
19+
.foregroundColor(.secondary)
20+
21+
Text(title)
22+
.font(.headline)
23+
.foregroundColor(.primary)
24+
25+
if let description = description {
26+
Text(description)
27+
.font(.subheadline)
28+
.foregroundColor(.secondary)
29+
.multilineTextAlignment(.center)
30+
.padding(.horizontal, 40)
31+
}
32+
}
33+
.frame(maxWidth: .infinity, maxHeight: .infinity)
34+
}
35+
36+
/// 空状态标题
37+
private var title: String {
38+
switch displayType {
39+
case .All:
40+
return "暂无应用"
41+
case .Allowed:
42+
return "暂无网络活动"
43+
case .Rejected:
44+
return "暂无被拒绝的应用"
45+
}
46+
}
47+
48+
/// 空状态描述
49+
private var description: String? {
50+
switch displayType {
51+
case .All:
52+
return "当前没有应用产生网络活动"
53+
case .Allowed:
54+
return "当前没有网络活动"
55+
case .Rejected:
56+
return "当前没有拒绝访问网络的应用"
57+
}
58+
}
59+
}
60+
61+
// MARK: - Preview
62+
#Preview("App") {
63+
ContentView()
64+
.inRootView()
65+
.frame(width: 600, height: 600)
66+
}
67+
68+
#Preview("AppListEmptyView - All") {
69+
AppListEmptyView(displayType: .All)
70+
.frame(width: 600, height: 400)
71+
}
72+
73+
#Preview("AppListEmptyView - Allowed") {
74+
AppListEmptyView(displayType: .Allowed)
75+
.frame(width: 600, height: 400)
76+
}
77+
78+
#Preview("AppListEmptyView - Rejected") {
79+
AppListEmptyView(displayType: .Rejected)
80+
.frame(width: 600, height: 400)
81+
}
82+

0 commit comments

Comments
 (0)