Commit 89cbb8990f45433ef052c2efe6f86399064b6b52

Authored by 权海
1 parent d1a92435

feat(ui):watch_theme 国际化

Showing 25 changed files with 997 additions and 160 deletions
@@ -12,6 +12,7 @@ import 'package:get/get.dart'; @@ -12,6 +12,7 @@ import 'package:get/get.dart';
12 import 'package:image_cropper/image_cropper.dart'; 12 import 'package:image_cropper/image_cropper.dart';
13 import 'package:image_picker/image_picker.dart'; 13 import 'package:image_picker/image_picker.dart';
14 import 'package:path_provider/path_provider.dart'; 14 import 'package:path_provider/path_provider.dart';
  15 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
15 16
16 import '../models/watch_theme_models.dart'; 17 import '../models/watch_theme_models.dart';
17 import '../widgets/watch_theme_dialogs.dart'; 18 import '../widgets/watch_theme_dialogs.dart';
@@ -26,7 +27,7 @@ class CreateWatchThemeController extends GetxController { @@ -26,7 +27,7 @@ class CreateWatchThemeController extends GetxController {
26 27
27 final customThemeName = ''.obs; 28 final customThemeName = ''.obs;
28 final agreedToSubmission = true.obs; 29 final agreedToSubmission = true.obs;
29 - final customStatusNames = ['状态优秀', '状态正常', '注意压力', '压力过载'].obs; 30 + late final RxList<String> customStatusNames;
30 final customImagePaths = RxList<String?>.filled(4, null); 31 final customImagePaths = RxList<String?>.filled(4, null);
31 final isRemovingBackground = RxList<bool>.filled(4, false); 32 final isRemovingBackground = RxList<bool>.filled(4, false);
32 final isSaving = false.obs; 33 final isSaving = false.obs;
@@ -38,6 +39,12 @@ class CreateWatchThemeController extends GetxController { @@ -38,6 +39,12 @@ class CreateWatchThemeController extends GetxController {
38 @override 39 @override
39 void onInit() { 40 void onInit() {
40 super.onInit(); 41 super.onInit();
  42 + customStatusNames = [
  43 + l10n.watchThemeExcellent,
  44 + l10n.watchThemeNormal,
  45 + l10n.watchThemeSlightStressful,
  46 + l10n.watchThemeStressful,
  47 + ].obs;
41 themeNameController = TextEditingController(); 48 themeNameController = TextEditingController();
42 themeNameController.addListener(() { 49 themeNameController.addListener(() {
43 customThemeName.value = themeNameController.text.trim(); 50 customThemeName.value = themeNameController.text.trim();
@@ -78,11 +85,11 @@ class CreateWatchThemeController extends GetxController { @@ -78,11 +85,11 @@ class CreateWatchThemeController extends GetxController {
78 compressQuality: 100, 85 compressQuality: 100,
79 uiSettings: [ 86 uiSettings: [
80 AndroidUiSettings( 87 AndroidUiSettings(
81 - toolbarTitle: '裁剪表盘图片', 88 + toolbarTitle: l10n.watchThemeCropImage,
82 lockAspectRatio: true, 89 lockAspectRatio: true,
83 ), 90 ),
84 IOSUiSettings( 91 IOSUiSettings(
85 - title: '裁剪表盘图片', 92 + title: l10n.watchThemeCropImage,
86 aspectRatioLockEnabled: true, 93 aspectRatioLockEnabled: true,
87 resetAspectRatioEnabled: false, 94 resetAspectRatioEnabled: false,
88 ), 95 ),
@@ -102,7 +109,7 @@ class CreateWatchThemeController extends GetxController { @@ -102,7 +109,7 @@ class CreateWatchThemeController extends GetxController {
102 // 此处不等待结果,让裁切图先显示;处理完成后再原位替换。 109 // 此处不等待结果,让裁切图先显示;处理完成后再原位替换。
103 unawaited(_removeBackgroundAndReplace(index, savedPath, taskVersion)); 110 unawaited(_removeBackgroundAndReplace(index, savedPath, taskVersion));
104 } catch (_) { 111 } catch (_) {
105 - AppToast.show('图片处理失败,请重试'); 112 + AppToast.show(l10n.watchThemeImageProcessFailed);
106 } 113 }
107 } 114 }
108 115
@@ -209,11 +216,11 @@ class CreateWatchThemeController extends GetxController { @@ -209,11 +216,11 @@ class CreateWatchThemeController extends GetxController {
209 return; 216 return;
210 } 217 }
211 final abandon = await Get.dialog<bool>( 218 final abandon = await Get.dialog<bool>(
212 - const WatchThemeConfirmDialog(  
213 - title: '放弃编辑',  
214 - message: '关闭此页面后,已编辑的内容不会保留,是否放弃编辑?',  
215 - primaryText: '放弃编辑',  
216 - secondaryText: '继续编辑', 219 + WatchThemeConfirmDialog(
  220 + title: l10n.watchThemeAbandonEdit,
  221 + message: l10n.watchThemeAbandonMessage,
  222 + primaryText: l10n.watchThemeAbandonEdit,
  223 + secondaryText: l10n.watchThemeContinueEditing,
217 ), 224 ),
218 barrierDismissible: true, 225 barrierDismissible: true,
219 ); 226 );
@@ -241,7 +248,7 @@ class CreateWatchThemeController extends GetxController { @@ -241,7 +248,7 @@ class CreateWatchThemeController extends GetxController {
241 HResourceType.image, 248 HResourceType.image,
242 ); 249 );
243 if (imageUrl == null || imageUrl.isEmpty) { 250 if (imageUrl == null || imageUrl.isEmpty) {
244 - AppToast.show('图片上传失败,请重试'); 251 + AppToast.show(l10n.watchThemeImageUploadFailed);
245 return; 252 return;
246 } 253 }
247 uploadedImageUrls.add(imageUrl); 254 uploadedImageUrls.add(imageUrl);
@@ -275,7 +282,7 @@ class CreateWatchThemeController extends GetxController { @@ -275,7 +282,7 @@ class CreateWatchThemeController extends GetxController {
275 ); 282 );
276 return; 283 return;
277 } catch (_) { 284 } catch (_) {
278 - AppToast.show('创建表盘失败,请重试'); 285 + AppToast.show(l10n.watchThemeCreateFailed);
279 } finally { 286 } finally {
280 isSaving.value = false; 287 isSaving.value = false;
281 } 288 }
@@ -10,6 +10,7 @@ import 'package:doublefeel_flutter/pigeon/platform_api.g.dart'; @@ -10,6 +10,7 @@ import 'package:doublefeel_flutter/pigeon/platform_api.g.dart';
10 import 'package:doublefeel_flutter/pigeon/wear_engine_api.g.dart'; 10 import 'package:doublefeel_flutter/pigeon/wear_engine_api.g.dart';
11 import 'package:flutter/material.dart'; 11 import 'package:flutter/material.dart';
12 import 'package:get/get.dart'; 12 import 'package:get/get.dart';
  13 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
13 14
14 import '../../friends/models/friend_health_data.dart'; 15 import '../../friends/models/friend_health_data.dart';
15 import '../../friends/views/select_friend_view.dart'; 16 import '../../friends/views/select_friend_view.dart';
@@ -95,11 +96,11 @@ class CustomWatchThemePreviewController extends GetxController { @@ -95,11 +96,11 @@ class CustomWatchThemePreviewController extends GetxController {
95 96
96 Future<void> confirmDeleteCustomTheme() async { 97 Future<void> confirmDeleteCustomTheme() async {
97 final shouldDelete = await Get.dialog<bool>( 98 final shouldDelete = await Get.dialog<bool>(
98 - const WatchThemeConfirmDialog(  
99 - title: '删除主题',  
100 - message: '主题删除后无法恢复,确认删除该主题吗?',  
101 - primaryText: '删除',  
102 - secondaryText: '取消', 99 + WatchThemeConfirmDialog(
  100 + title: l10n.watchThemeDeleteTheme,
  101 + message: l10n.watchThemeDeleteMessage,
  102 + primaryText: l10n.watchThemeDelete,
  103 + secondaryText: l10n.watchThemeCancel,
103 ), 104 ),
104 barrierDismissible: true, 105 barrierDismissible: true,
105 ); 106 );
@@ -113,10 +114,10 @@ class CustomWatchThemePreviewController extends GetxController { @@ -113,10 +114,10 @@ class CustomWatchThemePreviewController extends GetxController {
113 final result = await _themeApi.deleteTheme(themeId); 114 final result = await _themeApi.deleteTheme(themeId);
114 isDeleting.value = false; 115 isDeleting.value = false;
115 if (result is! AppSuccess<void>) { 116 if (result is! AppSuccess<void>) {
116 - AppToast.show('删除主题失败'); 117 + AppToast.show(l10n.watchThemeDeleteFailed);
117 return; 118 return;
118 } 119 }
119 - AppToast.show('已删除主题'); 120 + AppToast.show(l10n.watchThemeDeleted);
120 Get.back(); 121 Get.back();
121 } 122 }
122 } 123 }
@@ -188,7 +189,7 @@ class CustomWatchThemePreviewController extends GetxController { @@ -188,7 +189,7 @@ class CustomWatchThemePreviewController extends GetxController {
188 Future<bool> applyAndSyncWatchFace() async { 189 Future<bool> applyAndSyncWatchFace() async {
189 final themeId = themeItem.id; 190 final themeId = themeItem.id;
190 if (themeId == null) { 191 if (themeId == null) {
191 - AppToast.show('主题信息不完整'); 192 + AppToast.show(l10n.watchThemeIncomplete);
192 return false; 193 return false;
193 } 194 }
194 195
@@ -196,7 +197,7 @@ class CustomWatchThemePreviewController extends GetxController { @@ -196,7 +197,7 @@ class CustomWatchThemePreviewController extends GetxController {
196 final result = await _themeApi.applyTheme(themeId); 197 final result = await _themeApi.applyTheme(themeId);
197 if (result is! AppSuccess<void>) { 198 if (result is! AppSuccess<void>) {
198 isApplying.value = false; 199 isApplying.value = false;
199 - AppToast.show('应用主题失败'); 200 + AppToast.show(l10n.watchThemeApplyFailed);
200 return false; 201 return false;
201 } 202 }
202 203
@@ -213,7 +214,7 @@ class CustomWatchThemePreviewController extends GetxController { @@ -213,7 +214,7 @@ class CustomWatchThemePreviewController extends GetxController {
213 } 214 }
214 isApplying.value = false; 215 isApplying.value = false;
215 if (!syncSuccess) { 216 if (!syncSuccess) {
216 - AppToast.show('表盘同步失败'); 217 + AppToast.show(l10n.watchThemeWatchSyncFailed);
217 } 218 }
218 return syncSuccess; 219 return syncSuccess;
219 } 220 }
@@ -8,6 +8,7 @@ import 'package:doublefeel_flutter/core/result/app_result.dart'; @@ -8,6 +8,7 @@ import 'package:doublefeel_flutter/core/result/app_result.dart';
8 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart'; 8 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart';
9 import 'package:doublefeel_flutter/data/models/local/user_preferences.dart'; 9 import 'package:doublefeel_flutter/data/models/local/user_preferences.dart';
10 import 'package:get/get.dart'; 10 import 'package:get/get.dart';
  11 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
11 12
12 import '../models/watch_theme_models.dart'; 13 import '../models/watch_theme_models.dart';
13 14
@@ -86,13 +87,15 @@ class WatchThemeController extends GetxController { @@ -86,13 +87,15 @@ class WatchThemeController extends GetxController {
86 final vipPrefs = UserPreferencesVipInfo.fromVipInfo(vip); 87 final vipPrefs = UserPreferencesVipInfo.fromVipInfo(vip);
87 await Get.find<UserPreferencesStorage>().updateVipInfo(vipPrefs); 88 await Get.find<UserPreferencesStorage>().updateVipInfo(vipPrefs);
88 isPremium.value = vipPrefs.isVip; 89 isPremium.value = vipPrefs.isVip;
89 - } on Exception catch (e) {} 90 + } on Exception catch (_) {
  91 + // Keep the current membership state when local persistence fails.
  92 + }
90 } 93 }
91 } 94 }
92 95
93 Future<void> _toPremiumPage() async { 96 Future<void> _toPremiumPage() async {
94 await Get.toNamed(Routes.PURCHASE, arguments: { 97 await Get.toNamed(Routes.PURCHASE, arguments: {
95 - IntentKeys.channelType: '表盘主题', 98 + IntentKeys.channelType: l10n.watchThemePurchaseChannel,
96 }); 99 });
97 await _refreshVip(); 100 await _refreshVip();
98 } 101 }
@@ -10,6 +10,7 @@ import 'package:doublefeel_flutter/pigeon/platform_api.g.dart'; @@ -10,6 +10,7 @@ import 'package:doublefeel_flutter/pigeon/platform_api.g.dart';
10 import 'package:doublefeel_flutter/pigeon/wear_engine_api.g.dart'; 10 import 'package:doublefeel_flutter/pigeon/wear_engine_api.g.dart';
11 import 'package:flutter/material.dart'; 11 import 'package:flutter/material.dart';
12 import 'package:get/get.dart'; 12 import 'package:get/get.dart';
  13 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
13 14
14 import '../../friends/models/friend_health_data.dart'; 15 import '../../friends/models/friend_health_data.dart';
15 import '../../friends/views/select_friend_view.dart'; 16 import '../../friends/views/select_friend_view.dart';
@@ -160,7 +161,7 @@ class WatchThemePreviewController extends GetxController { @@ -160,7 +161,7 @@ class WatchThemePreviewController extends GetxController {
160 Future<bool> applyAndSyncWatchFace() async { 161 Future<bool> applyAndSyncWatchFace() async {
161 final themeId = themeItem.id; 162 final themeId = themeItem.id;
162 if (themeId == null) { 163 if (themeId == null) {
163 - AppToast.show('主题信息不完整'); 164 + AppToast.show(l10n.watchThemeIncomplete);
164 return false; 165 return false;
165 } 166 }
166 167
@@ -168,7 +169,7 @@ class WatchThemePreviewController extends GetxController { @@ -168,7 +169,7 @@ class WatchThemePreviewController extends GetxController {
168 final result = await _themeApi.applyTheme(themeId); 169 final result = await _themeApi.applyTheme(themeId);
169 if (result is! AppSuccess<void>) { 170 if (result is! AppSuccess<void>) {
170 isApplying.value = false; 171 isApplying.value = false;
171 - AppToast.show('应用主题失败'); 172 + AppToast.show(l10n.watchThemeApplyFailed);
172 return false; 173 return false;
173 } 174 }
174 175
@@ -185,7 +186,7 @@ class WatchThemePreviewController extends GetxController { @@ -185,7 +186,7 @@ class WatchThemePreviewController extends GetxController {
185 } 186 }
186 isApplying.value = false; 187 isApplying.value = false;
187 if (!syncSuccess) { 188 if (!syncSuccess) {
188 - AppToast.show('表盘同步失败'); 189 + AppToast.show(l10n.watchThemeWatchSyncFailed);
189 } 190 }
190 return syncSuccess; 191 return syncSuccess;
191 } 192 }
1 import 'dart:ui'; 1 import 'dart:ui';
2 2
  3 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
  4 +
3 import '../widgets/watch_theme_colors.dart'; 5 import '../widgets/watch_theme_colors.dart';
4 6
5 class WatchThemeItem { 7 class WatchThemeItem {
@@ -46,18 +48,24 @@ class WatchThemeItem { @@ -46,18 +48,24 @@ class WatchThemeItem {
46 id: _intFromJson(json['id']), 48 id: _intFromJson(json['id']),
47 userId: _intFromJson(json['user_id']), 49 userId: _intFromJson(json['user_id']),
48 status: _intFromJson(json['status']), 50 status: _intFromJson(json['status']),
49 - themeName: _stringFromJson(json['theme_name'], '自定义主题'),  
50 - energeticDescription:  
51 - _stringFromJson(json['energetic_description'], '状态优秀'), 51 + themeName: _stringFromJson(
  52 + json['theme_name'],
  53 + l10n.watchThemeCustomTheme,
  54 + ),
  55 + energeticDescription: _stringFromJson(
  56 + json['energetic_description'], l10n.watchThemeExcellent),
52 energeticImage: _nullableStringFromJson(json['energetic_image']), 57 energeticImage: _nullableStringFromJson(json['energetic_image']),
53 - normalDescription: _stringFromJson(json['normal_description'], '状态正常'), 58 + normalDescription:
  59 + _stringFromJson(json['normal_description'], l10n.watchThemeNormal),
54 normalImage: _nullableStringFromJson(json['normal_image']), 60 normalImage: _nullableStringFromJson(json['normal_image']),
55 - slightStressfulDescription:  
56 - _stringFromJson(json['slight_stressful_description'], '注意压力'), 61 + slightStressfulDescription: _stringFromJson(
  62 + json['slight_stressful_description'],
  63 + l10n.watchThemeSlightStressful,
  64 + ),
57 slightStressfulImage: 65 slightStressfulImage:
58 _nullableStringFromJson(json['slight_stressful_image']), 66 _nullableStringFromJson(json['slight_stressful_image']),
59 - stressfulDescription:  
60 - _stringFromJson(json['stressful_description'], '压力过载'), 67 + stressfulDescription: _stringFromJson(
  68 + json['stressful_description'], l10n.watchThemeStressful),
61 stressfulImage: _nullableStringFromJson(json['stressful_image']), 69 stressfulImage: _nullableStringFromJson(json['stressful_image']),
62 isOfficial: _intFromJson(json['is_official']) ?? 0, 70 isOfficial: _intFromJson(json['is_official']) ?? 0,
63 isDefaultTheme: _intFromJson(json['is_default_theme']) ?? 0, 71 isDefaultTheme: _intFromJson(json['is_default_theme']) ?? 0,
@@ -117,12 +125,12 @@ class WatchThemeItem { @@ -117,12 +125,12 @@ class WatchThemeItem {
117 ]; 125 ];
118 126
119 static WatchThemeItem empty() { 127 static WatchThemeItem empty() {
120 - return const WatchThemeItem(  
121 - themeName: '自定义主题',  
122 - energeticDescription: '状态优秀',  
123 - normalDescription: '状态正常',  
124 - slightStressfulDescription: '注意压力',  
125 - stressfulDescription: '压力过载', 128 + return WatchThemeItem(
  129 + themeName: l10n.watchThemeCustomTheme,
  130 + energeticDescription: l10n.watchThemeExcellent,
  131 + normalDescription: l10n.watchThemeNormal,
  132 + slightStressfulDescription: l10n.watchThemeSlightStressful,
  133 + stressfulDescription: l10n.watchThemeStressful,
126 ); 134 );
127 } 135 }
128 136
@@ -226,12 +234,24 @@ class WatchThemeUpsertRequest { @@ -226,12 +234,24 @@ class WatchThemeUpsertRequest {
226 } 234 }
227 } 235 }
228 236
229 -final defaultThemeTemplates = [  
230 - WatchThemeTemplateItem(title: '状态优秀', color: WatchThemeColors.excellent),  
231 - WatchThemeTemplateItem(title: '状态正常', color: WatchThemeColors.normal),  
232 - WatchThemeTemplateItem(title: '注意压力', color: WatchThemeColors.stress),  
233 - WatchThemeTemplateItem(title: '压力过载', color: WatchThemeColors.overload),  
234 -]; 237 +List<WatchThemeTemplateItem> get defaultThemeTemplates => [
  238 + WatchThemeTemplateItem(
  239 + title: l10n.watchThemeExcellent,
  240 + color: WatchThemeColors.excellent,
  241 + ),
  242 + WatchThemeTemplateItem(
  243 + title: l10n.watchThemeNormal,
  244 + color: WatchThemeColors.normal,
  245 + ),
  246 + WatchThemeTemplateItem(
  247 + title: l10n.watchThemeSlightStressful,
  248 + color: WatchThemeColors.stress,
  249 + ),
  250 + WatchThemeTemplateItem(
  251 + title: l10n.watchThemeStressful,
  252 + color: WatchThemeColors.overload,
  253 + ),
  254 + ];
235 255
236 class WatchThemeTemplateItem { 256 class WatchThemeTemplateItem {
237 WatchThemeTemplateItem({required this.title, required this.color}); 257 WatchThemeTemplateItem({required this.title, required this.color});
@@ -2,6 +2,7 @@ import 'dart:io'; @@ -2,6 +2,7 @@ import 'dart:io';
2 2
3 import 'package:flutter/material.dart'; 3 import 'package:flutter/material.dart';
4 import 'package:get/get.dart'; 4 import 'package:get/get.dart';
  5 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
5 6
6 import '../controllers/create_watch_theme_controller.dart'; 7 import '../controllers/create_watch_theme_controller.dart';
7 import '../widgets/watch_face_preview.dart'; 8 import '../widgets/watch_face_preview.dart';
@@ -22,7 +23,7 @@ class CreateWatchThemeView extends GetView<CreateWatchThemeController> { @@ -22,7 +23,7 @@ class CreateWatchThemeView extends GetView<CreateWatchThemeController> {
22 } 23 }
23 }, 24 },
24 child: WatchThemeGradientScaffold( 25 child: WatchThemeGradientScaffold(
25 - title: '创作主题', 26 + title: context.l10n.watchThemeCreateTheme,
26 onBack: controller.handleCreateBack, 27 onBack: controller.handleCreateBack,
27 body: SingleChildScrollView( 28 body: SingleChildScrollView(
28 physics: const AlwaysScrollableScrollPhysics(), 29 physics: const AlwaysScrollableScrollPhysics(),
@@ -74,7 +75,7 @@ class _EditorCard extends StatelessWidget { @@ -74,7 +75,7 @@ class _EditorCard extends StatelessWidget {
74 crossAxisAlignment: CrossAxisAlignment.start, 75 crossAxisAlignment: CrossAxisAlignment.start,
75 children: [ 76 children: [
76 Text( 77 Text(
77 - '自定义主题', 78 + context.l10n.watchThemeCustomTheme,
78 style: TextStyle( 79 style: TextStyle(
79 color: WatchThemeColors.textPrimary, 80 color: WatchThemeColors.textPrimary,
80 fontSize: 16, 81 fontSize: 16,
@@ -83,7 +84,7 @@ class _EditorCard extends StatelessWidget { @@ -83,7 +84,7 @@ class _EditorCard extends StatelessWidget {
83 ), 84 ),
84 SizedBox(height: 4), 85 SizedBox(height: 4),
85 Text( 86 Text(
86 - '仅支持上传图片', 87 + context.l10n.watchThemeImagesOnly,
87 style: TextStyle( 88 style: TextStyle(
88 color: WatchThemeColors.textSecondary, 89 color: WatchThemeColors.textSecondary,
89 fontSize: 12, 90 fontSize: 12,
@@ -116,7 +117,7 @@ class _EditorCard extends StatelessWidget { @@ -116,7 +117,7 @@ class _EditorCard extends StatelessWidget {
116 ), 117 ),
117 SizedBox(height: 14), 118 SizedBox(height: 14),
118 Text( 119 Text(
119 - '主题名称', 120 + context.l10n.watchThemeName,
120 style: TextStyle( 121 style: TextStyle(
121 color: WatchThemeColors.textPrimary, 122 color: WatchThemeColors.textPrimary,
122 fontSize: 16, 123 fontSize: 16,
@@ -137,7 +138,7 @@ class _EditorCard extends StatelessWidget { @@ -137,7 +138,7 @@ class _EditorCard extends StatelessWidget {
137 maxLength: 10, 138 maxLength: 10,
138 decoration: InputDecoration( 139 decoration: InputDecoration(
139 counterText: '', 140 counterText: '',
140 - hintText: '最多10个字符', 141 + hintText: context.l10n.watchThemeNameMaxLength,
141 hintStyle: TextStyle( 142 hintStyle: TextStyle(
142 color: WatchThemeColors.textTertiary, 143 color: WatchThemeColors.textTertiary,
143 fontSize: 14, 144 fontSize: 14,
@@ -251,7 +252,7 @@ class _AgreementRow extends StatelessWidget { @@ -251,7 +252,7 @@ class _AgreementRow extends StatelessWidget {
251 ), 252 ),
252 SizedBox(width: 4), 253 SizedBox(width: 4),
253 Text( 254 Text(
254 - '我已阅读并同意用户投稿协议', 255 + context.l10n.watchThemeSubmissionAgreement,
255 style: TextStyle( 256 style: TextStyle(
256 color: WatchThemeColors.textSecondary, 257 color: WatchThemeColors.textSecondary,
257 fontSize: 12, 258 fontSize: 12,
@@ -287,7 +288,9 @@ class _SaveButton extends StatelessWidget { @@ -287,7 +288,9 @@ class _SaveButton extends StatelessWidget {
287 borderRadius: BorderRadius.circular(24), 288 borderRadius: BorderRadius.circular(24),
288 ), 289 ),
289 child: Text( 290 child: Text(
290 - controller.isSaving.value ? '保存中' : '保存主题', 291 + controller.isSaving.value
  292 + ? context.l10n.watchThemeSaving
  293 + : context.l10n.watchThemeSaveTheme,
291 style: TextStyle( 294 style: TextStyle(
292 color: Colors.white, 295 color: Colors.white,
293 fontSize: 16, 296 fontSize: 16,
1 import 'package:doublefeel_flutter/app/modules/watch_theme/widgets/dial_preview_card.dart'; 1 import 'package:doublefeel_flutter/app/modules/watch_theme/widgets/dial_preview_card.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 import 'package:get/get.dart'; 3 import 'package:get/get.dart';
  4 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
4 5
5 import '../controllers/custom_watch_theme_preview_controller.dart'; 6 import '../controllers/custom_watch_theme_preview_controller.dart';
6 import '../widgets/status_preview_card.dart'; 7 import '../widgets/status_preview_card.dart';
@@ -16,13 +17,13 @@ class CustomWatchThemePreviewView @@ -16,13 +17,13 @@ class CustomWatchThemePreviewView
16 Widget build(BuildContext context) { 17 Widget build(BuildContext context) {
17 final topPadding = MediaQuery.paddingOf(context).top + kToolbarHeight; 18 final topPadding = MediaQuery.paddingOf(context).top + kToolbarHeight;
18 return WatchThemeGradientScaffold( 19 return WatchThemeGradientScaffold(
19 - title: '预览', 20 + title: context.l10n.watchThemePreview,
20 onBack: controller.executeBackLogic, 21 onBack: controller.executeBackLogic,
21 trailing: GestureDetector( 22 trailing: GestureDetector(
22 onTap: controller.confirmDeleteCustomTheme, 23 onTap: controller.confirmDeleteCustomTheme,
23 - child: const Text(  
24 - '删除',  
25 - style: TextStyle( 24 + child: Text(
  25 + context.l10n.watchThemeDelete,
  26 + style: const TextStyle(
26 color: Color(0xFFFC4447), 27 color: Color(0xFFFC4447),
27 fontSize: 14, 28 fontSize: 14,
28 fontWeight: FontWeight.w600, 29 fontWeight: FontWeight.w600,
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:get/get.dart'; 2 import 'package:get/get.dart';
  3 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
3 4
4 import '../controllers/watch_theme_preview_controller.dart'; 5 import '../controllers/watch_theme_preview_controller.dart';
5 import '../widgets/dial_preview_card.dart'; 6 import '../widgets/dial_preview_card.dart';
@@ -15,7 +16,7 @@ class WatchThemePreviewView extends GetView<WatchThemePreviewController> { @@ -15,7 +16,7 @@ class WatchThemePreviewView extends GetView<WatchThemePreviewController> {
15 Widget build(BuildContext context) { 16 Widget build(BuildContext context) {
16 final topPadding = MediaQuery.paddingOf(context).top + kToolbarHeight; 17 final topPadding = MediaQuery.paddingOf(context).top + kToolbarHeight;
17 return WatchThemeGradientScaffold( 18 return WatchThemeGradientScaffold(
18 - title: '预览', 19 + title: context.l10n.watchThemePreview,
19 onBack: controller.executeBackLogic, 20 onBack: controller.executeBackLogic,
20 body: SingleChildScrollView( 21 body: SingleChildScrollView(
21 physics: const AlwaysScrollableScrollPhysics(), 22 physics: const AlwaysScrollableScrollPhysics(),
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:get/get.dart'; 2 import 'package:get/get.dart';
  3 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
3 4
4 import '../controllers/watch_theme_controller.dart'; 5 import '../controllers/watch_theme_controller.dart';
5 import '../widgets/custom_theme_card.dart'; 6 import '../widgets/custom_theme_card.dart';
@@ -14,7 +15,7 @@ class WatchThemeView extends GetView<WatchThemeController> { @@ -14,7 +15,7 @@ class WatchThemeView extends GetView<WatchThemeController> {
14 Widget build(BuildContext context) { 15 Widget build(BuildContext context) {
15 final topPadding = MediaQuery.paddingOf(context).top + kToolbarHeight; 16 final topPadding = MediaQuery.paddingOf(context).top + kToolbarHeight;
16 return WatchThemeGradientScaffold( 17 return WatchThemeGradientScaffold(
17 - title: 'Watch主题', 18 + title: context.l10n.watchThemePageTitle,
18 onBack: controller.executeBackLogic, 19 onBack: controller.executeBackLogic,
19 body: Obx( 20 body: Obx(
20 () => SingleChildScrollView( 21 () => SingleChildScrollView(
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:get/utils.dart'; 2 import 'package:get/utils.dart';
  3 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
3 4
4 import '../models/watch_theme_models.dart'; 5 import '../models/watch_theme_models.dart';
5 import 'watch_theme_character_avatar.dart'; 6 import 'watch_theme_character_avatar.dart';
@@ -31,12 +32,12 @@ class CustomThemeCard extends StatelessWidget { @@ -31,12 +32,12 @@ class CustomThemeCard extends StatelessWidget {
31 crossAxisAlignment: CrossAxisAlignment.start, 32 crossAxisAlignment: CrossAxisAlignment.start,
32 children: [ 33 children: [
33 WatchThemeSectionTitle( 34 WatchThemeSectionTitle(
34 - '自定义主题', 35 + context.l10n.watchThemeCustomTheme,
35 trailing: isPremium ? null : const WatchThemeProBadge(), 36 trailing: isPremium ? null : const WatchThemeProBadge(),
36 ), 37 ),
37 SizedBox(height: 4), 38 SizedBox(height: 4),
38 Text( 39 Text(
39 - '用创意记录每一次情绪波动,打造懂你的专属表盘吧~', 40 + context.l10n.watchThemeCustomDescription,
40 maxLines: 1, 41 maxLines: 1,
41 overflow: TextOverflow.ellipsis, 42 overflow: TextOverflow.ellipsis,
42 style: TextStyle( 43 style: TextStyle(
@@ -57,12 +58,12 @@ class CustomThemeCard extends StatelessWidget { @@ -57,12 +58,12 @@ class CustomThemeCard extends StatelessWidget {
57 padding: EdgeInsets.zero, 58 padding: EdgeInsets.zero,
58 itemBuilder: (context, index) { 59 itemBuilder: (context, index) {
59 return _CustomThemeItem( 60 return _CustomThemeItem(
60 - item: customThemes[index],  
61 - selected: customThemes[index].id != null &&  
62 - customThemes[index].id == activeThemeId,  
63 - onTap: onThemeTap == null  
64 - ? null  
65 - : () => onThemeTap!(customThemes[index]), 61 + item: customThemes[index],
  62 + selected: customThemes[index].id != null &&
  63 + customThemes[index].id == activeThemeId,
  64 + onTap: onThemeTap == null
  65 + ? null
  66 + : () => onThemeTap!(customThemes[index]),
66 ); 67 );
67 }, 68 },
68 separatorBuilder: (context, index) { 69 separatorBuilder: (context, index) {
@@ -114,7 +115,7 @@ class _CreateThemeButton extends StatelessWidget { @@ -114,7 +115,7 @@ class _CreateThemeButton extends StatelessWidget {
114 ), 115 ),
115 SizedBox(width: 8), 116 SizedBox(width: 8),
116 Text( 117 Text(
117 - '创作主题', 118 + context.l10n.watchThemeCreateTheme,
118 style: TextStyle( 119 style: TextStyle(
119 color: WatchThemeColors.textPrimary, 120 color: WatchThemeColors.textPrimary,
120 fontSize: 14, 121 fontSize: 14,
1 -  
2 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
3 import 'package:get/get.dart'; 2 import 'package:get/get.dart';
  3 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
4 4
5 import 'watch_face_preview.dart'; 5 import 'watch_face_preview.dart';
6 import 'watch_theme_section_card.dart'; 6 import 'watch_theme_section_card.dart';
7 7
8 class DialPreviewCard extends StatelessWidget { 8 class DialPreviewCard extends StatelessWidget {
9 - bool showFriend; 9 + final bool showFriend;
10 final String? themeImageUrl; 10 final String? themeImageUrl;
11 final String? themeImageUrl2; 11 final String? themeImageUrl2;
12 final Function()? switchFriend; 12 final Function()? switchFriend;
13 - DialPreviewCard( 13 + const DialPreviewCard(
14 {super.key, 14 {super.key,
15 required this.showFriend, 15 required this.showFriend,
16 this.themeImageUrl, 16 this.themeImageUrl,
@@ -24,7 +24,8 @@ class DialPreviewCard extends StatelessWidget { @@ -24,7 +24,8 @@ class DialPreviewCard extends StatelessWidget {
24 child: Column( 24 child: Column(
25 crossAxisAlignment: CrossAxisAlignment.start, 25 crossAxisAlignment: CrossAxisAlignment.start,
26 children: [ 26 children: [
27 - const WatchThemeSectionTitle('表盘预览').paddingOnly(left: 20), 27 + WatchThemeSectionTitle(context.l10n.watchThemeDialPreview)
  28 + .paddingOnly(left: 20),
28 SizedBox(height: 16), 29 SizedBox(height: 16),
29 SizedBox( 30 SizedBox(
30 height: showFriend ? 172 : 136, 31 height: showFriend ? 172 : 136,
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
  2 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
2 3
3 import '../models/watch_theme_models.dart'; 4 import '../models/watch_theme_models.dart';
4 import 'watch_theme_character_avatar.dart'; 5 import 'watch_theme_character_avatar.dart';
@@ -24,58 +25,58 @@ class OfficialThemeGrid extends StatelessWidget { @@ -24,58 +25,58 @@ class OfficialThemeGrid extends StatelessWidget {
24 child: Column( 25 child: Column(
25 crossAxisAlignment: CrossAxisAlignment.start, 26 crossAxisAlignment: CrossAxisAlignment.start,
26 children: [ 27 children: [
27 - const WatchThemeSectionTitle('官方主题'), 28 + WatchThemeSectionTitle(context.l10n.watchThemeOfficialTheme),
28 SizedBox(height: 22), 29 SizedBox(height: 22),
29 themes.isEmpty 30 themes.isEmpty
30 ? SizedBox( 31 ? SizedBox(
31 height: 114, 32 height: 114,
32 ) 33 )
33 - :  
34 - GridView.builder(  
35 - shrinkWrap: true,  
36 - padding: EdgeInsets.zero,  
37 - physics: const NeverScrollableScrollPhysics(),  
38 - itemCount: themes.length,  
39 - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(  
40 - crossAxisCount: 3,  
41 - mainAxisSpacing: 21,  
42 - crossAxisSpacing: 19,  
43 - mainAxisExtent: 114,  
44 - ),  
45 - itemBuilder: (context, index) {  
46 - final theme = themes[index];  
47 - return GestureDetector(  
48 - behavior: HitTestBehavior.opaque,  
49 - onTap: () => onThemeTap(index),  
50 - child: Column(  
51 - children: [  
52 - WatchThemeSelectedView(  
53 - selected: theme.id != null && theme.id == activeThemeId,  
54 - size: 88,  
55 - child: WatchThemeCharacterAvatar(  
56 - size: 88,  
57 - assetPath: theme.infoList.firstOrNull?.assetPath,  
58 - imageUrl: theme.infoList.firstOrNull?.imgUrl, 34 + : GridView.builder(
  35 + shrinkWrap: true,
  36 + padding: EdgeInsets.zero,
  37 + physics: const NeverScrollableScrollPhysics(),
  38 + itemCount: themes.length,
  39 + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  40 + crossAxisCount: 3,
  41 + mainAxisSpacing: 21,
  42 + crossAxisSpacing: 19,
  43 + mainAxisExtent: 114,
  44 + ),
  45 + itemBuilder: (context, index) {
  46 + final theme = themes[index];
  47 + return GestureDetector(
  48 + behavior: HitTestBehavior.opaque,
  49 + onTap: () => onThemeTap(index),
  50 + child: Column(
  51 + children: [
  52 + WatchThemeSelectedView(
  53 + selected:
  54 + theme.id != null && theme.id == activeThemeId,
  55 + size: 88,
  56 + child: WatchThemeCharacterAvatar(
  57 + size: 88,
  58 + assetPath: theme.infoList.firstOrNull?.assetPath,
  59 + imageUrl: theme.infoList.firstOrNull?.imgUrl,
  60 + ),
  61 + ),
  62 + SizedBox(height: 8),
  63 + Text(
  64 + theme.title,
  65 + textAlign: TextAlign.center,
  66 + maxLines: 1,
  67 + overflow: TextOverflow.ellipsis,
  68 + style: TextStyle(
  69 + color: WatchThemeColors.textPrimary,
  70 + fontSize: 12,
  71 + fontWeight: FontWeight.w400,
  72 + height: 1.25,
  73 + ),
  74 + ),
  75 + ],
59 ), 76 ),
60 - ),  
61 - SizedBox(height: 8),  
62 - Text(  
63 - theme.title,  
64 - textAlign: TextAlign.center,  
65 - maxLines: 1,  
66 - overflow: TextOverflow.ellipsis,  
67 - style: TextStyle(  
68 - color: WatchThemeColors.textPrimary,  
69 - fontSize: 12,  
70 - fontWeight: FontWeight.w400,  
71 - height: 1.25,  
72 - ),  
73 - ),  
74 - ], 77 + );
  78 + },
75 ), 79 ),
76 - );  
77 - },  
78 - ),  
79 ], 80 ],
80 ), 81 ),
81 ); 82 );
1 import 'package:doublefeel_flutter/app/modules/watch_theme/models/watch_theme_models.dart'; 1 import 'package:doublefeel_flutter/app/modules/watch_theme/models/watch_theme_models.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
  3 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
3 4
4 import 'watch_theme_character_avatar.dart'; 5 import 'watch_theme_character_avatar.dart';
5 import 'watch_theme_section_card.dart'; 6 import 'watch_theme_section_card.dart';
@@ -15,7 +16,7 @@ class StatusPreviewCard extends StatelessWidget { @@ -15,7 +16,7 @@ class StatusPreviewCard extends StatelessWidget {
15 child: Column( 16 child: Column(
16 crossAxisAlignment: CrossAxisAlignment.start, 17 crossAxisAlignment: CrossAxisAlignment.start,
17 children: [ 18 children: [
18 - const WatchThemeSectionTitle('状态预览'), 19 + WatchThemeSectionTitle(context.l10n.watchThemeStatusPreview),
19 const SizedBox(height: 24), 20 const SizedBox(height: 24),
20 Row( 21 Row(
21 mainAxisAlignment: MainAxisAlignment.spaceBetween, 22 mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -3,6 +3,7 @@ import 'dart:io'; @@ -3,6 +3,7 @@ import 'dart:io';
3 import 'package:cached_network_image/cached_network_image.dart'; 3 import 'package:cached_network_image/cached_network_image.dart';
4 import 'package:flutter/material.dart'; 4 import 'package:flutter/material.dart';
5 import 'package:get/get.dart'; 5 import 'package:get/get.dart';
  6 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
6 7
7 enum WatchFacePreviewType { 8 enum WatchFacePreviewType {
8 surface, 9 surface,
@@ -64,17 +65,17 @@ class WatchFacePreview extends StatelessWidget { @@ -64,17 +65,17 @@ class WatchFacePreview extends StatelessWidget {
64 children: [ 65 children: [
65 Stack( 66 Stack(
66 alignment: Alignment.topCenter, 67 alignment: Alignment.topCenter,
67 - clipBehavior: Clip.none,  
68 - children: [  
69 - Image(  
70 - image: AssetImage(_backgroundAsset),  
71 - width: size.width,  
72 - height: size.height,  
73 - fit: BoxFit.fitWidth, 68 + clipBehavior: Clip.none,
  69 + children: [
  70 + Image(
  71 + image: AssetImage(_backgroundAsset),
  72 + width: size.width,
  73 + height: size.height,
  74 + fit: BoxFit.fitWidth,
  75 + ),
  76 + _buildThemeImages(),
  77 + ],
74 ), 78 ),
75 - _buildThemeImages(),  
76 - ],  
77 - ),  
78 type == WatchFacePreviewType.coupleSmall 79 type == WatchFacePreviewType.coupleSmall
79 ? GestureDetector( 80 ? GestureDetector(
80 onTap: switchFriend, 81 onTap: switchFriend,
@@ -86,7 +87,7 @@ class WatchFacePreview extends StatelessWidget { @@ -86,7 +87,7 @@ class WatchFacePreview extends StatelessWidget {
86 border: Border.all(width: 1, color: Color(0xFFC3ADFF)), 87 border: Border.all(width: 1, color: Color(0xFFC3ADFF)),
87 borderRadius: BorderRadius.all(Radius.circular(12))), 88 borderRadius: BorderRadius.all(Radius.circular(12))),
88 child: Text( 89 child: Text(
89 - '切换好友', 90 + context.l10n.watchThemeSwitchFriend,
90 style: TextStyle( 91 style: TextStyle(
91 fontSize: 12, 92 fontSize: 12,
92 fontWeight: FontWeight.w600, 93 fontWeight: FontWeight.w600,
@@ -143,7 +144,7 @@ class WatchFacePreview extends StatelessWidget { @@ -143,7 +144,7 @@ class WatchFacePreview extends StatelessWidget {
143 height: themeSize.height, 144 height: themeSize.height,
144 child: _buildFaceImage(themeImageUrl, 145 child: _buildFaceImage(themeImageUrl,
145 'assets/images/watch_theme/official_default_green.png'), 146 'assets/images/watch_theme/official_default_green.png'),
146 - ), 147 + ),
147 SizedBox( 148 SizedBox(
148 width: 12, 149 width: 12,
149 ), 150 ),
1 -  
2 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
  2 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
3 3
4 import 'watch_theme_colors.dart'; 4 import 'watch_theme_colors.dart';
5 5
@@ -26,7 +26,7 @@ class WatchThemeBottomActions extends StatelessWidget { @@ -26,7 +26,7 @@ class WatchThemeBottomActions extends StatelessWidget {
26 children: [ 26 children: [
27 Expanded( 27 Expanded(
28 child: _ActionButton( 28 child: _ActionButton(
29 - label: '添加表盘', 29 + label: context.l10n.watchThemeAddWatchFace,
30 color: WatchThemeColors.brand, 30 color: WatchThemeColors.brand,
31 textColor: Colors.white, 31 textColor: Colors.white,
32 onTap: onAddTap, 32 onTap: onAddTap,
@@ -35,7 +35,9 @@ class WatchThemeBottomActions extends StatelessWidget { @@ -35,7 +35,9 @@ class WatchThemeBottomActions extends StatelessWidget {
35 SizedBox(width: 12), 35 SizedBox(width: 12),
36 Expanded( 36 Expanded(
37 child: _ActionButton( 37 child: _ActionButton(
38 - label: isInUsage ? '正在使用' : '立即使用', 38 + label: isInUsage
  39 + ? context.l10n.watchThemeInUse
  40 + : context.l10n.watchThemeUseNow,
39 color: isInUsage 41 color: isInUsage
40 ? WatchThemeColors.brand.withValues(alpha: 0.4) 42 ? WatchThemeColors.brand.withValues(alpha: 0.4)
41 : WatchThemeColors.brand, 43 : WatchThemeColors.brand,
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:get/get.dart'; 2 import 'package:get/get.dart';
  3 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
3 4
4 class WatchThemeRenameDialog extends StatefulWidget { 5 class WatchThemeRenameDialog extends StatefulWidget {
5 const WatchThemeRenameDialog({super.key, required this.initialValue}); 6 const WatchThemeRenameDialog({super.key, required this.initialValue});
@@ -40,9 +41,9 @@ class _WatchThemeRenameDialogState extends State<WatchThemeRenameDialog> { @@ -40,9 +41,9 @@ class _WatchThemeRenameDialogState extends State<WatchThemeRenameDialog> {
40 child: Column( 41 child: Column(
41 mainAxisSize: MainAxisSize.min, 42 mainAxisSize: MainAxisSize.min,
42 children: [ 43 children: [
43 - const Text(  
44 - '修改状态名称',  
45 - style: TextStyle( 44 + Text(
  45 + context.l10n.watchThemeRenameStatus,
  46 + style: const TextStyle(
46 color: Color(0xFF141414), 47 color: Color(0xFF141414),
47 fontSize: 18, 48 fontSize: 18,
48 fontWeight: FontWeight.w600, 49 fontWeight: FontWeight.w600,
@@ -66,10 +67,11 @@ class _WatchThemeRenameDialogState extends State<WatchThemeRenameDialog> { @@ -66,10 +67,11 @@ class _WatchThemeRenameDialogState extends State<WatchThemeRenameDialog> {
66 child: TextField( 67 child: TextField(
67 controller: _controller, 68 controller: _controller,
68 maxLength: 4, 69 maxLength: 4,
69 - decoration: const InputDecoration( 70 + decoration: InputDecoration(
70 counterText: '', 71 counterText: '',
71 - hintText: '请输入昵称',  
72 - hintStyle: TextStyle(color: Color(0xFFB0B0B6)), 72 + hintText: context.l10n.watchThemeEnterNickname,
  73 + hintStyle:
  74 + const TextStyle(color: Color(0xFFB0B0B6)),
73 border: InputBorder.none, 75 border: InputBorder.none,
74 isCollapsed: true, 76 isCollapsed: true,
75 ), 77 ),
@@ -105,9 +107,9 @@ class _WatchThemeRenameDialogState extends State<WatchThemeRenameDialog> { @@ -105,9 +107,9 @@ class _WatchThemeRenameDialogState extends State<WatchThemeRenameDialog> {
105 color: const Color(0xFF845EEE), 107 color: const Color(0xFF845EEE),
106 borderRadius: BorderRadius.circular(24), 108 borderRadius: BorderRadius.circular(24),
107 ), 109 ),
108 - child: const Text(  
109 - '保存',  
110 - style: TextStyle( 110 + child: Text(
  111 + context.l10n.watchThemeSave,
  112 + style: const TextStyle(
111 color: Colors.white, 113 color: Colors.white,
112 fontSize: 14, 114 fontSize: 14,
113 fontWeight: FontWeight.w500, 115 fontWeight: FontWeight.w500,
1 import 'package:doublefeel_flutter/core/util/size_extensions.dart'; 1 import 'package:doublefeel_flutter/core/util/size_extensions.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 import 'package:get/get.dart'; 3 import 'package:get/get.dart';
  4 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
4 5
5 import 'watch_theme_colors.dart'; 6 import 'watch_theme_colors.dart';
6 7
@@ -37,7 +38,7 @@ class WatchThemeFriendPickerDialog extends StatelessWidget { @@ -37,7 +38,7 @@ class WatchThemeFriendPickerDialog extends StatelessWidget {
37 alignment: Alignment.center, 38 alignment: Alignment.center,
38 children: [ 39 children: [
39 Text( 40 Text(
40 - '选择好友', 41 + context.l10n.watchThemeSelectFriend,
41 style: TextStyle( 42 style: TextStyle(
42 color: WatchThemeColors.textPrimary, 43 color: WatchThemeColors.textPrimary,
43 fontSize: 16.dp, 44 fontSize: 16.dp,
@@ -90,7 +91,7 @@ class WatchThemeFriendPickerDialog extends StatelessWidget { @@ -90,7 +91,7 @@ class WatchThemeFriendPickerDialog extends StatelessWidget {
90 borderRadius: BorderRadius.circular(24.dp), 91 borderRadius: BorderRadius.circular(24.dp),
91 ), 92 ),
92 child: Text( 93 child: Text(
93 - '选择并同步至表盘', 94 + context.l10n.watchThemeSelectAndSync,
94 style: TextStyle( 95 style: TextStyle(
95 color: Colors.white, 96 color: Colors.white,
96 fontSize: 16.dp, 97 fontSize: 16.dp,
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
  2 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
2 3
3 import 'watch_face_preview.dart'; 4 import 'watch_face_preview.dart';
4 import 'watch_theme_colors.dart'; 5 import 'watch_theme_colors.dart';
@@ -6,11 +7,11 @@ import 'watch_theme_colors.dart'; @@ -6,11 +7,11 @@ import 'watch_theme_colors.dart';
6 class WatchThemeHeader extends StatelessWidget { 7 class WatchThemeHeader extends StatelessWidget {
7 const WatchThemeHeader({ 8 const WatchThemeHeader({
8 super.key, 9 super.key,
9 - this.title = '默认主题', 10 + this.title,
10 this.themeImageUrl, 11 this.themeImageUrl,
11 }); 12 });
12 13
13 - final String title; 14 + final String? title;
14 final String? themeImageUrl; 15 final String? themeImageUrl;
15 16
16 @override 17 @override
@@ -26,7 +27,7 @@ class WatchThemeHeader extends StatelessWidget { @@ -26,7 +27,7 @@ class WatchThemeHeader extends StatelessWidget {
26 ), 27 ),
27 SizedBox(height: 12), 28 SizedBox(height: 12),
28 Text( 29 Text(
29 - title, 30 + title ?? context.l10n.watchThemeDefaultTheme,
30 style: TextStyle( 31 style: TextStyle(
31 color: WatchThemeColors.textPrimary, 32 color: WatchThemeColors.textPrimary,
32 fontSize: 20, 33 fontSize: 20,
1 import 'package:doublefeel_flutter/core/util/size_extensions.dart'; 1 import 'package:doublefeel_flutter/core/util/size_extensions.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 import 'package:get/get.dart'; 3 import 'package:get/get.dart';
  4 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
4 5
5 import 'watch_theme_colors.dart'; 6 import 'watch_theme_colors.dart';
6 7
@@ -23,7 +24,7 @@ class WatchThemeNoWatchDialog extends StatelessWidget { @@ -23,7 +24,7 @@ class WatchThemeNoWatchDialog extends StatelessWidget {
23 mainAxisSize: MainAxisSize.min, 24 mainAxisSize: MainAxisSize.min,
24 children: [ 25 children: [
25 Text( 26 Text(
26 - '未找到苹果手表', 27 + context.l10n.watchThemeNoWatchTitle,
27 textAlign: TextAlign.center, 28 textAlign: TextAlign.center,
28 style: TextStyle( 29 style: TextStyle(
29 color: const Color(0xFF141414), 30 color: const Color(0xFF141414),
@@ -33,7 +34,7 @@ class WatchThemeNoWatchDialog extends StatelessWidget { @@ -33,7 +34,7 @@ class WatchThemeNoWatchDialog extends StatelessWidget {
33 ), 34 ),
34 SizedBox(height: 16.dp), 35 SizedBox(height: 16.dp),
35 Text( 36 Text(
36 - '请配对苹果手表后再尝试', 37 + context.l10n.watchThemeNoWatchMessage,
37 textAlign: TextAlign.center, 38 textAlign: TextAlign.center,
38 style: TextStyle( 39 style: TextStyle(
39 color: const Color(0xFF6E6D80), 40 color: const Color(0xFF6E6D80),
@@ -53,7 +54,7 @@ class WatchThemeNoWatchDialog extends StatelessWidget { @@ -53,7 +54,7 @@ class WatchThemeNoWatchDialog extends StatelessWidget {
53 borderRadius: BorderRadius.circular(24.dp), 54 borderRadius: BorderRadius.circular(24.dp),
54 ), 55 ),
55 child: Text( 56 child: Text(
56 - '好的', 57 + context.l10n.watchThemeOk,
57 style: TextStyle( 58 style: TextStyle(
58 color: Colors.white, 59 color: Colors.white,
59 fontSize: 14.dp, 60 fontSize: 14.dp,
1 import 'package:doublefeel_flutter/core/util/size_extensions.dart'; 1 import 'package:doublefeel_flutter/core/util/size_extensions.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 import 'package:get/get.dart'; 3 import 'package:get/get.dart';
  4 +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
4 5
5 import 'watch_face_preview.dart'; 6 import 'watch_face_preview.dart';
6 import 'watch_theme_colors.dart'; 7 import 'watch_theme_colors.dart';
@@ -104,7 +105,7 @@ class _WatchThemeSyncDialogState extends State<WatchThemeSyncDialog> { @@ -104,7 +105,7 @@ class _WatchThemeSyncDialogState extends State<WatchThemeSyncDialog> {
104 _WatchThemeSyncState.intro => Padding( 105 _WatchThemeSyncState.intro => Padding(
105 padding: EdgeInsets.symmetric(horizontal: 46.dp), 106 padding: EdgeInsets.symmetric(horizontal: 46.dp),
106 child: Text( 107 child: Text(
107 - '请先打开DoubleFeel手表端App,然后点击下方的“下一步”按钮', 108 + context.l10n.watchThemeSyncIntro,
108 textAlign: TextAlign.center, 109 textAlign: TextAlign.center,
109 style: TextStyle( 110 style: TextStyle(
110 color: WatchThemeColors.textPrimary, 111 color: WatchThemeColors.textPrimary,
@@ -114,7 +115,7 @@ class _WatchThemeSyncDialogState extends State<WatchThemeSyncDialog> { @@ -114,7 +115,7 @@ class _WatchThemeSyncDialogState extends State<WatchThemeSyncDialog> {
114 ), 115 ),
115 ), 116 ),
116 _WatchThemeSyncState.syncing => Text( 117 _WatchThemeSyncState.syncing => Text(
117 - '请保持打开手表App,等待同步', 118 + context.l10n.watchThemeSyncWaiting,
118 textAlign: TextAlign.center, 119 textAlign: TextAlign.center,
119 style: TextStyle( 120 style: TextStyle(
120 color: WatchThemeColors.textPrimary, 121 color: WatchThemeColors.textPrimary,
@@ -141,7 +142,9 @@ class _WatchThemeSyncDialogState extends State<WatchThemeSyncDialog> { @@ -141,7 +142,9 @@ class _WatchThemeSyncDialogState extends State<WatchThemeSyncDialog> {
141 ), 142 ),
142 SizedBox(width: 4.dp), 143 SizedBox(width: 4.dp),
143 Text( 144 Text(
144 - _success ? '同步完成' : '同步失败', 145 + _success
  146 + ? context.l10n.watchThemeSyncComplete
  147 + : context.l10n.watchThemeSyncFailed,
145 style: TextStyle( 148 style: TextStyle(
146 color: WatchThemeColors.textPrimary, 149 color: WatchThemeColors.textPrimary,
147 fontSize: 14.dp, 150 fontSize: 14.dp,
@@ -155,12 +158,12 @@ class _WatchThemeSyncDialogState extends State<WatchThemeSyncDialog> { @@ -155,12 +158,12 @@ class _WatchThemeSyncDialogState extends State<WatchThemeSyncDialog> {
155 Widget _buildAction() { 158 Widget _buildAction() {
156 return switch (_state) { 159 return switch (_state) {
157 _WatchThemeSyncState.intro => _PrimaryButton( 160 _WatchThemeSyncState.intro => _PrimaryButton(
158 - label: '下一步', 161 + label: context.l10n.watchThemeNext,
159 onTap: _startSync, 162 onTap: _startSync,
160 ), 163 ),
161 _WatchThemeSyncState.syncing => const _ProgressButton(progress: 0.85), 164 _WatchThemeSyncState.syncing => const _ProgressButton(progress: 0.85),
162 _WatchThemeSyncState.done => _PrimaryButton( 165 _WatchThemeSyncState.done => _PrimaryButton(
163 - label: '好的', 166 + label: context.l10n.watchThemeOk,
164 onTap: Get.back, 167 onTap: Get.back,
165 ), 168 ),
166 }; 169 };
@@ -223,7 +226,9 @@ class _ProgressButton extends StatelessWidget { @@ -223,7 +226,9 @@ class _ProgressButton extends StatelessWidget {
223 ), 226 ),
224 Center( 227 Center(
225 child: Text( 228 child: Text(
226 - '同步中 ${(progress * 100).round()}%', 229 + context.l10n.watchThemeSyncingProgress(
  230 + (progress * 100).round(),
  231 + ),
227 style: TextStyle( 232 style: TextStyle(
228 color: Colors.white, 233 color: Colors.white,
229 fontSize: 16.dp, 234 fontSize: 16.dp,
@@ -578,5 +578,66 @@ @@ -578,5 +578,66 @@
578 "noHealthDataError2Body": "DoubleFeel requires access to Apple Health data to provide stress stats, alerts, and recommendations. If not authorized, some features may not work properly.\n\nRest assured, all health data is only stored locally and will not be uploaded.\n\nTo enable permissions, follow the prompt and select Allow All -> Health -> DoubleFeel in iOS Settings.", 578 "noHealthDataError2Body": "DoubleFeel requires access to Apple Health data to provide stress stats, alerts, and recommendations. If not authorized, some features may not work properly.\n\nRest assured, all health data is only stored locally and will not be uploaded.\n\nTo enable permissions, follow the prompt and select Allow All -> Health -> DoubleFeel in iOS Settings.",
579 "noHealthDataError3Title": "Error 3: System Issue", 579 "noHealthDataError3Title": "Error 3: System Issue",
580 "noHealthDataError3Body": "Based on user feedback, we found two reasons why HRV or heart rate data might be missing:\n\n1. Apple Watch not connected\n · If your Apple Watch has not been worn for a long time, heart rate data may not be collected.\n · Please check iOS Health App -> 'My Watch' to confirm if recent heart rate data was recorded while wearing the Apple Watch.\n · If not, please try wearing your Apple Watch for data collection and turn on the heart rate feature supported by Apple.\n\n2. Heart rate or HRV data missing in the past 30 days\n · Open iOS Health App -> Browse -> 'Heart Rate' or 'HRV' -> 'No Data Found' to confirm if it's missing.\n · If data is missing, please wear the watch again, restart your iPhone and Apple Watch, then open DoubleFeel again.", 580 "noHealthDataError3Body": "Based on user feedback, we found two reasons why HRV or heart rate data might be missing:\n\n1. Apple Watch not connected\n · If your Apple Watch has not been worn for a long time, heart rate data may not be collected.\n · Please check iOS Health App -> 'My Watch' to confirm if recent heart rate data was recorded while wearing the Apple Watch.\n · If not, please try wearing your Apple Watch for data collection and turn on the heart rate feature supported by Apple.\n\n2. Heart rate or HRV data missing in the past 30 days\n · Open iOS Health App -> Browse -> 'Heart Rate' or 'HRV' -> 'No Data Found' to confirm if it's missing.\n · If data is missing, please wear the watch again, restart your iPhone and Apple Watch, then open DoubleFeel again.",
581 - "noHealthDataGoToSettings": "Go to Settings"  
582 -}  
  581 + "noHealthDataGoToSettings": "Go to Settings",
  582 + "watchThemeDefaultTheme": "Default Theme",
  583 + "watchThemeNoWatchTitle": "Apple Watch Not Found",
  584 + "watchThemeNoWatchMessage": "Pair an Apple Watch and try again",
  585 + "watchThemeOk": "OK",
  586 + "watchThemeSelectFriend": "Select Friend",
  587 + "watchThemeSelectAndSync": "Select and Sync to Watch Face",
  588 + "watchThemeCustomTheme": "Custom Themes",
  589 + "watchThemeCustomDescription": "Capture every mood with your creativity and make a watch face that's uniquely yours.",
  590 + "watchThemeCreateTheme": "Create Theme",
  591 + "watchThemeOfficialTheme": "Official Themes",
  592 + "watchThemeRenameStatus": "Rename Status",
  593 + "watchThemeEnterNickname": "Enter a name",
  594 + "watchThemeSave": "Save",
  595 + "watchThemeDialPreview": "Watch Face Preview",
  596 + "watchThemeSwitchFriend": "Switch Friend",
  597 + "watchThemeStatusPreview": "Status Preview",
  598 + "watchThemeAddWatchFace": "Add Watch Face",
  599 + "watchThemeInUse": "In Use",
  600 + "watchThemeUseNow": "Use Now",
  601 + "watchThemeSyncIntro": "Open the DoubleFeel app on your Apple Watch, then tap Next below.",
  602 + "watchThemeSyncWaiting": "Keep the Watch app open while syncing",
  603 + "watchThemeSyncComplete": "Sync Complete",
  604 + "watchThemeSyncFailed": "Sync Failed",
  605 + "watchThemeNext": "Next",
  606 + "watchThemeSyncingProgress": "Syncing {progress}%",
  607 + "@watchThemeSyncingProgress": {
  608 + "placeholders": {
  609 + "progress": {
  610 + "type": "int"
  611 + }
  612 + }
  613 + },
  614 + "watchThemePreview": "Preview",
  615 + "watchThemeDelete": "Delete",
  616 + "watchThemePageTitle": "Watch Themes",
  617 + "watchThemeImagesOnly": "Images only",
  618 + "watchThemeName": "Theme Name",
  619 + "watchThemeNameMaxLength": "Up to 10 characters",
  620 + "watchThemeSubmissionAgreement": "I have read and agree to the User Submission Agreement",
  621 + "watchThemeSaving": "Saving",
  622 + "watchThemeSaveTheme": "Save Theme",
  623 + "watchThemeExcellent": "Excellent",
  624 + "watchThemeNormal": "Normal",
  625 + "watchThemeSlightStressful": "Watch Your Stress",
  626 + "watchThemeStressful": "Stress Overload",
  627 + "watchThemeCropImage": "Crop Watch Face Image",
  628 + "watchThemeImageProcessFailed": "Image processing failed. Please try again",
  629 + "watchThemeAbandonEdit": "Discard Changes",
  630 + "watchThemeAbandonMessage": "Your changes won't be saved if you close this page. Discard them?",
  631 + "watchThemeContinueEditing": "Continue Editing",
  632 + "watchThemeImageUploadFailed": "Image upload failed. Please try again",
  633 + "watchThemeCreateFailed": "Failed to create watch face. Please try again",
  634 + "watchThemeDeleteTheme": "Delete Theme",
  635 + "watchThemeDeleteMessage": "Deleted themes cannot be restored. Delete this theme?",
  636 + "watchThemeCancel": "Cancel",
  637 + "watchThemeDeleteFailed": "Failed to delete theme",
  638 + "watchThemeDeleted": "Theme deleted",
  639 + "watchThemeIncomplete": "Theme information is incomplete",
  640 + "watchThemeApplyFailed": "Failed to apply theme",
  641 + "watchThemeWatchSyncFailed": "Watch face sync failed",
  642 + "watchThemePurchaseChannel": "Watch Face Themes"
  643 +}
@@ -866,5 +866,66 @@ @@ -866,5 +866,66 @@
866 "noHealthDataError2Body": "DoubleFeel 需要访问 Apple Health 数据的权限,以提供压力统计、提醒和建议。如果未授权,部分功能可能无法正常使用。\n\n请放心,所有健康数据仅存储在本地,不会上传。\n\n要启用权限,请按提示操作,并在 iOS 设置中选择 允许所有 → 健康 → DoubleFeel。", 866 "noHealthDataError2Body": "DoubleFeel 需要访问 Apple Health 数据的权限,以提供压力统计、提醒和建议。如果未授权,部分功能可能无法正常使用。\n\n请放心,所有健康数据仅存储在本地,不会上传。\n\n要启用权限,请按提示操作,并在 iOS 设置中选择 允许所有 → 健康 → DoubleFeel。",
867 "noHealthDataError3Title": "错误 3:系统问题", 867 "noHealthDataError3Title": "错误 3:系统问题",
868 "noHealthDataError3Body": "根据用户反馈,我们发现 HRV 或心率数据可能缺失的两个原因:\n\n1. Apple Watch 未连接\n · 如果你的 Apple Watch 长时间未佩戴,心率数据可能无法采集。\n · 请检查 iOS 健康 App → “我的手表”,确认最近的心率数据是否在佩戴 Apple Watch 时记录。\n · 如果没有,请尝试佩戴 Apple Watch 进行数据采集,并打开 Apple 支持的心率功能。\n\n2. 过去 30 天的心率或 HRV 数据缺失\n · 打开 iOS 健康 App → 浏览 → “心率” 或 “HRV” → “未找到数据”,确认是否缺失。\n · 如果数据缺失,请重新佩戴手表,并重启 iPhone 和 Apple Watch 后,再次打开 DoubleFeel。", 868 "noHealthDataError3Body": "根据用户反馈,我们发现 HRV 或心率数据可能缺失的两个原因:\n\n1. Apple Watch 未连接\n · 如果你的 Apple Watch 长时间未佩戴,心率数据可能无法采集。\n · 请检查 iOS 健康 App → “我的手表”,确认最近的心率数据是否在佩戴 Apple Watch 时记录。\n · 如果没有,请尝试佩戴 Apple Watch 进行数据采集,并打开 Apple 支持的心率功能。\n\n2. 过去 30 天的心率或 HRV 数据缺失\n · 打开 iOS 健康 App → 浏览 → “心率” 或 “HRV” → “未找到数据”,确认是否缺失。\n · 如果数据缺失,请重新佩戴手表,并重启 iPhone 和 Apple Watch 后,再次打开 DoubleFeel。",
869 - "noHealthDataGoToSettings": "前往开启"  
870 -}  
  869 + "noHealthDataGoToSettings": "前往开启",
  870 + "watchThemeDefaultTheme": "默认主题",
  871 + "watchThemeNoWatchTitle": "未找到苹果手表",
  872 + "watchThemeNoWatchMessage": "请配对苹果手表后再尝试",
  873 + "watchThemeOk": "好的",
  874 + "watchThemeSelectFriend": "选择好友",
  875 + "watchThemeSelectAndSync": "选择并同步至表盘",
  876 + "watchThemeCustomTheme": "自定义主题",
  877 + "watchThemeCustomDescription": "用创意记录每一次情绪波动,打造懂你的专属表盘吧~",
  878 + "watchThemeCreateTheme": "创作主题",
  879 + "watchThemeOfficialTheme": "官方主题",
  880 + "watchThemeRenameStatus": "修改状态名称",
  881 + "watchThemeEnterNickname": "请输入昵称",
  882 + "watchThemeSave": "保存",
  883 + "watchThemeDialPreview": "表盘预览",
  884 + "watchThemeSwitchFriend": "切换好友",
  885 + "watchThemeStatusPreview": "状态预览",
  886 + "watchThemeAddWatchFace": "添加表盘",
  887 + "watchThemeInUse": "正在使用",
  888 + "watchThemeUseNow": "立即使用",
  889 + "watchThemeSyncIntro": "请先打开DoubleFeel手表端App,然后点击下方的“下一步”按钮",
  890 + "watchThemeSyncWaiting": "请保持打开手表App,等待同步",
  891 + "watchThemeSyncComplete": "同步完成",
  892 + "watchThemeSyncFailed": "同步失败",
  893 + "watchThemeNext": "下一步",
  894 + "watchThemeSyncingProgress": "同步中 {progress}%",
  895 + "@watchThemeSyncingProgress": {
  896 + "placeholders": {
  897 + "progress": {
  898 + "type": "int"
  899 + }
  900 + }
  901 + },
  902 + "watchThemePreview": "预览",
  903 + "watchThemeDelete": "删除",
  904 + "watchThemePageTitle": "Watch主题",
  905 + "watchThemeImagesOnly": "仅支持上传图片",
  906 + "watchThemeName": "主题名称",
  907 + "watchThemeNameMaxLength": "最多10个字符",
  908 + "watchThemeSubmissionAgreement": "我已阅读并同意用户投稿协议",
  909 + "watchThemeSaving": "保存中",
  910 + "watchThemeSaveTheme": "保存主题",
  911 + "watchThemeExcellent": "状态优秀",
  912 + "watchThemeNormal": "状态正常",
  913 + "watchThemeSlightStressful": "注意压力",
  914 + "watchThemeStressful": "压力过载",
  915 + "watchThemeCropImage": "裁剪表盘图片",
  916 + "watchThemeImageProcessFailed": "图片处理失败,请重试",
  917 + "watchThemeAbandonEdit": "放弃编辑",
  918 + "watchThemeAbandonMessage": "关闭此页面后,已编辑的内容不会保留,是否放弃编辑?",
  919 + "watchThemeContinueEditing": "继续编辑",
  920 + "watchThemeImageUploadFailed": "图片上传失败,请重试",
  921 + "watchThemeCreateFailed": "创建表盘失败,请重试",
  922 + "watchThemeDeleteTheme": "删除主题",
  923 + "watchThemeDeleteMessage": "主题删除后无法恢复,确认删除该主题吗?",
  924 + "watchThemeCancel": "取消",
  925 + "watchThemeDeleteFailed": "删除主题失败",
  926 + "watchThemeDeleted": "已删除主题",
  927 + "watchThemeIncomplete": "主题信息不完整",
  928 + "watchThemeApplyFailed": "应用主题失败",
  929 + "watchThemeWatchSyncFailed": "表盘同步失败",
  930 + "watchThemePurchaseChannel": "表盘主题"
  931 +}
@@ -3428,6 +3428,330 @@ abstract class AppLocalizations { @@ -3428,6 +3428,330 @@ abstract class AppLocalizations {
3428 /// In zh, this message translates to: 3428 /// In zh, this message translates to:
3429 /// **'前往开启'** 3429 /// **'前往开启'**
3430 String get noHealthDataGoToSettings; 3430 String get noHealthDataGoToSettings;
  3431 +
  3432 + /// No description provided for @watchThemeDefaultTheme.
  3433 + ///
  3434 + /// In zh, this message translates to:
  3435 + /// **'默认主题'**
  3436 + String get watchThemeDefaultTheme;
  3437 +
  3438 + /// No description provided for @watchThemeNoWatchTitle.
  3439 + ///
  3440 + /// In zh, this message translates to:
  3441 + /// **'未找到苹果手表'**
  3442 + String get watchThemeNoWatchTitle;
  3443 +
  3444 + /// No description provided for @watchThemeNoWatchMessage.
  3445 + ///
  3446 + /// In zh, this message translates to:
  3447 + /// **'请配对苹果手表后再尝试'**
  3448 + String get watchThemeNoWatchMessage;
  3449 +
  3450 + /// No description provided for @watchThemeOk.
  3451 + ///
  3452 + /// In zh, this message translates to:
  3453 + /// **'好的'**
  3454 + String get watchThemeOk;
  3455 +
  3456 + /// No description provided for @watchThemeSelectFriend.
  3457 + ///
  3458 + /// In zh, this message translates to:
  3459 + /// **'选择好友'**
  3460 + String get watchThemeSelectFriend;
  3461 +
  3462 + /// No description provided for @watchThemeSelectAndSync.
  3463 + ///
  3464 + /// In zh, this message translates to:
  3465 + /// **'选择并同步至表盘'**
  3466 + String get watchThemeSelectAndSync;
  3467 +
  3468 + /// No description provided for @watchThemeCustomTheme.
  3469 + ///
  3470 + /// In zh, this message translates to:
  3471 + /// **'自定义主题'**
  3472 + String get watchThemeCustomTheme;
  3473 +
  3474 + /// No description provided for @watchThemeCustomDescription.
  3475 + ///
  3476 + /// In zh, this message translates to:
  3477 + /// **'用创意记录每一次情绪波动,打造懂你的专属表盘吧~'**
  3478 + String get watchThemeCustomDescription;
  3479 +
  3480 + /// No description provided for @watchThemeCreateTheme.
  3481 + ///
  3482 + /// In zh, this message translates to:
  3483 + /// **'创作主题'**
  3484 + String get watchThemeCreateTheme;
  3485 +
  3486 + /// No description provided for @watchThemeOfficialTheme.
  3487 + ///
  3488 + /// In zh, this message translates to:
  3489 + /// **'官方主题'**
  3490 + String get watchThemeOfficialTheme;
  3491 +
  3492 + /// No description provided for @watchThemeRenameStatus.
  3493 + ///
  3494 + /// In zh, this message translates to:
  3495 + /// **'修改状态名称'**
  3496 + String get watchThemeRenameStatus;
  3497 +
  3498 + /// No description provided for @watchThemeEnterNickname.
  3499 + ///
  3500 + /// In zh, this message translates to:
  3501 + /// **'请输入昵称'**
  3502 + String get watchThemeEnterNickname;
  3503 +
  3504 + /// No description provided for @watchThemeSave.
  3505 + ///
  3506 + /// In zh, this message translates to:
  3507 + /// **'保存'**
  3508 + String get watchThemeSave;
  3509 +
  3510 + /// No description provided for @watchThemeDialPreview.
  3511 + ///
  3512 + /// In zh, this message translates to:
  3513 + /// **'表盘预览'**
  3514 + String get watchThemeDialPreview;
  3515 +
  3516 + /// No description provided for @watchThemeSwitchFriend.
  3517 + ///
  3518 + /// In zh, this message translates to:
  3519 + /// **'切换好友'**
  3520 + String get watchThemeSwitchFriend;
  3521 +
  3522 + /// No description provided for @watchThemeStatusPreview.
  3523 + ///
  3524 + /// In zh, this message translates to:
  3525 + /// **'状态预览'**
  3526 + String get watchThemeStatusPreview;
  3527 +
  3528 + /// No description provided for @watchThemeAddWatchFace.
  3529 + ///
  3530 + /// In zh, this message translates to:
  3531 + /// **'添加表盘'**
  3532 + String get watchThemeAddWatchFace;
  3533 +
  3534 + /// No description provided for @watchThemeInUse.
  3535 + ///
  3536 + /// In zh, this message translates to:
  3537 + /// **'正在使用'**
  3538 + String get watchThemeInUse;
  3539 +
  3540 + /// No description provided for @watchThemeUseNow.
  3541 + ///
  3542 + /// In zh, this message translates to:
  3543 + /// **'立即使用'**
  3544 + String get watchThemeUseNow;
  3545 +
  3546 + /// No description provided for @watchThemeSyncIntro.
  3547 + ///
  3548 + /// In zh, this message translates to:
  3549 + /// **'请先打开DoubleFeel手表端App,然后点击下方的“下一步”按钮'**
  3550 + String get watchThemeSyncIntro;
  3551 +
  3552 + /// No description provided for @watchThemeSyncWaiting.
  3553 + ///
  3554 + /// In zh, this message translates to:
  3555 + /// **'请保持打开手表App,等待同步'**
  3556 + String get watchThemeSyncWaiting;
  3557 +
  3558 + /// No description provided for @watchThemeSyncComplete.
  3559 + ///
  3560 + /// In zh, this message translates to:
  3561 + /// **'同步完成'**
  3562 + String get watchThemeSyncComplete;
  3563 +
  3564 + /// No description provided for @watchThemeSyncFailed.
  3565 + ///
  3566 + /// In zh, this message translates to:
  3567 + /// **'同步失败'**
  3568 + String get watchThemeSyncFailed;
  3569 +
  3570 + /// No description provided for @watchThemeNext.
  3571 + ///
  3572 + /// In zh, this message translates to:
  3573 + /// **'下一步'**
  3574 + String get watchThemeNext;
  3575 +
  3576 + /// No description provided for @watchThemeSyncingProgress.
  3577 + ///
  3578 + /// In zh, this message translates to:
  3579 + /// **'同步中 {progress}%'**
  3580 + String watchThemeSyncingProgress(int progress);
  3581 +
  3582 + /// No description provided for @watchThemePreview.
  3583 + ///
  3584 + /// In zh, this message translates to:
  3585 + /// **'预览'**
  3586 + String get watchThemePreview;
  3587 +
  3588 + /// No description provided for @watchThemeDelete.
  3589 + ///
  3590 + /// In zh, this message translates to:
  3591 + /// **'删除'**
  3592 + String get watchThemeDelete;
  3593 +
  3594 + /// No description provided for @watchThemePageTitle.
  3595 + ///
  3596 + /// In zh, this message translates to:
  3597 + /// **'Watch主题'**
  3598 + String get watchThemePageTitle;
  3599 +
  3600 + /// No description provided for @watchThemeImagesOnly.
  3601 + ///
  3602 + /// In zh, this message translates to:
  3603 + /// **'仅支持上传图片'**
  3604 + String get watchThemeImagesOnly;
  3605 +
  3606 + /// No description provided for @watchThemeName.
  3607 + ///
  3608 + /// In zh, this message translates to:
  3609 + /// **'主题名称'**
  3610 + String get watchThemeName;
  3611 +
  3612 + /// No description provided for @watchThemeNameMaxLength.
  3613 + ///
  3614 + /// In zh, this message translates to:
  3615 + /// **'最多10个字符'**
  3616 + String get watchThemeNameMaxLength;
  3617 +
  3618 + /// No description provided for @watchThemeSubmissionAgreement.
  3619 + ///
  3620 + /// In zh, this message translates to:
  3621 + /// **'我已阅读并同意用户投稿协议'**
  3622 + String get watchThemeSubmissionAgreement;
  3623 +
  3624 + /// No description provided for @watchThemeSaving.
  3625 + ///
  3626 + /// In zh, this message translates to:
  3627 + /// **'保存中'**
  3628 + String get watchThemeSaving;
  3629 +
  3630 + /// No description provided for @watchThemeSaveTheme.
  3631 + ///
  3632 + /// In zh, this message translates to:
  3633 + /// **'保存主题'**
  3634 + String get watchThemeSaveTheme;
  3635 +
  3636 + /// No description provided for @watchThemeExcellent.
  3637 + ///
  3638 + /// In zh, this message translates to:
  3639 + /// **'状态优秀'**
  3640 + String get watchThemeExcellent;
  3641 +
  3642 + /// No description provided for @watchThemeNormal.
  3643 + ///
  3644 + /// In zh, this message translates to:
  3645 + /// **'状态正常'**
  3646 + String get watchThemeNormal;
  3647 +
  3648 + /// No description provided for @watchThemeSlightStressful.
  3649 + ///
  3650 + /// In zh, this message translates to:
  3651 + /// **'注意压力'**
  3652 + String get watchThemeSlightStressful;
  3653 +
  3654 + /// No description provided for @watchThemeStressful.
  3655 + ///
  3656 + /// In zh, this message translates to:
  3657 + /// **'压力过载'**
  3658 + String get watchThemeStressful;
  3659 +
  3660 + /// No description provided for @watchThemeCropImage.
  3661 + ///
  3662 + /// In zh, this message translates to:
  3663 + /// **'裁剪表盘图片'**
  3664 + String get watchThemeCropImage;
  3665 +
  3666 + /// No description provided for @watchThemeImageProcessFailed.
  3667 + ///
  3668 + /// In zh, this message translates to:
  3669 + /// **'图片处理失败,请重试'**
  3670 + String get watchThemeImageProcessFailed;
  3671 +
  3672 + /// No description provided for @watchThemeAbandonEdit.
  3673 + ///
  3674 + /// In zh, this message translates to:
  3675 + /// **'放弃编辑'**
  3676 + String get watchThemeAbandonEdit;
  3677 +
  3678 + /// No description provided for @watchThemeAbandonMessage.
  3679 + ///
  3680 + /// In zh, this message translates to:
  3681 + /// **'关闭此页面后,已编辑的内容不会保留,是否放弃编辑?'**
  3682 + String get watchThemeAbandonMessage;
  3683 +
  3684 + /// No description provided for @watchThemeContinueEditing.
  3685 + ///
  3686 + /// In zh, this message translates to:
  3687 + /// **'继续编辑'**
  3688 + String get watchThemeContinueEditing;
  3689 +
  3690 + /// No description provided for @watchThemeImageUploadFailed.
  3691 + ///
  3692 + /// In zh, this message translates to:
  3693 + /// **'图片上传失败,请重试'**
  3694 + String get watchThemeImageUploadFailed;
  3695 +
  3696 + /// No description provided for @watchThemeCreateFailed.
  3697 + ///
  3698 + /// In zh, this message translates to:
  3699 + /// **'创建表盘失败,请重试'**
  3700 + String get watchThemeCreateFailed;
  3701 +
  3702 + /// No description provided for @watchThemeDeleteTheme.
  3703 + ///
  3704 + /// In zh, this message translates to:
  3705 + /// **'删除主题'**
  3706 + String get watchThemeDeleteTheme;
  3707 +
  3708 + /// No description provided for @watchThemeDeleteMessage.
  3709 + ///
  3710 + /// In zh, this message translates to:
  3711 + /// **'主题删除后无法恢复,确认删除该主题吗?'**
  3712 + String get watchThemeDeleteMessage;
  3713 +
  3714 + /// No description provided for @watchThemeCancel.
  3715 + ///
  3716 + /// In zh, this message translates to:
  3717 + /// **'取消'**
  3718 + String get watchThemeCancel;
  3719 +
  3720 + /// No description provided for @watchThemeDeleteFailed.
  3721 + ///
  3722 + /// In zh, this message translates to:
  3723 + /// **'删除主题失败'**
  3724 + String get watchThemeDeleteFailed;
  3725 +
  3726 + /// No description provided for @watchThemeDeleted.
  3727 + ///
  3728 + /// In zh, this message translates to:
  3729 + /// **'已删除主题'**
  3730 + String get watchThemeDeleted;
  3731 +
  3732 + /// No description provided for @watchThemeIncomplete.
  3733 + ///
  3734 + /// In zh, this message translates to:
  3735 + /// **'主题信息不完整'**
  3736 + String get watchThemeIncomplete;
  3737 +
  3738 + /// No description provided for @watchThemeApplyFailed.
  3739 + ///
  3740 + /// In zh, this message translates to:
  3741 + /// **'应用主题失败'**
  3742 + String get watchThemeApplyFailed;
  3743 +
  3744 + /// No description provided for @watchThemeWatchSyncFailed.
  3745 + ///
  3746 + /// In zh, this message translates to:
  3747 + /// **'表盘同步失败'**
  3748 + String get watchThemeWatchSyncFailed;
  3749 +
  3750 + /// No description provided for @watchThemePurchaseChannel.
  3751 + ///
  3752 + /// In zh, this message translates to:
  3753 + /// **'表盘主题'**
  3754 + String get watchThemePurchaseChannel;
3431 } 3755 }
3432 3756
3433 class _AppLocalizationsDelegate 3757 class _AppLocalizationsDelegate
@@ -1913,4 +1913,176 @@ class AppLocalizationsEn extends AppLocalizations { @@ -1913,4 +1913,176 @@ class AppLocalizationsEn extends AppLocalizations {
1913 1913
1914 @override 1914 @override
1915 String get noHealthDataGoToSettings => 'Go to Settings'; 1915 String get noHealthDataGoToSettings => 'Go to Settings';
  1916 +
  1917 + @override
  1918 + String get watchThemeDefaultTheme => 'Default Theme';
  1919 +
  1920 + @override
  1921 + String get watchThemeNoWatchTitle => 'Apple Watch Not Found';
  1922 +
  1923 + @override
  1924 + String get watchThemeNoWatchMessage => 'Pair an Apple Watch and try again';
  1925 +
  1926 + @override
  1927 + String get watchThemeOk => 'OK';
  1928 +
  1929 + @override
  1930 + String get watchThemeSelectFriend => 'Select Friend';
  1931 +
  1932 + @override
  1933 + String get watchThemeSelectAndSync => 'Select and Sync to Watch Face';
  1934 +
  1935 + @override
  1936 + String get watchThemeCustomTheme => 'Custom Themes';
  1937 +
  1938 + @override
  1939 + String get watchThemeCustomDescription =>
  1940 + 'Capture every mood with your creativity and make a watch face that\'s uniquely yours.';
  1941 +
  1942 + @override
  1943 + String get watchThemeCreateTheme => 'Create Theme';
  1944 +
  1945 + @override
  1946 + String get watchThemeOfficialTheme => 'Official Themes';
  1947 +
  1948 + @override
  1949 + String get watchThemeRenameStatus => 'Rename Status';
  1950 +
  1951 + @override
  1952 + String get watchThemeEnterNickname => 'Enter a name';
  1953 +
  1954 + @override
  1955 + String get watchThemeSave => 'Save';
  1956 +
  1957 + @override
  1958 + String get watchThemeDialPreview => 'Watch Face Preview';
  1959 +
  1960 + @override
  1961 + String get watchThemeSwitchFriend => 'Switch Friend';
  1962 +
  1963 + @override
  1964 + String get watchThemeStatusPreview => 'Status Preview';
  1965 +
  1966 + @override
  1967 + String get watchThemeAddWatchFace => 'Add Watch Face';
  1968 +
  1969 + @override
  1970 + String get watchThemeInUse => 'In Use';
  1971 +
  1972 + @override
  1973 + String get watchThemeUseNow => 'Use Now';
  1974 +
  1975 + @override
  1976 + String get watchThemeSyncIntro =>
  1977 + 'Open the DoubleFeel app on your Apple Watch, then tap Next below.';
  1978 +
  1979 + @override
  1980 + String get watchThemeSyncWaiting => 'Keep the Watch app open while syncing';
  1981 +
  1982 + @override
  1983 + String get watchThemeSyncComplete => 'Sync Complete';
  1984 +
  1985 + @override
  1986 + String get watchThemeSyncFailed => 'Sync Failed';
  1987 +
  1988 + @override
  1989 + String get watchThemeNext => 'Next';
  1990 +
  1991 + @override
  1992 + String watchThemeSyncingProgress(int progress) {
  1993 + return 'Syncing $progress%';
  1994 + }
  1995 +
  1996 + @override
  1997 + String get watchThemePreview => 'Preview';
  1998 +
  1999 + @override
  2000 + String get watchThemeDelete => 'Delete';
  2001 +
  2002 + @override
  2003 + String get watchThemePageTitle => 'Watch Themes';
  2004 +
  2005 + @override
  2006 + String get watchThemeImagesOnly => 'Images only';
  2007 +
  2008 + @override
  2009 + String get watchThemeName => 'Theme Name';
  2010 +
  2011 + @override
  2012 + String get watchThemeNameMaxLength => 'Up to 10 characters';
  2013 +
  2014 + @override
  2015 + String get watchThemeSubmissionAgreement =>
  2016 + 'I have read and agree to the User Submission Agreement';
  2017 +
  2018 + @override
  2019 + String get watchThemeSaving => 'Saving';
  2020 +
  2021 + @override
  2022 + String get watchThemeSaveTheme => 'Save Theme';
  2023 +
  2024 + @override
  2025 + String get watchThemeExcellent => 'Excellent';
  2026 +
  2027 + @override
  2028 + String get watchThemeNormal => 'Normal';
  2029 +
  2030 + @override
  2031 + String get watchThemeSlightStressful => 'Watch Your Stress';
  2032 +
  2033 + @override
  2034 + String get watchThemeStressful => 'Stress Overload';
  2035 +
  2036 + @override
  2037 + String get watchThemeCropImage => 'Crop Watch Face Image';
  2038 +
  2039 + @override
  2040 + String get watchThemeImageProcessFailed =>
  2041 + 'Image processing failed. Please try again';
  2042 +
  2043 + @override
  2044 + String get watchThemeAbandonEdit => 'Discard Changes';
  2045 +
  2046 + @override
  2047 + String get watchThemeAbandonMessage =>
  2048 + 'Your changes won\'t be saved if you close this page. Discard them?';
  2049 +
  2050 + @override
  2051 + String get watchThemeContinueEditing => 'Continue Editing';
  2052 +
  2053 + @override
  2054 + String get watchThemeImageUploadFailed =>
  2055 + 'Image upload failed. Please try again';
  2056 +
  2057 + @override
  2058 + String get watchThemeCreateFailed =>
  2059 + 'Failed to create watch face. Please try again';
  2060 +
  2061 + @override
  2062 + String get watchThemeDeleteTheme => 'Delete Theme';
  2063 +
  2064 + @override
  2065 + String get watchThemeDeleteMessage =>
  2066 + 'Deleted themes cannot be restored. Delete this theme?';
  2067 +
  2068 + @override
  2069 + String get watchThemeCancel => 'Cancel';
  2070 +
  2071 + @override
  2072 + String get watchThemeDeleteFailed => 'Failed to delete theme';
  2073 +
  2074 + @override
  2075 + String get watchThemeDeleted => 'Theme deleted';
  2076 +
  2077 + @override
  2078 + String get watchThemeIncomplete => 'Theme information is incomplete';
  2079 +
  2080 + @override
  2081 + String get watchThemeApplyFailed => 'Failed to apply theme';
  2082 +
  2083 + @override
  2084 + String get watchThemeWatchSyncFailed => 'Watch face sync failed';
  2085 +
  2086 + @override
  2087 + String get watchThemePurchaseChannel => 'Watch Face Themes';
1916 } 2088 }
@@ -1812,4 +1812,168 @@ class AppLocalizationsZh extends AppLocalizations { @@ -1812,4 +1812,168 @@ class AppLocalizationsZh extends AppLocalizations {
1812 1812
1813 @override 1813 @override
1814 String get noHealthDataGoToSettings => '前往开启'; 1814 String get noHealthDataGoToSettings => '前往开启';
  1815 +
  1816 + @override
  1817 + String get watchThemeDefaultTheme => '默认主题';
  1818 +
  1819 + @override
  1820 + String get watchThemeNoWatchTitle => '未找到苹果手表';
  1821 +
  1822 + @override
  1823 + String get watchThemeNoWatchMessage => '请配对苹果手表后再尝试';
  1824 +
  1825 + @override
  1826 + String get watchThemeOk => '好的';
  1827 +
  1828 + @override
  1829 + String get watchThemeSelectFriend => '选择好友';
  1830 +
  1831 + @override
  1832 + String get watchThemeSelectAndSync => '选择并同步至表盘';
  1833 +
  1834 + @override
  1835 + String get watchThemeCustomTheme => '自定义主题';
  1836 +
  1837 + @override
  1838 + String get watchThemeCustomDescription => '用创意记录每一次情绪波动,打造懂你的专属表盘吧~';
  1839 +
  1840 + @override
  1841 + String get watchThemeCreateTheme => '创作主题';
  1842 +
  1843 + @override
  1844 + String get watchThemeOfficialTheme => '官方主题';
  1845 +
  1846 + @override
  1847 + String get watchThemeRenameStatus => '修改状态名称';
  1848 +
  1849 + @override
  1850 + String get watchThemeEnterNickname => '请输入昵称';
  1851 +
  1852 + @override
  1853 + String get watchThemeSave => '保存';
  1854 +
  1855 + @override
  1856 + String get watchThemeDialPreview => '表盘预览';
  1857 +
  1858 + @override
  1859 + String get watchThemeSwitchFriend => '切换好友';
  1860 +
  1861 + @override
  1862 + String get watchThemeStatusPreview => '状态预览';
  1863 +
  1864 + @override
  1865 + String get watchThemeAddWatchFace => '添加表盘';
  1866 +
  1867 + @override
  1868 + String get watchThemeInUse => '正在使用';
  1869 +
  1870 + @override
  1871 + String get watchThemeUseNow => '立即使用';
  1872 +
  1873 + @override
  1874 + String get watchThemeSyncIntro => '请先打开DoubleFeel手表端App,然后点击下方的“下一步”按钮';
  1875 +
  1876 + @override
  1877 + String get watchThemeSyncWaiting => '请保持打开手表App,等待同步';
  1878 +
  1879 + @override
  1880 + String get watchThemeSyncComplete => '同步完成';
  1881 +
  1882 + @override
  1883 + String get watchThemeSyncFailed => '同步失败';
  1884 +
  1885 + @override
  1886 + String get watchThemeNext => '下一步';
  1887 +
  1888 + @override
  1889 + String watchThemeSyncingProgress(int progress) {
  1890 + return '同步中 $progress%';
  1891 + }
  1892 +
  1893 + @override
  1894 + String get watchThemePreview => '预览';
  1895 +
  1896 + @override
  1897 + String get watchThemeDelete => '删除';
  1898 +
  1899 + @override
  1900 + String get watchThemePageTitle => 'Watch主题';
  1901 +
  1902 + @override
  1903 + String get watchThemeImagesOnly => '仅支持上传图片';
  1904 +
  1905 + @override
  1906 + String get watchThemeName => '主题名称';
  1907 +
  1908 + @override
  1909 + String get watchThemeNameMaxLength => '最多10个字符';
  1910 +
  1911 + @override
  1912 + String get watchThemeSubmissionAgreement => '我已阅读并同意用户投稿协议';
  1913 +
  1914 + @override
  1915 + String get watchThemeSaving => '保存中';
  1916 +
  1917 + @override
  1918 + String get watchThemeSaveTheme => '保存主题';
  1919 +
  1920 + @override
  1921 + String get watchThemeExcellent => '状态优秀';
  1922 +
  1923 + @override
  1924 + String get watchThemeNormal => '状态正常';
  1925 +
  1926 + @override
  1927 + String get watchThemeSlightStressful => '注意压力';
  1928 +
  1929 + @override
  1930 + String get watchThemeStressful => '压力过载';
  1931 +
  1932 + @override
  1933 + String get watchThemeCropImage => '裁剪表盘图片';
  1934 +
  1935 + @override
  1936 + String get watchThemeImageProcessFailed => '图片处理失败,请重试';
  1937 +
  1938 + @override
  1939 + String get watchThemeAbandonEdit => '放弃编辑';
  1940 +
  1941 + @override
  1942 + String get watchThemeAbandonMessage => '关闭此页面后,已编辑的内容不会保留,是否放弃编辑?';
  1943 +
  1944 + @override
  1945 + String get watchThemeContinueEditing => '继续编辑';
  1946 +
  1947 + @override
  1948 + String get watchThemeImageUploadFailed => '图片上传失败,请重试';
  1949 +
  1950 + @override
  1951 + String get watchThemeCreateFailed => '创建表盘失败,请重试';
  1952 +
  1953 + @override
  1954 + String get watchThemeDeleteTheme => '删除主题';
  1955 +
  1956 + @override
  1957 + String get watchThemeDeleteMessage => '主题删除后无法恢复,确认删除该主题吗?';
  1958 +
  1959 + @override
  1960 + String get watchThemeCancel => '取消';
  1961 +
  1962 + @override
  1963 + String get watchThemeDeleteFailed => '删除主题失败';
  1964 +
  1965 + @override
  1966 + String get watchThemeDeleted => '已删除主题';
  1967 +
  1968 + @override
  1969 + String get watchThemeIncomplete => '主题信息不完整';
  1970 +
  1971 + @override
  1972 + String get watchThemeApplyFailed => '应用主题失败';
  1973 +
  1974 + @override
  1975 + String get watchThemeWatchSyncFailed => '表盘同步失败';
  1976 +
  1977 + @override
  1978 + String get watchThemePurchaseChannel => '表盘主题';
1815 } 1979 }