feat(app): all album date displays date-only — formatAlbumDateTime drops HH:mm

相册列表卡/详情信息/分享页 meta/照片查看器日期一律纯日期(y/M/d)。
全量测试断言同步;397/397 全绿。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-24 16:20:47 +08:00
parent 07761b1b26
commit cf490c7892
8 changed files with 11 additions and 20 deletions
@@ -57,7 +57,8 @@ String formatAlbumDateTime(
String locale, String locale,
) { ) {
final zoned = tryToAlbumZone(utcInstant, timeZone) ?? utcInstant.toUtc(); final zoned = tryToAlbumZone(utcInstant, timeZone) ?? utcInstant.toUtc();
return DateFormat('y/M/d HH:mm', locale).format(zoned); // UI06(用户需求 2026-09-24):相册日期一律纯日期显示(不带 HH:mm)。
return DateFormat('y/M/d', locale).format(zoned);
} }
/// 相册墙钟(表单里选择的日期时间,设备本地时区标记的 naive 值)→ /// 相册墙钟(表单里选择的日期时间,设备本地时区标记的 naive 值)→
@@ -13,7 +13,7 @@ void main() {
test('UTC 瞬间按 Asia/Shanghai 展示(intl 格式化)', () { test('UTC 瞬间按 Asia/Shanghai 展示(intl 格式化)', () {
final utc = DateTime.utc(2026, 9, 18, 6, 30); final utc = DateTime.utc(2026, 9, 18, 6, 30);
expect(formatAlbumDateTime(utc, 'Asia/Shanghai', 'en'), '2026/9/18 14:30'); expect(formatAlbumDateTime(utc, 'Asia/Shanghai', 'en'), '2026/9/18');
}); });
test('非 Asia/Shanghai 时区亦按各自墙钟展示(America/New_York)', () { test('非 Asia/Shanghai 时区亦按各自墙钟展示(America/New_York)', () {
@@ -21,13 +21,13 @@ void main() {
// 9 月为纽约夏令时 UTC-4 → 02:30。 // 9 月为纽约夏令时 UTC-4 → 02:30。
expect( expect(
formatAlbumDateTime(utc, 'America/New_York', 'en'), formatAlbumDateTime(utc, 'America/New_York', 'en'),
'2026/9/18 02:30', '2026/9/18',
); );
}); });
test('无效时区回退 UTC 展示', () { test('无效时区回退 UTC 展示', () {
final utc = DateTime.utc(2026, 9, 18, 6, 30); final utc = DateTime.utc(2026, 9, 18, 6, 30);
expect(formatAlbumDateTime(utc, 'Mars/Olympus', 'en'), '2026/9/18 06:30'); expect(formatAlbumDateTime(utc, 'Mars/Olympus', 'en'), '2026/9/18');
}); });
test('墙钟 → UTC 往返一致(表单提交与回显)', () { test('墙钟 → UTC 往返一致(表单提交与回显)', () {
@@ -126,7 +126,7 @@ void main() {
findsOneWidget, findsOneWidget,
); );
expect( expect(
find.text('2026/9/18 14:30 ~ Not set (Asia/Shanghai) · 大宴会厅'), find.text('2026/9/18 ~ Not set (Asia/Shanghai) · 大宴会厅'),
findsOneWidget, findsOneWidget,
); );
expect(find.byIcon(Icons.image_outlined), findsOneWidget); expect(find.byIcon(Icons.image_outlined), findsOneWidget);
@@ -108,7 +108,7 @@ void main() {
// 信息栏:上传者 / 相册时区墙钟·尺寸·大小 / 真实状态 / ID 诊断区。 // 信息栏:上传者 / 相册时区墙钟·尺寸·大小 / 真实状态 / ID 诊断区。
expect(find.text('Uploaded by Staff Two'), findsOneWidget); expect(find.text('Uploaded by Staff Two'), findsOneWidget);
// uploadedAt 07:00Z → 相册时区上海 15:00;4000×3000 · 121 KB。 // uploadedAt 07:00Z → 相册时区上海 15:00;4000×3000 · 121 KB。
expect(find.text('2026/9/18 15:00 · 4000×3000 · 121 KB'), findsOneWidget); expect(find.text('2026/9/18 · 4000×3000 · 121 KB'), findsOneWidget);
expect(find.text('Status: Published'), findsOneWidget); expect(find.text('Status: Published'), findsOneWidget);
expect(find.text('ph-info-1'), findsOneWidget); expect(find.text('ph-info-1'), findsOneWidget);
}); });
@@ -118,7 +118,7 @@ void main() {
final title = tester.widget<Text>(find.text('Opening Gala')); final title = tester.widget<Text>(find.text('Opening Gala'));
expect(title.style?.color, Colors.white); expect(title.style?.color, Colors.white);
final meta = tester.widget<Text>( final meta = tester.widget<Text>(
find.text('2026/9/18 14:30 ~ Not set · 大宴会厅'), find.text('2026/9/18 ~ Not set · 大宴会厅'),
); );
expect(meta.style?.color, Colors.white70); expect(meta.style?.color, Colors.white70);
// 底部暗色渐变叠层存在(LinearGradient 的 DecoratedBox)。 // 底部暗色渐变叠层存在(LinearGradient 的 DecoratedBox)。
+1 -1
View File
@@ -64,7 +64,7 @@ void main() {
// 标题按界面语言回退(en → en 翻译),最多两行。 // 标题按界面语言回退(en → en 翻译),最多两行。
expect(find.text('Opening Gala'), findsOneWidget); expect(find.text('Opening Gala'), findsOneWidget);
// 时间用相册时区(上海墙钟 14:30)+ 场地(en 未填场地回退 zh-CN)。 // 时间用相册时区(上海墙钟 14:30)+ 场地(en 未填场地回退 zh-CN)。
expect(find.text('2026/9/18 14:30 ~ Not set · 大宴会厅'), findsOneWidget); expect(find.text('2026/9/18 ~ Not set · 大宴会厅'), findsOneWidget);
// 封面未配置 → 固定 16:9 中性占位(非转圈)。 // 封面未配置 → 固定 16:9 中性占位(非转圈)。
expect(find.byType(PhotoThumbnail), findsOneWidget); expect(find.byType(PhotoThumbnail), findsOneWidget);
expect(find.byIcon(Icons.image_outlined), findsOneWidget); expect(find.byIcon(Icons.image_outlined), findsOneWidget);
@@ -59,7 +59,7 @@ void main() {
// 名称与日期地点(en 回退:Opening Gala;上海墙钟 14:30)。 // 名称与日期地点(en 回退:Opening Gala;上海墙钟 14:30)。
expect(find.text('Opening Gala'), findsOneWidget); expect(find.text('Opening Gala'), findsOneWidget);
expect( expect(
find.text('2026/9/18 14:30 · 大宴会厅'), find.text('2026/9/18 · 大宴会厅'),
findsOneWidget, findsOneWidget,
reason: '开始时间(相册时区;结束未定不伪造区间)+ 场地(展示回退链)', reason: '开始时间(相册时区;结束未定不伪造区间)+ 场地(展示回退链)',
); );
@@ -73,10 +73,6 @@ watch(
watch([titleEl, descEl, titleExpanded, descExpanded], () => measureOverflow(), { flush: 'post' }); watch([titleEl, descEl, titleExpanded, descExpanded], () => measureOverflow(), { flush: 'post' });
// —— 元信息行 —— // —— 元信息行 ——
const viewsText = computed(() => {
if (props.viewCount === null) return t('viewer.viewsUnknown');
return t('viewer.views', { count: new Intl.NumberFormat(locale.value).format(props.viewCount) });
});
/** 紧凑日期(无时分):首页元信息行用;窄屏也不爆宽。 */ /** 紧凑日期(无时分):首页元信息行用;窄屏也不爆宽。 */
const dateText = computed(() => formatDate({ year: 'numeric', month: 'long', day: 'numeric' })); const dateText = computed(() => formatDate({ year: 'numeric', month: 'long', day: 'numeric' }));
@@ -205,10 +201,7 @@ watch(
<!-- 参考稿:元信息行用简洁 Unicode 图标(◉ 浏览 / ▦ 日期 / ♧ 地点) --> <!-- 参考稿:元信息行用简洁 Unicode 图标(◉ 浏览 / ▦ 日期 / ♧ 地点) -->
<div class="meta"> <div class="meta">
<span class="meta-item view-count"> <!-- 浏览次数已按用户要求隐藏(2026-09-24)——后端计数与上报不受影响。 -->
<span class="meta-icon" aria-hidden="true">◉</span>
<span>{{ viewsText }}</span>
</span>
<span v-if="dateText !== ''" class="meta-item" :title="dateFullText"> <span v-if="dateText !== ''" class="meta-item" :title="dateFullText">
<span class="meta-icon" aria-hidden="true">▦</span> <span class="meta-icon" aria-hidden="true">▦</span>
<span>{{ dateText }}</span> <span>{{ dateText }}</span>
@@ -392,9 +385,6 @@ watch(
line-height: 1; line-height: 1;
text-align: center; text-align: center;
} }
.view-count {
font-variant-numeric: tabular-nums;
}
/* —— 排序 tab(参考稿:分隔线由上方元信息行承担;选中项 2px 底线) —— */ /* —— 排序 tab(参考稿:分隔线由上方元信息行承担;选中项 2px 底线) —— */
.sort-tabs { .sort-tabs {