feat(timeline): TimelineRow + DateSection + grouping tests + Diary sheet

- TimelineRow: 时间线条目单行视图
- DateSection + TimelineGrouping: 今日/昨日/本周/更早分组
- DiaryQuickSheet: 文字日记快速记录入口
- TimelineGroupingTests: 分组逻辑烟测
- SymptomEndSheet / RootView: 配套微调
This commit is contained in:
link2026
2026-05-25 23:23:21 +08:00
parent b1b8d0a8c7
commit b63b26bce5
6 changed files with 337 additions and 14 deletions

View File

@@ -0,0 +1,83 @@
import Testing
import Foundation
@testable import
struct TimelineGroupingTests {
private let now: Date = {
var c = DateComponents()
c.year = 2026; c.month = 5; c.day = 25; c.hour = 12
return Calendar(identifier: .gregorian).date(from: c)!
}()
@Test func todaySection() {
#expect(TimelineGrouping.section(for: now, now: now) == .today)
}
@Test func yesterdaySection() {
let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: now)!
#expect(TimelineGrouping.section(for: yesterday, now: now) == .yesterday)
}
@Test func thisWeekSection() {
// 5/25 , ( 5/24 zh_CN ; 3 , within-week)
let cal = Calendar(identifier: .gregorian)
let twoDaysAgo = cal.date(byAdding: .day, value: -2, to: now)!
let section = TimelineGrouping.section(for: twoDaysAgo, now: now, calendar: cal)
// 2 .thisWeek .yesterday/.thisMonth .today
#expect(section != .today)
}
@Test func thisMonthSection() {
let earlierThisMonth = Calendar.current.date(byAdding: .day, value: -15, to: now)!
let section = TimelineGrouping.section(for: earlierThisMonth, now: now)
#expect(section == .thisMonth)
}
@Test func yearSection() {
var c = DateComponents()
c.year = 2024; c.month = 3; c.day = 1
let oldDate = Calendar(identifier: .gregorian).date(from: c)!
let section = TimelineGrouping.section(for: oldDate, now: now)
#expect(section == .year(2024))
}
@Test func sectionOrderingTodayFirst() {
let cal = Calendar(identifier: .gregorian)
let yesterday = cal.date(byAdding: .day, value: -1, to: now)!
let lastYear = cal.date(byAdding: .year, value: -1, to: now)!
let entries = [
mockEntry(id: "old", date: lastYear),
mockEntry(id: "yest", date: yesterday),
mockEntry(id: "today", date: now),
]
let grouped = TimelineGrouping.group(entries, now: now, calendar: cal)
let labels = grouped.map { $0.section.label }
#expect(labels.first == "今天")
#expect(labels.last?.contains("") == true)
}
@Test func formatDurationBoundaries() {
#expect(formatDuration(0) == "刚刚")
#expect(formatDuration(30) == "刚刚") // < 1 min
#expect(formatDuration(120) == "2 分钟") // 2 min
#expect(formatDuration(3600) == "1 小时") // 1h
#expect(formatDuration(3600 + 1800) == "1 小时 30 分")
#expect(formatDuration(86400) == "1 天")
#expect(formatDuration(86400 + 3600) == "1 天 1 小时")
}
private func mockEntry(id: String, date: Date) -> TimelineEntry {
TimelineEntry(
id: id,
kind: .diary,
date: date,
title: id,
subtitle: "test",
trailing: nil,
trailingIsAlert: false,
isOngoing: false
)
}
}