release(ios): 发布 0.2.1 并重构图标与界面细节
- 应用图标改用与 Web favicon 同源的扁平标记,金色 SIM 卡体加三格递增信号,29pt 下仍可读 - 标签统一为胶囊形状,提高深色主题下的描边权重,避免标签在暗色下消失 - 消息卡片与详情分区卡片收紧行距,单屏信息密度明显提升 - 详情头部指标精简为 4 行,数据模块改为单条读数 - 批量选择勾选框移出名称区域,工具栏控件统一为等高 34pt - 分组编辑器改为点选即生效,移除说明文字与常驻禁用按钮
This commit is contained in:
@@ -4,12 +4,18 @@ import XCTest
|
||||
|
||||
@MainActor
|
||||
final class FleetViewModelTests: XCTestCase {
|
||||
private func transientPreferences() -> UserDefaults {
|
||||
let suite = "FleetViewModelTests.\(UUID().uuidString)"
|
||||
return UserDefaults(suiteName: suite)!
|
||||
}
|
||||
|
||||
func testRefreshSortsByNameAndReportsStatus() async throws {
|
||||
let repository = MemoryInstanceRepository()
|
||||
let model = FleetViewModel(
|
||||
repository: repository,
|
||||
probe: ConnectionProbe(client: AlwaysOnlineClient()),
|
||||
credentials: NoopCredentialStore()
|
||||
credentials: NoopCredentialStore(),
|
||||
preferences: transientPreferences()
|
||||
)
|
||||
try await model.add(InstanceInput(
|
||||
name: "Zulu",
|
||||
@@ -36,7 +42,8 @@ final class FleetViewModelTests: XCTestCase {
|
||||
let model = FleetViewModel(
|
||||
repository: repository,
|
||||
probe: ConnectionProbe(client: AlwaysOnlineClient()),
|
||||
credentials: NoopCredentialStore()
|
||||
credentials: NoopCredentialStore(),
|
||||
preferences: transientPreferences()
|
||||
)
|
||||
try await model.add(InstanceInput(name: "Home", origin: URL(string: "http://192.168.1.70:3000")!, tags: ["home"]))
|
||||
try await model.add(InstanceInput(name: "Lab", origin: URL(string: "http://192.168.1.71:3000")!, tags: []))
|
||||
@@ -48,14 +55,80 @@ final class FleetViewModelTests: XCTestCase {
|
||||
XCTAssertEqual(model.groupedRows.flatMap(\.rows).map(\.instance.name), ["Home"])
|
||||
|
||||
model.searchText = ""
|
||||
model.groupMode = .tags
|
||||
XCTAssertEqual(model.groupedRows.map(\.title), ["home", "未打标签"])
|
||||
XCTAssertEqual(model.groupedRows.map(\.rows.count), [1, 1])
|
||||
model.clearTagFilters()
|
||||
model.toggleTagFilter("Home")
|
||||
XCTAssertEqual(model.allTags, ["home"])
|
||||
XCTAssertEqual(model.visibleRows.map(\.instance.name), ["Home"])
|
||||
XCTAssertEqual(model.countForTagFilter("home"), 1)
|
||||
model.clearTagFilters()
|
||||
|
||||
model.groupMode = .status
|
||||
XCTAssertEqual(model.groupedRows.map(\.title), ["在线"])
|
||||
}
|
||||
|
||||
func testTagFiltersCombineWithAndSemanticsAndPruneStaleSelections() async throws {
|
||||
let repository = MemoryInstanceRepository()
|
||||
let model = FleetViewModel(
|
||||
repository: repository,
|
||||
probe: ConnectionProbe(client: AlwaysOnlineClient()),
|
||||
credentials: NoopCredentialStore(),
|
||||
preferences: transientPreferences()
|
||||
)
|
||||
try await model.add(InstanceInput(
|
||||
name: "Both",
|
||||
origin: URL(string: "http://192.168.1.90:3000")!,
|
||||
tags: ["primary", "field"]
|
||||
))
|
||||
try await model.add(InstanceInput(
|
||||
name: "Single",
|
||||
origin: URL(string: "http://192.168.1.91:3000")!,
|
||||
tags: ["primary"]
|
||||
))
|
||||
await model.refresh()
|
||||
|
||||
model.toggleTagFilter("primary")
|
||||
XCTAssertEqual(model.visibleRows.map(\.instance.name), ["Both", "Single"])
|
||||
|
||||
model.toggleTagFilter("FIELD")
|
||||
XCTAssertEqual(model.visibleRows.map(\.instance.name), ["Both"])
|
||||
|
||||
model.toggleTagFilter("field")
|
||||
model.toggleTagFilter("primary")
|
||||
XCTAssertTrue(model.selectedTagFilters.isEmpty)
|
||||
|
||||
model.toggleTagFilter("vanished")
|
||||
XCTAssertTrue(model.isTagFilterActive("vanished"))
|
||||
await model.refresh()
|
||||
XCTAssertTrue(model.selectedTagFilters.isEmpty, "已不存在的标签筛选应当在刷新后自动清理")
|
||||
}
|
||||
|
||||
func testTagFilterSelectionSurvivesAcrossInstances() async throws {
|
||||
let suite = "FleetTagFilterTests.\(UUID().uuidString)"
|
||||
let repository = MemoryInstanceRepository()
|
||||
let first = FleetViewModel(
|
||||
repository: repository,
|
||||
probe: ConnectionProbe(client: AlwaysOnlineClient()),
|
||||
credentials: NoopCredentialStore(),
|
||||
preferences: UserDefaults(suiteName: suite)!
|
||||
)
|
||||
try await first.add(InstanceInput(
|
||||
name: "Relay",
|
||||
origin: URL(string: "http://192.168.1.92:3000")!,
|
||||
tags: ["relay"]
|
||||
))
|
||||
await first.refresh()
|
||||
first.toggleTagFilter("relay")
|
||||
|
||||
let second = FleetViewModel(
|
||||
repository: repository,
|
||||
probe: ConnectionProbe(client: AlwaysOnlineClient()),
|
||||
credentials: NoopCredentialStore(),
|
||||
preferences: UserDefaults(suiteName: suite)!
|
||||
)
|
||||
XCTAssertTrue(second.selectedTagFilters.contains("relay"))
|
||||
UserDefaults(suiteName: suite)?.removePersistentDomain(forName: suite)
|
||||
}
|
||||
|
||||
func testGroupModeKeepsUngroupedInstancesVisible() async throws {
|
||||
let repository = MemoryInstanceRepository()
|
||||
let model = FleetViewModel(
|
||||
|
||||
Reference in New Issue
Block a user