feat(mobile): UI-01 theme system, shared components and navigation

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-21 14:55:29 +08:00
parent 8f4ad11bd5
commit c94b9e5e58
27 changed files with 2067 additions and 555 deletions
+93 -99
View File
@@ -145,17 +145,14 @@ class FakeAdapter implements HttpClientAdapter {
Map<String, dynamic> loginOkBody({
String token = 'tok-new',
String expiresAt = '2026-09-20T12:00:00Z',
}) => <String, dynamic>{
'sessionToken': token,
'expiresAt': expiresAt,
};
}) => <String, dynamic>{'sessionToken': token, 'expiresAt': expiresAt};
/// 常用响应体:契约 Error 形状。
Map<String, dynamic> errorBody(String code) => <String, dynamic>{
'code': code,
'message': 'stub message',
'requestId': 'req-stub',
};
'code': code,
'message': 'stub message',
'requestId': 'req-stub',
};
// ── 相册域 fixtures(P3 计划 Task 4;形状对齐 openapi.yaml schemas)──
@@ -175,44 +172,45 @@ Map<String, dynamic> albumJson({
bool originalDownloadEnabled = false,
List<Map<String, dynamic>>? translations,
List<Map<String, dynamic>> categories = const <Map<String, dynamic>>[],
}) =>
<String, dynamic>{
'id': id,
'publicToken': publicToken,
'ownerId': ownerId,
'status': status,
'defaultLocale': defaultLocale,
'timezone': timezone,
'startAt': startAt,
'endAt': endAt,
'uploadEnabled': uploadEnabled,
'publicEnabled': publicEnabled,
'downloadEnabled': downloadEnabled,
'originalDownloadEnabled': originalDownloadEnabled,
'watermarkVersion': 0,
'translations': translations ??
<Map<String, dynamic>>[
<String, dynamic>{
'locale': 'zh-CN',
'title': '开幕晚宴',
'description': null,
'venue': '大宴会厅',
'address': null,
},
<String, dynamic>{
'locale': 'en',
'title': 'Opening Gala',
'description': null,
'venue': null,
'address': null,
},
],
'categories': categories,
'createdAt': '2026-09-01T00:00:00Z',
'updatedAt': '2026-09-01T00:00:00Z',
'statsSyncedAt': null,
'cover': null,
};
Map<String, dynamic>? cover,
}) => <String, dynamic>{
'id': id,
'publicToken': publicToken,
'ownerId': ownerId,
'status': status,
'defaultLocale': defaultLocale,
'timezone': timezone,
'startAt': startAt,
'endAt': endAt,
'uploadEnabled': uploadEnabled,
'publicEnabled': publicEnabled,
'downloadEnabled': downloadEnabled,
'originalDownloadEnabled': originalDownloadEnabled,
'watermarkVersion': 0,
'translations':
translations ??
<Map<String, dynamic>>[
<String, dynamic>{
'locale': 'zh-CN',
'title': '开幕晚宴',
'description': null,
'venue': '大宴会厅',
'address': null,
},
<String, dynamic>{
'locale': 'en',
'title': 'Opening Gala',
'description': null,
'venue': null,
'address': null,
},
],
'categories': categories,
'createdAt': '2026-09-01T00:00:00Z',
'updatedAt': '2026-09-01T00:00:00Z',
'statsSyncedAt': null,
'cover': cover,
};
/// 契约 `Category` 响应体。
Map<String, dynamic> categoryJson({
@@ -220,17 +218,17 @@ Map<String, dynamic> categoryJson({
String albumId = 'alb-1',
int sortOrder = 0,
List<Map<String, dynamic>>? translations,
}) =>
<String, dynamic>{
'id': id,
'albumId': albumId,
'sortOrder': sortOrder,
'translations': translations ??
<Map<String, dynamic>>[
<String, dynamic>{'locale': 'zh-CN', 'name': '仪式'},
<String, dynamic>{'locale': 'en', 'name': 'Ceremony'},
],
};
}) => <String, dynamic>{
'id': id,
'albumId': albumId,
'sortOrder': sortOrder,
'translations':
translations ??
<Map<String, dynamic>>[
<String, dynamic>{'locale': 'zh-CN', 'name': '仪式'},
<String, dynamic>{'locale': 'en', 'name': 'Ceremony'},
],
};
/// 契约 `Member` 响应体。
Map<String, dynamic> memberJson({
@@ -238,26 +236,24 @@ Map<String, dynamic> memberJson({
String account = 'staff02',
String displayName = 'Staff Two',
String role = 'collaborator',
}) =>
<String, dynamic>{
'userId': userId,
'account': account,
'displayName': displayName,
'role': role,
'status': 'active',
};
}) => <String, dynamic>{
'userId': userId,
'account': account,
'displayName': displayName,
'role': role,
'status': 'active',
};
/// 契约 `AdminUserLookupItem` 响应体。
Map<String, dynamic> lookupUserJson({
String id = 'u-9',
String account = 'staff09',
String displayName = 'Staff Nine',
}) =>
<String, dynamic>{
'id': id,
'account': account,
'displayName': displayName,
};
}) => <String, dynamic>{
'id': id,
'account': account,
'displayName': displayName,
};
/// 契约 `AdminPhoto` 响应体。
Map<String, dynamic> adminPhotoJson({
@@ -266,36 +262,34 @@ Map<String, dynamic> adminPhotoJson({
String visibility = 'published',
String processingState = 'ready',
int bytes = 123456,
}) =>
<String, dynamic>{
'photoId': photoId,
'albumId': albumId,
'categoryId': null,
'uploaderId': 'u-2',
'visibility': visibility,
'processingState': processingState,
'bytes': bytes,
'width': 4000,
'height': 3000,
'shotAt': null,
'uploadedAt': '2026-09-18T07:00:00Z',
'publishedAt': '2026-09-18T07:05:00Z',
'likeCount': 0,
'uploader': <String, dynamic>{
'userId': 'u-2',
'account': 'staff02',
'displayName': 'Staff Two',
},
'preview': null,
};
}) => <String, dynamic>{
'photoId': photoId,
'albumId': albumId,
'categoryId': null,
'uploaderId': 'u-2',
'visibility': visibility,
'processingState': processingState,
'bytes': bytes,
'width': 4000,
'height': 3000,
'shotAt': null,
'uploadedAt': '2026-09-18T07:00:00Z',
'publishedAt': '2026-09-18T07:05:00Z',
'likeCount': 0,
'uploader': <String, dynamic>{
'userId': 'u-2',
'account': 'staff02',
'displayName': 'Staff Two',
},
'preview': null,
};
/// 契约游标分页响应体(hasMore 与 nextCursor 成对)。
Map<String, dynamic> cursorPageBody(
List<Map<String, dynamic>> items, {
String? nextCursor,
}) =>
<String, dynamic>{
'items': items,
'nextCursor': nextCursor,
'hasMore': nextCursor != null,
};
}) => <String, dynamic>{
'items': items,
'nextCursor': nextCursor,
'hasMore': nextCursor != null,
};