diff --git a/lib/common/models/yt_video_model.freezed.dart b/lib/common/models/yt_video_model.freezed.dart index 90a6458e..23678323 100644 --- a/lib/common/models/yt_video_model.freezed.dart +++ b/lib/common/models/yt_video_model.freezed.dart @@ -696,6 +696,7 @@ YTThumbnails _$YTThumbnailsFromJson(Map json) { /// @nodoc mixin _$YTThumbnails { +// ignore: invalid_annotation_target @JsonKey(name: 'default') YTThumbnail? get defaults => throw _privateConstructorUsedError; YTThumbnail? get medium => throw _privateConstructorUsedError; @@ -855,6 +856,7 @@ class _$YTThumbnailsImpl implements _YTThumbnails { factory _$YTThumbnailsImpl.fromJson(Map json) => _$$YTThumbnailsImplFromJson(json); +// ignore: invalid_annotation_target @override @JsonKey(name: 'default') final YTThumbnail? defaults; @@ -906,7 +908,7 @@ abstract class _YTThumbnails implements YTThumbnails { factory _YTThumbnails.fromJson(Map json) = _$YTThumbnailsImpl.fromJson; - @override + @override // ignore: invalid_annotation_target @JsonKey(name: 'default') YTThumbnail? get defaults; @override diff --git a/lib/common/utils/dialog_util.dart b/lib/common/utils/dialog_util.dart index da703a7a..c54837f7 100644 --- a/lib/common/utils/dialog_util.dart +++ b/lib/common/utils/dialog_util.dart @@ -39,21 +39,20 @@ class DialogUtil { builder: (BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; - final androidPermissionTexts = - t.dialogs.licenseDialog.androidPermissions - .mapIndexed( - (index, permissionText) => Text( - '${index + 1}. $permissionText', - style: TextStyle( - color: isDark ? Colors.white : primaryTextColor, - fontSize: 14, - fontWeight: FontWeight.w400, - ), - ).nestedPadding(padding: const EdgeInsets.only(top: 4)), - ) - .toList(); + final androidPermissionTexts = t.dialogs.license.androidPermissions + .mapIndexed( + (index, permissionText) => Text( + '${index + 1}. $permissionText', + style: TextStyle( + color: isDark ? Colors.white : primaryTextColor, + fontSize: 14, + fontWeight: FontWeight.w400, + ), + ).nestedPadding(padding: const EdgeInsets.only(top: 4)), + ) + .toList(); - final iosPermissionTexts = t.dialogs.licenseDialog.iosPermissions + final iosPermissionTexts = t.dialogs.license.iosPermissions .mapIndexed( (index, permissionText) => Text( '${index + 1}. $permissionText', @@ -68,7 +67,7 @@ class DialogUtil { return AlertDialog( title: Text( - t.dialogs.licenseDialog.licenseDialogTitle, + t.dialogs.license.title, style: TextStyle( color: isDark ? Colors.white : primaryTextColor, fontSize: 18, @@ -80,7 +79,7 @@ class DialogUtil { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - t.dialogs.licenseDialog.licenseDialogContentContent, + t.dialogs.license.contentContent, style: TextStyle( color: isDark ? Colors.white : primaryTextColor, fontSize: 14, @@ -88,7 +87,7 @@ class DialogUtil { ), ), Text( - t.dialogs.licenseDialog.licenseDialogContentTip, + t.dialogs.license.contentTip, style: TextStyle( color: isDark ? Colors.white : primaryTextColor, fontSize: 14, @@ -101,8 +100,7 @@ class DialogUtil { text: TextSpan( children: [ TextSpan( - text: - t.dialogs.licenseDialog.licenseDialogContentPrefix, + text: t.dialogs.license.contentPrefix, style: TextStyle( color: isDark ? Colors.white : primaryTextColor, fontSize: 14, @@ -110,8 +108,7 @@ class DialogUtil { ), ), TextSpan( - text: t.dialogs.licenseDialog - .licenseDialogContentUserAgreement, + text: t.dialogs.license.contentUserAgreement, recognizer: TapGestureRecognizer() ..onTap = () async { final uri = Uri.parse( @@ -128,7 +125,7 @@ class DialogUtil { ), ), TextSpan( - text: t.dialogs.licenseDialog.licenseDialogContentAnd, + text: t.dialogs.license.contentAnd, style: TextStyle( color: isDark ? Colors.white : primaryTextColor, fontSize: 14, @@ -136,8 +133,7 @@ class DialogUtil { ), ), TextSpan( - text: t.dialogs.licenseDialog - .licenseDialogContentPrivacyAgreement, + text: t.dialogs.license.contentPrivacyAgreement, recognizer: TapGestureRecognizer() ..onTap = () async { final uri = Uri.parse( @@ -154,8 +150,7 @@ class DialogUtil { ), ), TextSpan( - text: - t.dialogs.licenseDialog.licenseDialogContentSuffix, + text: t.dialogs.license.contentSuffix, style: TextStyle( color: isDark ? Colors.white : primaryTextColor, fontSize: 14, diff --git a/lib/common/widgets/bottom_sheet.dart b/lib/common/widgets/bottom_sheet.dart index df9481a8..88e28a0b 100644 --- a/lib/common/widgets/bottom_sheet.dart +++ b/lib/common/widgets/bottom_sheet.dart @@ -93,6 +93,7 @@ class ModalBottomSheet extends StatelessWidget { style: TextStyle( fontSize: 18, color: isDark ? Colors.white : primaryTextColor, + fontWeight: FontWeight.w400, ), textAlign: TextAlign.center, maxLines: 1, @@ -123,6 +124,7 @@ class ModalBottomSheet extends StatelessWidget { style: TextStyle( fontSize: 18, color: isDark ? Colors.white : primaryTextColor, + fontWeight: FontWeight.w400, ), textAlign: TextAlign.center, maxLines: 1, diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index a21b86b4..627b6bb8 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 2 -/// Strings: 48 (24 per locale) +/// Strings: 256 (128 per locale) /// -/// Built on 2024-04-27 at 04:05 UTC +/// Built on 2024-05-23 at 12:41 UTC // coverage:ignore-file // ignore_for_file: type=lint @@ -149,8 +149,10 @@ class Translations implements BaseTranslations { // Translations String get appName => 'Homing Pigeon'; + late final _StringsCommonEn common = _StringsCommonEn._(_root); late final _StringsPagesEn pages = _StringsPagesEn._(_root); late final _StringsButtonsEn buttons = _StringsButtonsEn._(_root); + late final _StringsBottomSheetsEn bottomSheets = _StringsBottomSheetsEn._(_root); late final _StringsDialogsEn dialogs = _StringsDialogsEn._(_root); Map get locales => { 'en': 'English', @@ -158,6 +160,19 @@ class Translations implements BaseTranslations { }; } +// Path: common +class _StringsCommonEn { + _StringsCommonEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get copied => 'Copied'; + String get success => 'Succeeded😊'; + String get failure => 'Failed😭'; + String get noData => 'No data, click to reload😭'; +} + // Path: pages class _StringsPagesEn { _StringsPagesEn._(this._root); @@ -165,7 +180,14 @@ class _StringsPagesEn { final Translations _root; // ignore: unused_field // Translations - late final _StringsPagesHomePageEn homePage = _StringsPagesHomePageEn._(_root); + late final _StringsPagesHomeEn home = _StringsPagesHomeEn._(_root); + late final _StringsPagesEmojiEn emoji = _StringsPagesEmojiEn._(_root); + late final _StringsPagesFeedbackEn feedback = _StringsPagesFeedbackEn._(_root); + late final _StringsPagesFeedbackDetailEn feedbackDetail = _StringsPagesFeedbackDetailEn._(_root); + late final _StringsPagesLiveEn live = _StringsPagesLiveEn._(_root); + late final _StringsPagesMovieEn movie = _StringsPagesMovieEn._(_root); + late final _StringsPagesRoadmapEn roadmap = _StringsPagesRoadmapEn._(_root); + late final _StringsPagesSocialEn social = _StringsPagesSocialEn._(_root); } // Path: buttons @@ -177,6 +199,24 @@ class _StringsButtonsEn { // Translations String get agree => 'Agree'; String get cancel => 'Cancel'; + String get login => 'Login'; + String get signup => 'Sign up'; + String get logout => 'Logout'; + String get ignore => 'Ignore'; + String get turnOn => 'Turn on'; + String get turnOff => 'Turn off'; +} + +// Path: bottomSheets +class _StringsBottomSheetsEn { + _StringsBottomSheetsEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + late final _StringsBottomSheetsLoginEn login = _StringsBottomSheetsLoginEn._(_root); + late final _StringsBottomSheetsSignupEn signup = _StringsBottomSheetsSignupEn._(_root); + late final _StringsBottomSheetsStoreEn store = _StringsBottomSheetsStoreEn._(_root); } // Path: dialogs @@ -186,34 +226,147 @@ class _StringsDialogsEn { final Translations _root; // ignore: unused_field // Translations - late final _StringsDialogsLicenseDialogEn licenseDialog = _StringsDialogsLicenseDialogEn._(_root); + late final _StringsDialogsLicenseEn license = _StringsDialogsLicenseEn._(_root); + late final _StringsDialogsAlbumEn album = _StringsDialogsAlbumEn._(_root); +} + +// Path: pages.home +class _StringsPagesHomeEn { + _StringsPagesHomeEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + late final _StringsPagesHomePrimaryEn primary = _StringsPagesHomePrimaryEn._(_root); + late final _StringsPagesHomeOtherEn other = _StringsPagesHomeOtherEn._(_root); + String get version => 'Version'; +} + +// Path: pages.emoji +class _StringsPagesEmojiEn { + _StringsPagesEmojiEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Emojis~'; + late final _StringsPagesEmojiTipsEn tips = _StringsPagesEmojiTipsEn._(_root); + late final _StringsPagesEmojiDialogsEn dialogs = _StringsPagesEmojiDialogsEn._(_root); +} + +// Path: pages.feedback +class _StringsPagesFeedbackEn { + _StringsPagesFeedbackEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Feedback'; + late final _StringsPagesFeedbackTipsEn tips = _StringsPagesFeedbackTipsEn._(_root); + late final _StringsPagesFeedbackDialogsEn dialogs = _StringsPagesFeedbackDialogsEn._(_root); +} + +// Path: pages.feedbackDetail +class _StringsPagesFeedbackDetailEn { + _StringsPagesFeedbackDetailEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Feedback details'; +} + +// Path: pages.live +class _StringsPagesLiveEn { + _StringsPagesLiveEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Live streaming~'; +} + +// Path: pages.movie +class _StringsPagesMovieEn { + _StringsPagesMovieEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Movie'; +} + +// Path: pages.roadmap +class _StringsPagesRoadmapEn { + _StringsPagesRoadmapEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Roadmap'; +} + +// Path: pages.social +class _StringsPagesSocialEn { + _StringsPagesSocialEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Social'; +} + +// Path: bottomSheets.login +class _StringsBottomSheetsLoginEn { + _StringsBottomSheetsLoginEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get header => 'Please fill in your login information'; + late final _StringsBottomSheetsLoginFormEn form = _StringsBottomSheetsLoginFormEn._(_root); + late final _StringsBottomSheetsLoginTipsEn tips = _StringsBottomSheetsLoginTipsEn._(_root); +} + +// Path: bottomSheets.signup +class _StringsBottomSheetsSignupEn { + _StringsBottomSheetsSignupEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get header => 'Please fill in the registration information'; + late final _StringsBottomSheetsSignupFormEn form = _StringsBottomSheetsSignupFormEn._(_root); + late final _StringsBottomSheetsSignupTipsEn tips = _StringsBottomSheetsSignupTipsEn._(_root); } -// Path: pages.homePage -class _StringsPagesHomePageEn { - _StringsPagesHomePageEn._(this._root); +// Path: bottomSheets.store +class _StringsBottomSheetsStoreEn { + _StringsBottomSheetsStoreEn._(this._root); final Translations _root; // ignore: unused_field // Translations - String get title => 'Homing Pigeon'; + String get title => 'Please select to continue'; + late final _StringsBottomSheetsStoreCodeEn code = _StringsBottomSheetsStoreCodeEn._(_root); + late final _StringsBottomSheetsStoreLinkEn link = _StringsBottomSheetsStoreLinkEn._(_root); } -// Path: dialogs.licenseDialog -class _StringsDialogsLicenseDialogEn { - _StringsDialogsLicenseDialogEn._(this._root); +// Path: dialogs.license +class _StringsDialogsLicenseEn { + _StringsDialogsLicenseEn._(this._root); final Translations _root; // ignore: unused_field // Translations - String get licenseDialogTitle => 'Terms and Conditions'; - String get licenseDialogContentContent => 'Protecting user\'s privacy and personal information is a fundamental principle of Homing Pigeon.'; - String get licenseDialogContentTip => 'Below is a list of permissions required by this APP:'; - String get licenseDialogContentPrefix => 'Before you use this APP\'s services, please carefully read and agree to the '; - String get licenseDialogContentUserAgreement => 'User Agreement'; - String get licenseDialogContentAnd => ' and '; - String get licenseDialogContentPrivacyAgreement => 'Privacy Agreement'; - String get licenseDialogContentSuffix => ', start using our services after you agree and accept all terms.'; + String get title => 'Terms and Conditions'; + String get contentContent => 'Protecting user\'s privacy and personal information is a fundamental principle of Homing Pigeon.'; + String get contentTip => 'Below is a list of permissions required by this APP:'; + String get contentPrefix => 'Before you use this APP\'s services, please carefully read and agree to the '; + String get contentUserAgreement => 'User Agreement'; + String get contentAnd => ' and '; + String get contentPrivacyAgreement => 'Privacy Agreement'; + String get contentSuffix => ', start using our services after you agree and accept all terms.'; List get iosPermissions => [ 'For you to take pictures, Homing Pigeon needs access to your Camera. (NSCameraUsageDescription)', 'For you to upload pictures, Homing Pigeon needs access to your Photos. (NSPhotoLibraryUsageDescription)', @@ -230,110 +383,1225 @@ class _StringsDialogsLicenseDialogEn { ]; } -// Path: -class _StringsZh implements Translations { - /// You can call this constructor and build your own translation instance of this locale. - /// Constructing via the enum [AppLocale.build] is preferred. - _StringsZh.build({Map? overrides, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) - : assert(overrides == null, 'Set "translation_overrides: true" in order to enable this feature.'), - $meta = TranslationMetadata( - locale: AppLocale.zh, - overrides: overrides ?? {}, - cardinalResolver: cardinalResolver, - ordinalResolver: ordinalResolver, - ) { - $meta.setFlatMapFunction(_flatMapFunction); - } +// Path: dialogs.album +class _StringsDialogsAlbumEn { + _StringsDialogsAlbumEn._(this._root); - /// Metadata for the translations of . - @override final TranslationMetadata $meta; + final Translations _root; // ignore: unused_field - /// Access flat map - @override dynamic operator[](String key) => $meta.getTranslation(key); + // Translations + String get title => 'Allow access to your album'; + String get description => 'Please go to your phone Settings to grant Homing Pigeon the permission to visit your album.'; +} - @override late final _StringsZh _root = this; // ignore: unused_field +// Path: pages.home.primary +class _StringsPagesHomePrimaryEn { + _StringsPagesHomePrimaryEn._(this._root); + + final Translations _root; // ignore: unused_field // Translations - @override String get appName => '信鸽'; - @override late final _StringsPagesZh pages = _StringsPagesZh._(_root); - @override late final _StringsButtonsZh buttons = _StringsButtonsZh._(_root); - @override late final _StringsDialogsZh dialogs = _StringsDialogsZh._(_root); - @override Map get locales => { - 'en': 'English', - 'zh': '中文', - }; + String get title => 'Primary'; + late final _StringsPagesHomePrimaryRatingEn rating = _StringsPagesHomePrimaryRatingEn._(_root); + late final _StringsPagesHomePrimaryLiveEn live = _StringsPagesHomePrimaryLiveEn._(_root); + late final _StringsPagesHomePrimarySettingsEn settings = _StringsPagesHomePrimarySettingsEn._(_root); } -// Path: pages -class _StringsPagesZh implements _StringsPagesEn { - _StringsPagesZh._(this._root); +// Path: pages.home.other +class _StringsPagesHomeOtherEn { + _StringsPagesHomeOtherEn._(this._root); - @override final _StringsZh _root; // ignore: unused_field + final Translations _root; // ignore: unused_field // Translations - @override late final _StringsPagesHomePageZh homePage = _StringsPagesHomePageZh._(_root); + String get title => 'Others'; + late final _StringsPagesHomeOtherNotificationsEn notifications = _StringsPagesHomeOtherNotificationsEn._(_root); + late final _StringsPagesHomeOtherStoreEn store = _StringsPagesHomeOtherStoreEn._(_root); + late final _StringsPagesHomeOtherEmojiEn emoji = _StringsPagesHomeOtherEmojiEn._(_root); + late final _StringsPagesHomeOtherFeedbackEn feedback = _StringsPagesHomeOtherFeedbackEn._(_root); + late final _StringsPagesHomeOtherRoadmapEn roadmap = _StringsPagesHomeOtherRoadmapEn._(_root); } -// Path: buttons -class _StringsButtonsZh implements _StringsButtonsEn { - _StringsButtonsZh._(this._root); +// Path: pages.emoji.tips +class _StringsPagesEmojiTipsEn { + _StringsPagesEmojiTipsEn._(this._root); - @override final _StringsZh _root; // ignore: unused_field + final Translations _root; // ignore: unused_field // Translations - @override String get agree => '同意'; - @override String get cancel => '再想想'; + String get title => 'Contributions are welcome, Wow~'; + String get prefix => 'Welcome'; + String get button => ' [click here] '; + String get suffix => 'to contribute, it can be emoticons, creative copywriting, or some embarrassing pictures or screenshots of cats, etc.😄'; } -// Path: dialogs -class _StringsDialogsZh implements _StringsDialogsEn { - _StringsDialogsZh._(this._root); +// Path: pages.emoji.dialogs +class _StringsPagesEmojiDialogsEn { + _StringsPagesEmojiDialogsEn._(this._root); - @override final _StringsZh _root; // ignore: unused_field + final Translations _root; // ignore: unused_field // Translations - @override late final _StringsDialogsLicenseDialogZh licenseDialog = _StringsDialogsLicenseDialogZh._(_root); + late final _StringsPagesEmojiDialogsUploadEn upload = _StringsPagesEmojiDialogsUploadEn._(_root); } -// Path: pages.homePage -class _StringsPagesHomePageZh implements _StringsPagesHomePageEn { - _StringsPagesHomePageZh._(this._root); +// Path: pages.feedback.tips +class _StringsPagesFeedbackTipsEn { + _StringsPagesFeedbackTipsEn._(this._root); - @override final _StringsZh _root; // ignore: unused_field + final Translations _root; // ignore: unused_field // Translations - @override String get title => '信鸽'; + String get title => 'Comments or suggestions are welcome, wow~'; + String get prefix => 'No matter you encounter any questions, comments or suggestions, you can'; + String get button => ' [click here] '; + String get suffix => 'to give feedback.'; } -// Path: dialogs.licenseDialog -class _StringsDialogsLicenseDialogZh implements _StringsDialogsLicenseDialogEn { - _StringsDialogsLicenseDialogZh._(this._root); +// Path: pages.feedback.dialogs +class _StringsPagesFeedbackDialogsEn { + _StringsPagesFeedbackDialogsEn._(this._root); - @override final _StringsZh _root; // ignore: unused_field + final Translations _root; // ignore: unused_field // Translations - @override String get licenseDialogTitle => '隐私条款'; - @override String get licenseDialogContentContent => '信鸽 非常重视你的隐私保护和个人信息保护.'; - @override String get licenseDialogContentTip => '以下是该APP所需的权限列表:'; - @override String get licenseDialogContentPrefix => '在使用APP服务前,请认真阅读 '; - @override String get licenseDialogContentUserAgreement => '《隐私政策》'; - @override String get licenseDialogContentAnd => '和'; - @override String get licenseDialogContentPrivacyAgreement => '《用户服务协议》'; - @override String get licenseDialogContentSuffix => ', 你同意并接受全部条款后开始使用我们的服务.'; - @override List get iosPermissions => [ - '为了让您拍摄照片, 信鸽 需要访问您的相机. (NSCameraUsageDescription)', - '为了让您上传图片, 信鸽 需要访问您的照片. (NSPhotoLibraryUsageDescription)', - ]; - @override List get androidPermissions => [ - '用于应用程序和服务器之间的数据交互,信鸽 需要访问您的互联网. (android.permission.INTERNET)', - '为了给您发送通知, 信鸽 需要获取您的权限. (android.permission.POST_NOTIFICATIONS)', - '为了让您上传图片, 信鸽 需要访问您的存储. (android.permission.READ_EXTERNAL_STORAGE)', - '为了让您保存图片, 信鸽 需要访问您的存储. (android.permission.WRITE_EXTERNAL_STORAGE)', - '为了让您上传图片, 信鸽 需要访问您的照片. (android.permission.READ_MEDIA_IMAGES)', - '为了让您上传视频, 信鸽 需要访问您的视频. (android.permission.READ_MEDIA_VIDEO)', - '为了让您拍摄照片, 信鸽 需要访问您的相机. (android.permission.CAMERA)', - '为了向您发送本地通知, 信鸽 需要访问您的权限. (android.permission.RECEIVE_BOOT_COMPLETED)', - ]; + late final _StringsPagesFeedbackDialogsUploadEn upload = _StringsPagesFeedbackDialogsUploadEn._(_root); +} + +// Path: bottomSheets.login.form +class _StringsBottomSheetsLoginFormEn { + _StringsBottomSheetsLoginFormEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + late final _StringsBottomSheetsLoginFormAccountEn account = _StringsBottomSheetsLoginFormAccountEn._(_root); + late final _StringsBottomSheetsLoginFormPasswordEn password = _StringsBottomSheetsLoginFormPasswordEn._(_root); + late final _StringsBottomSheetsLoginFormPrivacyEn privacy = _StringsBottomSheetsLoginFormPrivacyEn._(_root); +} + +// Path: bottomSheets.login.tips +class _StringsBottomSheetsLoginTipsEn { + _StringsBottomSheetsLoginTipsEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get prefix => 'Already have an account, '; + String get suffix => 'go to login'; +} + +// Path: bottomSheets.signup.form +class _StringsBottomSheetsSignupFormEn { + _StringsBottomSheetsSignupFormEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + late final _StringsBottomSheetsSignupFormAccountEn account = _StringsBottomSheetsSignupFormAccountEn._(_root); + late final _StringsBottomSheetsSignupFormNicknameEn nickname = _StringsBottomSheetsSignupFormNicknameEn._(_root); + late final _StringsBottomSheetsSignupFormEmailEn email = _StringsBottomSheetsSignupFormEmailEn._(_root); + late final _StringsBottomSheetsSignupFormPasswordEn password = _StringsBottomSheetsSignupFormPasswordEn._(_root); + late final _StringsBottomSheetsSignupFormRepeatPasswordEn repeatPassword = _StringsBottomSheetsSignupFormRepeatPasswordEn._(_root); +} + +// Path: bottomSheets.signup.tips +class _StringsBottomSheetsSignupTipsEn { + _StringsBottomSheetsSignupTipsEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get prefix => 'No account yet, '; + String get suffix => 'go to register'; +} + +// Path: bottomSheets.store.code +class _StringsBottomSheetsStoreCodeEn { + _StringsBottomSheetsStoreCodeEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Copy Taobao code'; + String get description => 'Get the live broadcast platform, time, etc.'; +} + +// Path: bottomSheets.store.link +class _StringsBottomSheetsStoreLinkEn { + _StringsBottomSheetsStoreLinkEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Open store link'; + String get description => 'The cold wave is coming! Bring on a sweatshirt~~'; +} + +// Path: pages.home.primary.rating +class _StringsPagesHomePrimaryRatingEn { + _StringsPagesHomePrimaryRatingEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Movie rating'; + String get description => 'Rate the movies you’ve watched~~'; +} + +// Path: pages.home.primary.live +class _StringsPagesHomePrimaryLiveEn { + _StringsPagesHomePrimaryLiveEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Live broadcast preview'; + String get description => 'Go to the details'; +} + +// Path: pages.home.primary.settings +class _StringsPagesHomePrimarySettingsEn { + _StringsPagesHomePrimarySettingsEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Settings'; +} + +// Path: pages.home.other.notifications +class _StringsPagesHomeOtherNotificationsEn { + _StringsPagesHomeOtherNotificationsEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Reminders'; + String get description => 'Get the live broadcast platform, time, etc.'; +} + +// Path: pages.home.other.store +class _StringsPagesHomeOtherStoreEn { + _StringsPagesHomeOtherStoreEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'TAOBAO: Serious'; + String get description => 'The cold wave is coming! Bring on a sweatshirt~~'; +} + +// Path: pages.home.other.emoji +class _StringsPagesHomeOtherEmojiEn { + _StringsPagesHomeOtherEmojiEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Emojis🐱'; + String get description => 'Contributions welcome~~'; +} + +// Path: pages.home.other.feedback +class _StringsPagesHomeOtherFeedbackEn { + _StringsPagesHomeOtherFeedbackEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Feedback'; + String get description => 'No matter you encounter any questions, comments or suggestions, you can give us feedback...'; +} + +// Path: pages.home.other.roadmap +class _StringsPagesHomeOtherRoadmapEn { + _StringsPagesHomeOtherRoadmapEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Roadmap'; + String get description => 'View development plans and progress😄'; +} + +// Path: pages.emoji.dialogs.upload +class _StringsPagesEmojiDialogsUploadEn { + _StringsPagesEmojiDialogsUploadEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + late final _StringsPagesEmojiDialogsUploadButtonsEn buttons = _StringsPagesEmojiDialogsUploadButtonsEn._(_root); + String get header => 'Please select emojis you want to upload'; + late final _StringsPagesEmojiDialogsUploadTipsEn tips = _StringsPagesEmojiDialogsUploadTipsEn._(_root); + late final _StringsPagesEmojiDialogsUploadFormEn form = _StringsPagesEmojiDialogsUploadFormEn._(_root); + String get uploadFailed => 'File upload failed😭'; +} + +// Path: pages.feedback.dialogs.upload +class _StringsPagesFeedbackDialogsUploadEn { + _StringsPagesFeedbackDialogsUploadEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + late final _StringsPagesFeedbackDialogsUploadButtonsEn buttons = _StringsPagesFeedbackDialogsUploadButtonsEn._(_root); + String get header => 'Please fill in the feedback info'; + late final _StringsPagesFeedbackDialogsUploadFormEn form = _StringsPagesFeedbackDialogsUploadFormEn._(_root); + late final _StringsPagesFeedbackDialogsUploadErrorEn error = _StringsPagesFeedbackDialogsUploadErrorEn._(_root); + String get uploadFailed => '文件上传失败😭'; +} + +// Path: bottomSheets.login.form.account +class _StringsBottomSheetsLoginFormAccountEn { + _StringsBottomSheetsLoginFormAccountEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Account'; + String get hintText => 'Please enter your account'; + String get errorText => 'Please enter your account'; + String get errorText2 => 'Please enter at least 8 characters'; +} + +// Path: bottomSheets.login.form.password +class _StringsBottomSheetsLoginFormPasswordEn { + _StringsBottomSheetsLoginFormPasswordEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Password'; + String get hintText => 'Please enter your password'; + String get errorText => 'Please enter your password'; + String get errorText2 => 'Please enter at least 8 characters'; +} + +// Path: bottomSheets.login.form.privacy +class _StringsBottomSheetsLoginFormPrivacyEn { + _StringsBottomSheetsLoginFormPrivacyEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Privacy'; + String get prefix => 'I have read carefully and agree'; + String get privacy => ' Privacy Policy '; + String get and => '&'; + String get terms => ' terms and Conditions'; + String get errorText => 'Please agree to the privacy agreement'; +} + +// Path: bottomSheets.signup.form.account +class _StringsBottomSheetsSignupFormAccountEn { + _StringsBottomSheetsSignupFormAccountEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get helperText => 'The account number can only contain letters, numbers or underscores, and can only start with a letter and be at least 8 characters long.'; + String get errorText2 => 'The account number can only contain letters, numbers or underscores, and can only start with a letter and be at least 8 characters long.'; +} + +// Path: bottomSheets.signup.form.nickname +class _StringsBottomSheetsSignupFormNicknameEn { + _StringsBottomSheetsSignupFormNicknameEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Nickname'; + String get hintText => 'Please enter your nickname'; + String get helperText => 'Nickname cannot be longer than 20 characters'; + String get errorText => 'Nickname cannot be longer than 20 characters'; +} + +// Path: bottomSheets.signup.form.email +class _StringsBottomSheetsSignupFormEmailEn { + _StringsBottomSheetsSignupFormEmailEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Email'; + String get hintText => 'Please enter your email'; + String get errorText => 'Please enter your email'; + String get errorText2 => 'The email format you entered is wrong'; +} + +// Path: bottomSheets.signup.form.password +class _StringsBottomSheetsSignupFormPasswordEn { + _StringsBottomSheetsSignupFormPasswordEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get helperText => 'Please enter at least 8 characters'; +} + +// Path: bottomSheets.signup.form.repeatPassword +class _StringsBottomSheetsSignupFormRepeatPasswordEn { + _StringsBottomSheetsSignupFormRepeatPasswordEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Repeat password'; + String get hintText => 'Please enter your password again'; + String get errorText => 'Please enter your password again'; + String get errorText2 => 'The passwords entered twice are different'; +} + +// Path: pages.emoji.dialogs.upload.buttons +class _StringsPagesEmojiDialogsUploadButtonsEn { + _StringsPagesEmojiDialogsUploadButtonsEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get upload => 'Upload'; +} + +// Path: pages.emoji.dialogs.upload.tips +class _StringsPagesEmojiDialogsUploadTipsEn { + _StringsPagesEmojiDialogsUploadTipsEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get prefix => 'You can upload up to 9 images'; + String get suffix => 'Image size must be between 50KB and 15MB'; +} + +// Path: pages.emoji.dialogs.upload.form +class _StringsPagesEmojiDialogsUploadFormEn { + _StringsPagesEmojiDialogsUploadFormEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + late final _StringsPagesEmojiDialogsUploadFormEmojisEn emojis = _StringsPagesEmojiDialogsUploadFormEmojisEn._(_root); +} + +// Path: pages.feedback.dialogs.upload.buttons +class _StringsPagesFeedbackDialogsUploadButtonsEn { + _StringsPagesFeedbackDialogsUploadButtonsEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get upload => 'Submit'; +} + +// Path: pages.feedback.dialogs.upload.form +class _StringsPagesFeedbackDialogsUploadFormEn { + _StringsPagesFeedbackDialogsUploadFormEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + late final _StringsPagesFeedbackDialogsUploadFormTitleEn title = _StringsPagesFeedbackDialogsUploadFormTitleEn._(_root); + late final _StringsPagesFeedbackDialogsUploadFormDescriptionEn description = _StringsPagesFeedbackDialogsUploadFormDescriptionEn._(_root); + late final _StringsPagesFeedbackDialogsUploadFormAssetsEn assets = _StringsPagesFeedbackDialogsUploadFormAssetsEn._(_root); +} + +// Path: pages.feedback.dialogs.upload.error +class _StringsPagesFeedbackDialogsUploadErrorEn { + _StringsPagesFeedbackDialogsUploadErrorEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get image => 'Uploaded images must be between 15KB and 15MB'; + String get video => 'Uploaded videos must be between 15KB and 15MB'; +} + +// Path: pages.emoji.dialogs.upload.form.emojis +class _StringsPagesEmojiDialogsUploadFormEmojisEn { + _StringsPagesEmojiDialogsUploadFormEmojisEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get errorText => 'Please select emojis you want to upload'; +} + +// Path: pages.feedback.dialogs.upload.form.title +class _StringsPagesFeedbackDialogsUploadFormTitleEn { + _StringsPagesFeedbackDialogsUploadFormTitleEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Title'; + String get hintText => 'Please enter a title'; + String get errorText => 'Please enter a title'; +} + +// Path: pages.feedback.dialogs.upload.form.description +class _StringsPagesFeedbackDialogsUploadFormDescriptionEn { + _StringsPagesFeedbackDialogsUploadFormDescriptionEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Description'; + String get hintText => 'Please enter a description'; + String get errorText => 'Please enter a description'; +} + +// Path: pages.feedback.dialogs.upload.form.assets +class _StringsPagesFeedbackDialogsUploadFormAssetsEn { + _StringsPagesFeedbackDialogsUploadFormAssetsEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + String get title => 'Picture or video'; + String get prefix => 'You can upload up to 9 pictures or videos'; + String get suffix => 'Image size must be between 50KB and 15MB, video size must be between 50KB and 20MB'; +} + +// Path: +class _StringsZh implements Translations { + /// You can call this constructor and build your own translation instance of this locale. + /// Constructing via the enum [AppLocale.build] is preferred. + _StringsZh.build({Map? overrides, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) + : assert(overrides == null, 'Set "translation_overrides: true" in order to enable this feature.'), + $meta = TranslationMetadata( + locale: AppLocale.zh, + overrides: overrides ?? {}, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ) { + $meta.setFlatMapFunction(_flatMapFunction); + } + + /// Metadata for the translations of . + @override final TranslationMetadata $meta; + + /// Access flat map + @override dynamic operator[](String key) => $meta.getTranslation(key); + + @override late final _StringsZh _root = this; // ignore: unused_field + + // Translations + @override String get appName => '信鸽'; + @override late final _StringsCommonZh common = _StringsCommonZh._(_root); + @override late final _StringsPagesZh pages = _StringsPagesZh._(_root); + @override late final _StringsButtonsZh buttons = _StringsButtonsZh._(_root); + @override late final _StringsBottomSheetsZh bottomSheets = _StringsBottomSheetsZh._(_root); + @override late final _StringsDialogsZh dialogs = _StringsDialogsZh._(_root); + @override Map get locales => { + 'en': 'English', + 'zh': '中文', + }; +} + +// Path: common +class _StringsCommonZh implements _StringsCommonEn { + _StringsCommonZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get copied => '已复制'; + @override String get success => '成功啦😊'; + @override String get failure => '失败啦😭'; + @override String get noData => '没有数据, 点击以重新加载😭'; +} + +// Path: pages +class _StringsPagesZh implements _StringsPagesEn { + _StringsPagesZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override late final _StringsPagesHomeZh home = _StringsPagesHomeZh._(_root); + @override late final _StringsPagesEmojiZh emoji = _StringsPagesEmojiZh._(_root); + @override late final _StringsPagesFeedbackZh feedback = _StringsPagesFeedbackZh._(_root); + @override late final _StringsPagesFeedbackDetailZh feedbackDetail = _StringsPagesFeedbackDetailZh._(_root); + @override late final _StringsPagesLiveZh live = _StringsPagesLiveZh._(_root); + @override late final _StringsPagesMovieZh movie = _StringsPagesMovieZh._(_root); + @override late final _StringsPagesRoadmapZh roadmap = _StringsPagesRoadmapZh._(_root); + @override late final _StringsPagesSocialZh social = _StringsPagesSocialZh._(_root); +} + +// Path: buttons +class _StringsButtonsZh implements _StringsButtonsEn { + _StringsButtonsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get agree => '同意'; + @override String get cancel => '再想想'; + @override String get login => '登录'; + @override String get signup => '注册'; + @override String get logout => '退出'; + @override String get ignore => '忽略'; + @override String get turnOn => '开启'; + @override String get turnOff => '关闭'; +} + +// Path: bottomSheets +class _StringsBottomSheetsZh implements _StringsBottomSheetsEn { + _StringsBottomSheetsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override late final _StringsBottomSheetsLoginZh login = _StringsBottomSheetsLoginZh._(_root); + @override late final _StringsBottomSheetsSignupZh signup = _StringsBottomSheetsSignupZh._(_root); + @override late final _StringsBottomSheetsStoreZh store = _StringsBottomSheetsStoreZh._(_root); +} + +// Path: dialogs +class _StringsDialogsZh implements _StringsDialogsEn { + _StringsDialogsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override late final _StringsDialogsLicenseZh license = _StringsDialogsLicenseZh._(_root); + @override late final _StringsDialogsAlbumZh album = _StringsDialogsAlbumZh._(_root); +} + +// Path: pages.home +class _StringsPagesHomeZh implements _StringsPagesHomeEn { + _StringsPagesHomeZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override late final _StringsPagesHomePrimaryZh primary = _StringsPagesHomePrimaryZh._(_root); + @override late final _StringsPagesHomeOtherZh other = _StringsPagesHomeOtherZh._(_root); + @override String get version => '版本号'; +} + +// Path: pages.emoji +class _StringsPagesEmojiZh implements _StringsPagesEmojiEn { + _StringsPagesEmojiZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '表情库~'; + @override late final _StringsPagesEmojiTipsZh tips = _StringsPagesEmojiTipsZh._(_root); + @override late final _StringsPagesEmojiDialogsZh dialogs = _StringsPagesEmojiDialogsZh._(_root); +} + +// Path: pages.feedback +class _StringsPagesFeedbackZh implements _StringsPagesFeedbackEn { + _StringsPagesFeedbackZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '意见或建议'; + @override late final _StringsPagesFeedbackTipsZh tips = _StringsPagesFeedbackTipsZh._(_root); + @override late final _StringsPagesFeedbackDialogsZh dialogs = _StringsPagesFeedbackDialogsZh._(_root); +} + +// Path: pages.feedbackDetail +class _StringsPagesFeedbackDetailZh implements _StringsPagesFeedbackDetailEn { + _StringsPagesFeedbackDetailZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '反馈详情'; +} + +// Path: pages.live +class _StringsPagesLiveZh implements _StringsPagesLiveEn { + _StringsPagesLiveZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '直播~'; +} + +// Path: pages.movie +class _StringsPagesMovieZh implements _StringsPagesMovieEn { + _StringsPagesMovieZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '电影'; +} + +// Path: pages.roadmap +class _StringsPagesRoadmapZh implements _StringsPagesRoadmapEn { + _StringsPagesRoadmapZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '路线图'; +} + +// Path: pages.social +class _StringsPagesSocialZh implements _StringsPagesSocialEn { + _StringsPagesSocialZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '社交'; +} + +// Path: bottomSheets.login +class _StringsBottomSheetsLoginZh implements _StringsBottomSheetsLoginEn { + _StringsBottomSheetsLoginZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get header => '请填写登录信息'; + @override late final _StringsBottomSheetsLoginFormZh form = _StringsBottomSheetsLoginFormZh._(_root); + @override late final _StringsBottomSheetsLoginTipsZh tips = _StringsBottomSheetsLoginTipsZh._(_root); +} + +// Path: bottomSheets.signup +class _StringsBottomSheetsSignupZh implements _StringsBottomSheetsSignupEn { + _StringsBottomSheetsSignupZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get header => '请填写注册信息'; + @override late final _StringsBottomSheetsSignupFormZh form = _StringsBottomSheetsSignupFormZh._(_root); + @override late final _StringsBottomSheetsSignupTipsZh tips = _StringsBottomSheetsSignupTipsZh._(_root); +} + +// Path: bottomSheets.store +class _StringsBottomSheetsStoreZh implements _StringsBottomSheetsStoreEn { + _StringsBottomSheetsStoreZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '请选择您的操作'; + @override late final _StringsBottomSheetsStoreCodeZh code = _StringsBottomSheetsStoreCodeZh._(_root); + @override late final _StringsBottomSheetsStoreLinkZh link = _StringsBottomSheetsStoreLinkZh._(_root); +} + +// Path: dialogs.license +class _StringsDialogsLicenseZh implements _StringsDialogsLicenseEn { + _StringsDialogsLicenseZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '隐私条款'; + @override String get contentContent => '信鸽 非常重视你的隐私保护和个人信息保护.'; + @override String get contentTip => '以下是该APP所需的权限列表:'; + @override String get contentPrefix => '在使用APP服务前,请认真阅读 '; + @override String get contentUserAgreement => '《隐私政策》'; + @override String get contentAnd => '和'; + @override String get contentPrivacyAgreement => '《用户服务协议》'; + @override String get contentSuffix => ', 你同意并接受全部条款后开始使用我们的服务.'; + @override List get iosPermissions => [ + '为了让您拍摄照片, 信鸽 需要访问您的相机. (NSCameraUsageDescription)', + '为了让您上传图片, 信鸽 需要访问您的照片. (NSPhotoLibraryUsageDescription)', + ]; + @override List get androidPermissions => [ + '用于应用程序和服务器之间的数据交互,信鸽 需要访问您的互联网. (android.permission.INTERNET)', + '为了给您发送通知, 信鸽 需要获取您的权限. (android.permission.POST_NOTIFICATIONS)', + '为了让您上传图片, 信鸽 需要访问您的存储. (android.permission.READ_EXTERNAL_STORAGE)', + '为了让您保存图片, 信鸽 需要访问您的存储. (android.permission.WRITE_EXTERNAL_STORAGE)', + '为了让您上传图片, 信鸽 需要访问您的照片. (android.permission.READ_MEDIA_IMAGES)', + '为了让您上传视频, 信鸽 需要访问您的视频. (android.permission.READ_MEDIA_VIDEO)', + '为了让您拍摄照片, 信鸽 需要访问您的相机. (android.permission.CAMERA)', + '为了向您发送本地通知, 信鸽 需要访问您的权限. (android.permission.RECEIVE_BOOT_COMPLETED)', + ]; +} + +// Path: dialogs.album +class _StringsDialogsAlbumZh implements _StringsDialogsAlbumEn { + _StringsDialogsAlbumZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '允许访问您的相册'; + @override String get description => '请前往您的手机设置授予信鸽访问您相册的权限.'; +} + +// Path: pages.home.primary +class _StringsPagesHomePrimaryZh implements _StringsPagesHomePrimaryEn { + _StringsPagesHomePrimaryZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '主要功能'; + @override late final _StringsPagesHomePrimaryRatingZh rating = _StringsPagesHomePrimaryRatingZh._(_root); + @override late final _StringsPagesHomePrimaryLiveZh live = _StringsPagesHomePrimaryLiveZh._(_root); + @override late final _StringsPagesHomePrimarySettingsZh settings = _StringsPagesHomePrimarySettingsZh._(_root); +} + +// Path: pages.home.other +class _StringsPagesHomeOtherZh implements _StringsPagesHomeOtherEn { + _StringsPagesHomeOtherZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '其他功能'; + @override late final _StringsPagesHomeOtherNotificationsZh notifications = _StringsPagesHomeOtherNotificationsZh._(_root); + @override late final _StringsPagesHomeOtherStoreZh store = _StringsPagesHomeOtherStoreZh._(_root); + @override late final _StringsPagesHomeOtherEmojiZh emoji = _StringsPagesHomeOtherEmojiZh._(_root); + @override late final _StringsPagesHomeOtherFeedbackZh feedback = _StringsPagesHomeOtherFeedbackZh._(_root); + @override late final _StringsPagesHomeOtherRoadmapZh roadmap = _StringsPagesHomeOtherRoadmapZh._(_root); +} + +// Path: pages.emoji.tips +class _StringsPagesEmojiTipsZh implements _StringsPagesEmojiTipsEn { + _StringsPagesEmojiTipsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '欢迎投稿,嗷呜~'; + @override String get prefix => '欢迎'; + @override String get button => ' [点击此处] '; + @override String get suffix => '投稿,可以是表情包,可以是文案创意,也可以是一些令猫尴尬的图片或截图等~😄'; +} + +// Path: pages.emoji.dialogs +class _StringsPagesEmojiDialogsZh implements _StringsPagesEmojiDialogsEn { + _StringsPagesEmojiDialogsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override late final _StringsPagesEmojiDialogsUploadZh upload = _StringsPagesEmojiDialogsUploadZh._(_root); +} + +// Path: pages.feedback.tips +class _StringsPagesFeedbackTipsZh implements _StringsPagesFeedbackTipsEn { + _StringsPagesFeedbackTipsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '欢迎提意见或建议,嗷呜~'; + @override String get prefix => '无论您遇到任何问题、意见或建议,均可'; + @override String get button => ' [点击此处] '; + @override String get suffix => '进行反馈.'; +} + +// Path: pages.feedback.dialogs +class _StringsPagesFeedbackDialogsZh implements _StringsPagesFeedbackDialogsEn { + _StringsPagesFeedbackDialogsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override late final _StringsPagesFeedbackDialogsUploadZh upload = _StringsPagesFeedbackDialogsUploadZh._(_root); +} + +// Path: bottomSheets.login.form +class _StringsBottomSheetsLoginFormZh implements _StringsBottomSheetsLoginFormEn { + _StringsBottomSheetsLoginFormZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override late final _StringsBottomSheetsLoginFormAccountZh account = _StringsBottomSheetsLoginFormAccountZh._(_root); + @override late final _StringsBottomSheetsLoginFormPasswordZh password = _StringsBottomSheetsLoginFormPasswordZh._(_root); + @override late final _StringsBottomSheetsLoginFormPrivacyZh privacy = _StringsBottomSheetsLoginFormPrivacyZh._(_root); +} + +// Path: bottomSheets.login.tips +class _StringsBottomSheetsLoginTipsZh implements _StringsBottomSheetsLoginTipsEn { + _StringsBottomSheetsLoginTipsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get prefix => '已有账号, '; + @override String get suffix => '去登录'; +} + +// Path: bottomSheets.signup.form +class _StringsBottomSheetsSignupFormZh implements _StringsBottomSheetsSignupFormEn { + _StringsBottomSheetsSignupFormZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override late final _StringsBottomSheetsSignupFormAccountZh account = _StringsBottomSheetsSignupFormAccountZh._(_root); + @override late final _StringsBottomSheetsSignupFormNicknameZh nickname = _StringsBottomSheetsSignupFormNicknameZh._(_root); + @override late final _StringsBottomSheetsSignupFormEmailZh email = _StringsBottomSheetsSignupFormEmailZh._(_root); + @override late final _StringsBottomSheetsSignupFormPasswordZh password = _StringsBottomSheetsSignupFormPasswordZh._(_root); + @override late final _StringsBottomSheetsSignupFormRepeatPasswordZh repeatPassword = _StringsBottomSheetsSignupFormRepeatPasswordZh._(_root); +} + +// Path: bottomSheets.signup.tips +class _StringsBottomSheetsSignupTipsZh implements _StringsBottomSheetsSignupTipsEn { + _StringsBottomSheetsSignupTipsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get prefix => '还没有账号, '; + @override String get suffix => '去注册'; +} + +// Path: bottomSheets.store.code +class _StringsBottomSheetsStoreCodeZh implements _StringsBottomSheetsStoreCodeEn { + _StringsBottomSheetsStoreCodeZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '复制淘口令'; + @override String get description => '直播平台、时间等'; +} + +// Path: bottomSheets.store.link +class _StringsBottomSheetsStoreLinkZh implements _StringsBottomSheetsStoreLinkEn { + _StringsBottomSheetsStoreLinkZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '打开淘宝店地址'; + @override String get description => '寒潮啦! 来件卫衣吧~~'; +} + +// Path: pages.home.primary.rating +class _StringsPagesHomePrimaryRatingZh implements _StringsPagesHomePrimaryRatingEn { + _StringsPagesHomePrimaryRatingZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '电影打分系统'; + @override String get description => '给看过的电影打个分吧~~'; +} + +// Path: pages.home.primary.live +class _StringsPagesHomePrimaryLiveZh implements _StringsPagesHomePrimaryLiveEn { + _StringsPagesHomePrimaryLiveZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '直播预告'; + @override String get description => '查看详情'; +} + +// Path: pages.home.primary.settings +class _StringsPagesHomePrimarySettingsZh implements _StringsPagesHomePrimarySettingsEn { + _StringsPagesHomePrimarySettingsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '开播通知设置'; +} + +// Path: pages.home.other.notifications +class _StringsPagesHomeOtherNotificationsZh implements _StringsPagesHomeOtherNotificationsEn { + _StringsPagesHomeOtherNotificationsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '直播信息/提醒群'; + @override String get description => '直播平台、时间等'; +} + +// Path: pages.home.other.store +class _StringsPagesHomeOtherStoreZh implements _StringsPagesHomeOtherStoreEn { + _StringsPagesHomeOtherStoreZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '小德官方店: 喜瑞斯'; + @override String get description => '寒潮啦! 来件卫衣吧~~'; +} + +// Path: pages.home.other.emoji +class _StringsPagesHomeOtherEmojiZh implements _StringsPagesHomeOtherEmojiEn { + _StringsPagesHomeOtherEmojiZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '小德表情包🐱'; + @override String get description => '欢迎投稿~~'; +} + +// Path: pages.home.other.feedback +class _StringsPagesHomeOtherFeedbackZh implements _StringsPagesHomeOtherFeedbackEn { + _StringsPagesHomeOtherFeedbackZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '意见/建议'; + @override String get description => '无论您遇到任何问题、意见或建议, 均可反馈...'; +} + +// Path: pages.home.other.roadmap +class _StringsPagesHomeOtherRoadmapZh implements _StringsPagesHomeOtherRoadmapEn { + _StringsPagesHomeOtherRoadmapZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '路线图'; + @override String get description => '查看开发计划和进度😄'; +} + +// Path: pages.emoji.dialogs.upload +class _StringsPagesEmojiDialogsUploadZh implements _StringsPagesEmojiDialogsUploadEn { + _StringsPagesEmojiDialogsUploadZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override late final _StringsPagesEmojiDialogsUploadButtonsZh buttons = _StringsPagesEmojiDialogsUploadButtonsZh._(_root); + @override String get header => '请选择要上传的表情'; + @override late final _StringsPagesEmojiDialogsUploadTipsZh tips = _StringsPagesEmojiDialogsUploadTipsZh._(_root); + @override late final _StringsPagesEmojiDialogsUploadFormZh form = _StringsPagesEmojiDialogsUploadFormZh._(_root); + @override String get uploadFailed => '文件上传失败😭'; +} + +// Path: pages.feedback.dialogs.upload +class _StringsPagesFeedbackDialogsUploadZh implements _StringsPagesFeedbackDialogsUploadEn { + _StringsPagesFeedbackDialogsUploadZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override late final _StringsPagesFeedbackDialogsUploadButtonsZh buttons = _StringsPagesFeedbackDialogsUploadButtonsZh._(_root); + @override String get header => '请填写反馈内容'; + @override late final _StringsPagesFeedbackDialogsUploadFormZh form = _StringsPagesFeedbackDialogsUploadFormZh._(_root); + @override late final _StringsPagesFeedbackDialogsUploadErrorZh error = _StringsPagesFeedbackDialogsUploadErrorZh._(_root); + @override String get uploadFailed => '文件上传失败😭'; +} + +// Path: bottomSheets.login.form.account +class _StringsBottomSheetsLoginFormAccountZh implements _StringsBottomSheetsLoginFormAccountEn { + _StringsBottomSheetsLoginFormAccountZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '账号'; + @override String get hintText => '请输入账号'; + @override String get errorText => '请输入账号'; + @override String get errorText2 => '请输入至少8个字符'; +} + +// Path: bottomSheets.login.form.password +class _StringsBottomSheetsLoginFormPasswordZh implements _StringsBottomSheetsLoginFormPasswordEn { + _StringsBottomSheetsLoginFormPasswordZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '密码'; + @override String get hintText => '请输入密码'; + @override String get errorText => '请输入密码'; + @override String get errorText2 => '请输入至少8个字符'; +} + +// Path: bottomSheets.login.form.privacy +class _StringsBottomSheetsLoginFormPrivacyZh implements _StringsBottomSheetsLoginFormPrivacyEn { + _StringsBottomSheetsLoginFormPrivacyZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '隐私协议'; + @override String get prefix => '我已仔细阅读并同意'; + @override String get privacy => '隐私政策'; + @override String get and => '以及'; + @override String get terms => '条款和条件'; + @override String get errorText => '请同意隐私协议'; +} + +// Path: bottomSheets.signup.form.account +class _StringsBottomSheetsSignupFormAccountZh implements _StringsBottomSheetsSignupFormAccountEn { + _StringsBottomSheetsSignupFormAccountZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get helperText => '只能包含英文, 数字或下划线, 且只能以字母开头, 至少8个字符'; + @override String get errorText2 => '账号只能包含英文,数字或下划线, 且只能以字母开头, 至少8个字符'; +} + +// Path: bottomSheets.signup.form.nickname +class _StringsBottomSheetsSignupFormNicknameZh implements _StringsBottomSheetsSignupFormNicknameEn { + _StringsBottomSheetsSignupFormNicknameZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '昵称'; + @override String get hintText => '请输入昵称'; + @override String get helperText => '不能多于20个字符'; + @override String get errorText => '昵称长度不能大于20'; +} + +// Path: bottomSheets.signup.form.email +class _StringsBottomSheetsSignupFormEmailZh implements _StringsBottomSheetsSignupFormEmailEn { + _StringsBottomSheetsSignupFormEmailZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '邮箱'; + @override String get hintText => '请输入邮箱'; + @override String get errorText => '请输入邮箱'; + @override String get errorText2 => '邮箱格式错误'; +} + +// Path: bottomSheets.signup.form.password +class _StringsBottomSheetsSignupFormPasswordZh implements _StringsBottomSheetsSignupFormPasswordEn { + _StringsBottomSheetsSignupFormPasswordZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get helperText => '请输入至少8个字符'; +} + +// Path: bottomSheets.signup.form.repeatPassword +class _StringsBottomSheetsSignupFormRepeatPasswordZh implements _StringsBottomSheetsSignupFormRepeatPasswordEn { + _StringsBottomSheetsSignupFormRepeatPasswordZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '账号'; + @override String get hintText => '请再次输入密码'; + @override String get errorText => '请再次输入密码'; + @override String get errorText2 => '两次输入的密码不一样'; +} + +// Path: pages.emoji.dialogs.upload.buttons +class _StringsPagesEmojiDialogsUploadButtonsZh implements _StringsPagesEmojiDialogsUploadButtonsEn { + _StringsPagesEmojiDialogsUploadButtonsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get upload => '上传'; +} + +// Path: pages.emoji.dialogs.upload.tips +class _StringsPagesEmojiDialogsUploadTipsZh implements _StringsPagesEmojiDialogsUploadTipsEn { + _StringsPagesEmojiDialogsUploadTipsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get prefix => '您最多可以上传9张图片'; + @override String get suffix => '图片大小必须在50KB到15MB之间'; +} + +// Path: pages.emoji.dialogs.upload.form +class _StringsPagesEmojiDialogsUploadFormZh implements _StringsPagesEmojiDialogsUploadFormEn { + _StringsPagesEmojiDialogsUploadFormZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override late final _StringsPagesEmojiDialogsUploadFormEmojisZh emojis = _StringsPagesEmojiDialogsUploadFormEmojisZh._(_root); +} + +// Path: pages.feedback.dialogs.upload.buttons +class _StringsPagesFeedbackDialogsUploadButtonsZh implements _StringsPagesFeedbackDialogsUploadButtonsEn { + _StringsPagesFeedbackDialogsUploadButtonsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get upload => '提交'; +} + +// Path: pages.feedback.dialogs.upload.form +class _StringsPagesFeedbackDialogsUploadFormZh implements _StringsPagesFeedbackDialogsUploadFormEn { + _StringsPagesFeedbackDialogsUploadFormZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override late final _StringsPagesFeedbackDialogsUploadFormTitleZh title = _StringsPagesFeedbackDialogsUploadFormTitleZh._(_root); + @override late final _StringsPagesFeedbackDialogsUploadFormDescriptionZh description = _StringsPagesFeedbackDialogsUploadFormDescriptionZh._(_root); + @override late final _StringsPagesFeedbackDialogsUploadFormAssetsZh assets = _StringsPagesFeedbackDialogsUploadFormAssetsZh._(_root); +} + +// Path: pages.feedback.dialogs.upload.error +class _StringsPagesFeedbackDialogsUploadErrorZh implements _StringsPagesFeedbackDialogsUploadErrorEn { + _StringsPagesFeedbackDialogsUploadErrorZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get image => '上传的图片必须在15KB至15MB之间'; + @override String get video => '上传的视频必须在15KB至20MB之间'; +} + +// Path: pages.emoji.dialogs.upload.form.emojis +class _StringsPagesEmojiDialogsUploadFormEmojisZh implements _StringsPagesEmojiDialogsUploadFormEmojisEn { + _StringsPagesEmojiDialogsUploadFormEmojisZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get errorText => '请选择要上传的表情'; +} + +// Path: pages.feedback.dialogs.upload.form.title +class _StringsPagesFeedbackDialogsUploadFormTitleZh implements _StringsPagesFeedbackDialogsUploadFormTitleEn { + _StringsPagesFeedbackDialogsUploadFormTitleZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '标题'; + @override String get hintText => '请输入标题'; + @override String get errorText => '请输入标题'; +} + +// Path: pages.feedback.dialogs.upload.form.description +class _StringsPagesFeedbackDialogsUploadFormDescriptionZh implements _StringsPagesFeedbackDialogsUploadFormDescriptionEn { + _StringsPagesFeedbackDialogsUploadFormDescriptionZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '描述'; + @override String get hintText => '请输入描述'; + @override String get errorText => '请输入描述'; +} + +// Path: pages.feedback.dialogs.upload.form.assets +class _StringsPagesFeedbackDialogsUploadFormAssetsZh implements _StringsPagesFeedbackDialogsUploadFormAssetsEn { + _StringsPagesFeedbackDialogsUploadFormAssetsZh._(this._root); + + @override final _StringsZh _root; // ignore: unused_field + + // Translations + @override String get title => '图片或视频'; + @override String get prefix => '您最多可以上传9张图片或视频'; + @override String get suffix => '图片大小必须在50KB到15MB之间, 视频大小必须在50KB到20MB之间'; } /// Flat map(s) containing all translations. @@ -343,27 +1611,131 @@ extension on Translations { dynamic _flatMapFunction(String path) { switch (path) { case 'appName': return 'Homing Pigeon'; - case 'pages.homePage.title': return 'Homing Pigeon'; + case 'common.copied': return 'Copied'; + case 'common.success': return 'Succeeded😊'; + case 'common.failure': return 'Failed😭'; + case 'common.noData': return 'No data, click to reload😭'; + case 'pages.home.primary.title': return 'Primary'; + case 'pages.home.primary.rating.title': return 'Movie rating'; + case 'pages.home.primary.rating.description': return 'Rate the movies you’ve watched~~'; + case 'pages.home.primary.live.title': return 'Live broadcast preview'; + case 'pages.home.primary.live.description': return 'Go to the details'; + case 'pages.home.primary.settings.title': return 'Settings'; + case 'pages.home.other.title': return 'Others'; + case 'pages.home.other.notifications.title': return 'Reminders'; + case 'pages.home.other.notifications.description': return 'Get the live broadcast platform, time, etc.'; + case 'pages.home.other.store.title': return 'TAOBAO: Serious'; + case 'pages.home.other.store.description': return 'The cold wave is coming! Bring on a sweatshirt~~'; + case 'pages.home.other.emoji.title': return 'Emojis🐱'; + case 'pages.home.other.emoji.description': return 'Contributions welcome~~'; + case 'pages.home.other.feedback.title': return 'Feedback'; + case 'pages.home.other.feedback.description': return 'No matter you encounter any questions, comments or suggestions, you can give us feedback...'; + case 'pages.home.other.roadmap.title': return 'Roadmap'; + case 'pages.home.other.roadmap.description': return 'View development plans and progress😄'; + case 'pages.home.version': return 'Version'; + case 'pages.emoji.title': return 'Emojis~'; + case 'pages.emoji.tips.title': return 'Contributions are welcome, Wow~'; + case 'pages.emoji.tips.prefix': return 'Welcome'; + case 'pages.emoji.tips.button': return ' [click here] '; + case 'pages.emoji.tips.suffix': return 'to contribute, it can be emoticons, creative copywriting, or some embarrassing pictures or screenshots of cats, etc.😄'; + case 'pages.emoji.dialogs.upload.buttons.upload': return 'Upload'; + case 'pages.emoji.dialogs.upload.header': return 'Please select emojis you want to upload'; + case 'pages.emoji.dialogs.upload.tips.prefix': return 'You can upload up to 9 images'; + case 'pages.emoji.dialogs.upload.tips.suffix': return 'Image size must be between 50KB and 15MB'; + case 'pages.emoji.dialogs.upload.form.emojis.errorText': return 'Please select emojis you want to upload'; + case 'pages.emoji.dialogs.upload.uploadFailed': return 'File upload failed😭'; + case 'pages.feedback.title': return 'Feedback'; + case 'pages.feedback.tips.title': return 'Comments or suggestions are welcome, wow~'; + case 'pages.feedback.tips.prefix': return 'No matter you encounter any questions, comments or suggestions, you can'; + case 'pages.feedback.tips.button': return ' [click here] '; + case 'pages.feedback.tips.suffix': return 'to give feedback.'; + case 'pages.feedback.dialogs.upload.buttons.upload': return 'Submit'; + case 'pages.feedback.dialogs.upload.header': return 'Please fill in the feedback info'; + case 'pages.feedback.dialogs.upload.form.title.title': return 'Title'; + case 'pages.feedback.dialogs.upload.form.title.hintText': return 'Please enter a title'; + case 'pages.feedback.dialogs.upload.form.title.errorText': return 'Please enter a title'; + case 'pages.feedback.dialogs.upload.form.description.title': return 'Description'; + case 'pages.feedback.dialogs.upload.form.description.hintText': return 'Please enter a description'; + case 'pages.feedback.dialogs.upload.form.description.errorText': return 'Please enter a description'; + case 'pages.feedback.dialogs.upload.form.assets.title': return 'Picture or video'; + case 'pages.feedback.dialogs.upload.form.assets.prefix': return 'You can upload up to 9 pictures or videos'; + case 'pages.feedback.dialogs.upload.form.assets.suffix': return 'Image size must be between 50KB and 15MB, video size must be between 50KB and 20MB'; + case 'pages.feedback.dialogs.upload.error.image': return 'Uploaded images must be between 15KB and 15MB'; + case 'pages.feedback.dialogs.upload.error.video': return 'Uploaded videos must be between 15KB and 15MB'; + case 'pages.feedback.dialogs.upload.uploadFailed': return '文件上传失败😭'; + case 'pages.feedbackDetail.title': return 'Feedback details'; + case 'pages.live.title': return 'Live streaming~'; + case 'pages.movie.title': return 'Movie'; + case 'pages.roadmap.title': return 'Roadmap'; + case 'pages.social.title': return 'Social'; case 'buttons.agree': return 'Agree'; case 'buttons.cancel': return 'Cancel'; - case 'dialogs.licenseDialog.licenseDialogTitle': return 'Terms and Conditions'; - case 'dialogs.licenseDialog.licenseDialogContentContent': return 'Protecting user\'s privacy and personal information is a fundamental principle of Homing Pigeon.'; - case 'dialogs.licenseDialog.licenseDialogContentTip': return 'Below is a list of permissions required by this APP:'; - case 'dialogs.licenseDialog.licenseDialogContentPrefix': return 'Before you use this APP\'s services, please carefully read and agree to the '; - case 'dialogs.licenseDialog.licenseDialogContentUserAgreement': return 'User Agreement'; - case 'dialogs.licenseDialog.licenseDialogContentAnd': return ' and '; - case 'dialogs.licenseDialog.licenseDialogContentPrivacyAgreement': return 'Privacy Agreement'; - case 'dialogs.licenseDialog.licenseDialogContentSuffix': return ', start using our services after you agree and accept all terms.'; - case 'dialogs.licenseDialog.iosPermissions.0': return 'For you to take pictures, Homing Pigeon needs access to your Camera. (NSCameraUsageDescription)'; - case 'dialogs.licenseDialog.iosPermissions.1': return 'For you to upload pictures, Homing Pigeon needs access to your Photos. (NSPhotoLibraryUsageDescription)'; - case 'dialogs.licenseDialog.androidPermissions.0': return 'Used for data interaction between the application and the server, Homing Pigeon needs access to your Internet. (android.permission.INTERNET)'; - case 'dialogs.licenseDialog.androidPermissions.1': return 'In order to send you notifications, Homing Pigeon needs access to your permission. (android.permission.POST_NOTIFICATIONS)'; - case 'dialogs.licenseDialog.androidPermissions.2': return 'For you to upload pictures, Homing Pigeon needs access to your Storage. (android.permission.READ_EXTERNAL_STORAGE)'; - case 'dialogs.licenseDialog.androidPermissions.3': return 'For you to save pictures, Homing Pigeon needs access to your Storage. (android.permission.WRITE_EXTERNAL_STORAGE)'; - case 'dialogs.licenseDialog.androidPermissions.4': return 'For you to upload pictures, Homing Pigeon needs access to your Photos. (android.permission.READ_MEDIA_IMAGES)'; - case 'dialogs.licenseDialog.androidPermissions.5': return 'For you to upload videos, Homing Pigeon needs access to your Videos. (android.permission.READ_MEDIA_VIDEO)'; - case 'dialogs.licenseDialog.androidPermissions.6': return 'For you to take pictures, Homing Pigeon needs access to your Camera. (android.permission.CAMERA)'; - case 'dialogs.licenseDialog.androidPermissions.7': return 'In order to send you local notifications, Homing Pigeon needs access to your permission. (android.permission.RECEIVE_BOOT_COMPLETED)'; + case 'buttons.login': return 'Login'; + case 'buttons.signup': return 'Sign up'; + case 'buttons.logout': return 'Logout'; + case 'buttons.ignore': return 'Ignore'; + case 'buttons.turnOn': return 'Turn on'; + case 'buttons.turnOff': return 'Turn off'; + case 'bottomSheets.login.header': return 'Please fill in your login information'; + case 'bottomSheets.login.form.account.title': return 'Account'; + case 'bottomSheets.login.form.account.hintText': return 'Please enter your account'; + case 'bottomSheets.login.form.account.errorText': return 'Please enter your account'; + case 'bottomSheets.login.form.account.errorText2': return 'Please enter at least 8 characters'; + case 'bottomSheets.login.form.password.title': return 'Password'; + case 'bottomSheets.login.form.password.hintText': return 'Please enter your password'; + case 'bottomSheets.login.form.password.errorText': return 'Please enter your password'; + case 'bottomSheets.login.form.password.errorText2': return 'Please enter at least 8 characters'; + case 'bottomSheets.login.form.privacy.title': return 'Privacy'; + case 'bottomSheets.login.form.privacy.prefix': return 'I have read carefully and agree'; + case 'bottomSheets.login.form.privacy.privacy': return ' Privacy Policy '; + case 'bottomSheets.login.form.privacy.and': return '&'; + case 'bottomSheets.login.form.privacy.terms': return ' terms and Conditions'; + case 'bottomSheets.login.form.privacy.errorText': return 'Please agree to the privacy agreement'; + case 'bottomSheets.login.tips.prefix': return 'Already have an account, '; + case 'bottomSheets.login.tips.suffix': return 'go to login'; + case 'bottomSheets.signup.header': return 'Please fill in the registration information'; + case 'bottomSheets.signup.form.account.helperText': return 'The account number can only contain letters, numbers or underscores, and can only start with a letter and be at least 8 characters long.'; + case 'bottomSheets.signup.form.account.errorText2': return 'The account number can only contain letters, numbers or underscores, and can only start with a letter and be at least 8 characters long.'; + case 'bottomSheets.signup.form.nickname.title': return 'Nickname'; + case 'bottomSheets.signup.form.nickname.hintText': return 'Please enter your nickname'; + case 'bottomSheets.signup.form.nickname.helperText': return 'Nickname cannot be longer than 20 characters'; + case 'bottomSheets.signup.form.nickname.errorText': return 'Nickname cannot be longer than 20 characters'; + case 'bottomSheets.signup.form.email.title': return 'Email'; + case 'bottomSheets.signup.form.email.hintText': return 'Please enter your email'; + case 'bottomSheets.signup.form.email.errorText': return 'Please enter your email'; + case 'bottomSheets.signup.form.email.errorText2': return 'The email format you entered is wrong'; + case 'bottomSheets.signup.form.password.helperText': return 'Please enter at least 8 characters'; + case 'bottomSheets.signup.form.repeatPassword.title': return 'Repeat password'; + case 'bottomSheets.signup.form.repeatPassword.hintText': return 'Please enter your password again'; + case 'bottomSheets.signup.form.repeatPassword.errorText': return 'Please enter your password again'; + case 'bottomSheets.signup.form.repeatPassword.errorText2': return 'The passwords entered twice are different'; + case 'bottomSheets.signup.tips.prefix': return 'No account yet, '; + case 'bottomSheets.signup.tips.suffix': return 'go to register'; + case 'bottomSheets.store.title': return 'Please select to continue'; + case 'bottomSheets.store.code.title': return 'Copy Taobao code'; + case 'bottomSheets.store.code.description': return 'Get the live broadcast platform, time, etc.'; + case 'bottomSheets.store.link.title': return 'Open store link'; + case 'bottomSheets.store.link.description': return 'The cold wave is coming! Bring on a sweatshirt~~'; + case 'dialogs.license.title': return 'Terms and Conditions'; + case 'dialogs.license.contentContent': return 'Protecting user\'s privacy and personal information is a fundamental principle of Homing Pigeon.'; + case 'dialogs.license.contentTip': return 'Below is a list of permissions required by this APP:'; + case 'dialogs.license.contentPrefix': return 'Before you use this APP\'s services, please carefully read and agree to the '; + case 'dialogs.license.contentUserAgreement': return 'User Agreement'; + case 'dialogs.license.contentAnd': return ' and '; + case 'dialogs.license.contentPrivacyAgreement': return 'Privacy Agreement'; + case 'dialogs.license.contentSuffix': return ', start using our services after you agree and accept all terms.'; + case 'dialogs.license.iosPermissions.0': return 'For you to take pictures, Homing Pigeon needs access to your Camera. (NSCameraUsageDescription)'; + case 'dialogs.license.iosPermissions.1': return 'For you to upload pictures, Homing Pigeon needs access to your Photos. (NSPhotoLibraryUsageDescription)'; + case 'dialogs.license.androidPermissions.0': return 'Used for data interaction between the application and the server, Homing Pigeon needs access to your Internet. (android.permission.INTERNET)'; + case 'dialogs.license.androidPermissions.1': return 'In order to send you notifications, Homing Pigeon needs access to your permission. (android.permission.POST_NOTIFICATIONS)'; + case 'dialogs.license.androidPermissions.2': return 'For you to upload pictures, Homing Pigeon needs access to your Storage. (android.permission.READ_EXTERNAL_STORAGE)'; + case 'dialogs.license.androidPermissions.3': return 'For you to save pictures, Homing Pigeon needs access to your Storage. (android.permission.WRITE_EXTERNAL_STORAGE)'; + case 'dialogs.license.androidPermissions.4': return 'For you to upload pictures, Homing Pigeon needs access to your Photos. (android.permission.READ_MEDIA_IMAGES)'; + case 'dialogs.license.androidPermissions.5': return 'For you to upload videos, Homing Pigeon needs access to your Videos. (android.permission.READ_MEDIA_VIDEO)'; + case 'dialogs.license.androidPermissions.6': return 'For you to take pictures, Homing Pigeon needs access to your Camera. (android.permission.CAMERA)'; + case 'dialogs.license.androidPermissions.7': return 'In order to send you local notifications, Homing Pigeon needs access to your permission. (android.permission.RECEIVE_BOOT_COMPLETED)'; + case 'dialogs.album.title': return 'Allow access to your album'; + case 'dialogs.album.description': return 'Please go to your phone Settings to grant Homing Pigeon the permission to visit your album.'; case 'locales.en': return 'English'; case 'locales.zh': return '中文'; default: return null; @@ -375,27 +1747,131 @@ extension on _StringsZh { dynamic _flatMapFunction(String path) { switch (path) { case 'appName': return '信鸽'; - case 'pages.homePage.title': return '信鸽'; + case 'common.copied': return '已复制'; + case 'common.success': return '成功啦😊'; + case 'common.failure': return '失败啦😭'; + case 'common.noData': return '没有数据, 点击以重新加载😭'; + case 'pages.home.primary.title': return '主要功能'; + case 'pages.home.primary.rating.title': return '电影打分系统'; + case 'pages.home.primary.rating.description': return '给看过的电影打个分吧~~'; + case 'pages.home.primary.live.title': return '直播预告'; + case 'pages.home.primary.live.description': return '查看详情'; + case 'pages.home.primary.settings.title': return '开播通知设置'; + case 'pages.home.other.title': return '其他功能'; + case 'pages.home.other.notifications.title': return '直播信息/提醒群'; + case 'pages.home.other.notifications.description': return '直播平台、时间等'; + case 'pages.home.other.store.title': return '小德官方店: 喜瑞斯'; + case 'pages.home.other.store.description': return '寒潮啦! 来件卫衣吧~~'; + case 'pages.home.other.emoji.title': return '小德表情包🐱'; + case 'pages.home.other.emoji.description': return '欢迎投稿~~'; + case 'pages.home.other.feedback.title': return '意见/建议'; + case 'pages.home.other.feedback.description': return '无论您遇到任何问题、意见或建议, 均可反馈...'; + case 'pages.home.other.roadmap.title': return '路线图'; + case 'pages.home.other.roadmap.description': return '查看开发计划和进度😄'; + case 'pages.home.version': return '版本号'; + case 'pages.emoji.title': return '表情库~'; + case 'pages.emoji.tips.title': return '欢迎投稿,嗷呜~'; + case 'pages.emoji.tips.prefix': return '欢迎'; + case 'pages.emoji.tips.button': return ' [点击此处] '; + case 'pages.emoji.tips.suffix': return '投稿,可以是表情包,可以是文案创意,也可以是一些令猫尴尬的图片或截图等~😄'; + case 'pages.emoji.dialogs.upload.buttons.upload': return '上传'; + case 'pages.emoji.dialogs.upload.header': return '请选择要上传的表情'; + case 'pages.emoji.dialogs.upload.tips.prefix': return '您最多可以上传9张图片'; + case 'pages.emoji.dialogs.upload.tips.suffix': return '图片大小必须在50KB到15MB之间'; + case 'pages.emoji.dialogs.upload.form.emojis.errorText': return '请选择要上传的表情'; + case 'pages.emoji.dialogs.upload.uploadFailed': return '文件上传失败😭'; + case 'pages.feedback.title': return '意见或建议'; + case 'pages.feedback.tips.title': return '欢迎提意见或建议,嗷呜~'; + case 'pages.feedback.tips.prefix': return '无论您遇到任何问题、意见或建议,均可'; + case 'pages.feedback.tips.button': return ' [点击此处] '; + case 'pages.feedback.tips.suffix': return '进行反馈.'; + case 'pages.feedback.dialogs.upload.buttons.upload': return '提交'; + case 'pages.feedback.dialogs.upload.header': return '请填写反馈内容'; + case 'pages.feedback.dialogs.upload.form.title.title': return '标题'; + case 'pages.feedback.dialogs.upload.form.title.hintText': return '请输入标题'; + case 'pages.feedback.dialogs.upload.form.title.errorText': return '请输入标题'; + case 'pages.feedback.dialogs.upload.form.description.title': return '描述'; + case 'pages.feedback.dialogs.upload.form.description.hintText': return '请输入描述'; + case 'pages.feedback.dialogs.upload.form.description.errorText': return '请输入描述'; + case 'pages.feedback.dialogs.upload.form.assets.title': return '图片或视频'; + case 'pages.feedback.dialogs.upload.form.assets.prefix': return '您最多可以上传9张图片或视频'; + case 'pages.feedback.dialogs.upload.form.assets.suffix': return '图片大小必须在50KB到15MB之间, 视频大小必须在50KB到20MB之间'; + case 'pages.feedback.dialogs.upload.error.image': return '上传的图片必须在15KB至15MB之间'; + case 'pages.feedback.dialogs.upload.error.video': return '上传的视频必须在15KB至20MB之间'; + case 'pages.feedback.dialogs.upload.uploadFailed': return '文件上传失败😭'; + case 'pages.feedbackDetail.title': return '反馈详情'; + case 'pages.live.title': return '直播~'; + case 'pages.movie.title': return '电影'; + case 'pages.roadmap.title': return '路线图'; + case 'pages.social.title': return '社交'; case 'buttons.agree': return '同意'; case 'buttons.cancel': return '再想想'; - case 'dialogs.licenseDialog.licenseDialogTitle': return '隐私条款'; - case 'dialogs.licenseDialog.licenseDialogContentContent': return '信鸽 非常重视你的隐私保护和个人信息保护.'; - case 'dialogs.licenseDialog.licenseDialogContentTip': return '以下是该APP所需的权限列表:'; - case 'dialogs.licenseDialog.licenseDialogContentPrefix': return '在使用APP服务前,请认真阅读 '; - case 'dialogs.licenseDialog.licenseDialogContentUserAgreement': return '《隐私政策》'; - case 'dialogs.licenseDialog.licenseDialogContentAnd': return '和'; - case 'dialogs.licenseDialog.licenseDialogContentPrivacyAgreement': return '《用户服务协议》'; - case 'dialogs.licenseDialog.licenseDialogContentSuffix': return ', 你同意并接受全部条款后开始使用我们的服务.'; - case 'dialogs.licenseDialog.iosPermissions.0': return '为了让您拍摄照片, 信鸽 需要访问您的相机. (NSCameraUsageDescription)'; - case 'dialogs.licenseDialog.iosPermissions.1': return '为了让您上传图片, 信鸽 需要访问您的照片. (NSPhotoLibraryUsageDescription)'; - case 'dialogs.licenseDialog.androidPermissions.0': return '用于应用程序和服务器之间的数据交互,信鸽 需要访问您的互联网. (android.permission.INTERNET)'; - case 'dialogs.licenseDialog.androidPermissions.1': return '为了给您发送通知, 信鸽 需要获取您的权限. (android.permission.POST_NOTIFICATIONS)'; - case 'dialogs.licenseDialog.androidPermissions.2': return '为了让您上传图片, 信鸽 需要访问您的存储. (android.permission.READ_EXTERNAL_STORAGE)'; - case 'dialogs.licenseDialog.androidPermissions.3': return '为了让您保存图片, 信鸽 需要访问您的存储. (android.permission.WRITE_EXTERNAL_STORAGE)'; - case 'dialogs.licenseDialog.androidPermissions.4': return '为了让您上传图片, 信鸽 需要访问您的照片. (android.permission.READ_MEDIA_IMAGES)'; - case 'dialogs.licenseDialog.androidPermissions.5': return '为了让您上传视频, 信鸽 需要访问您的视频. (android.permission.READ_MEDIA_VIDEO)'; - case 'dialogs.licenseDialog.androidPermissions.6': return '为了让您拍摄照片, 信鸽 需要访问您的相机. (android.permission.CAMERA)'; - case 'dialogs.licenseDialog.androidPermissions.7': return '为了向您发送本地通知, 信鸽 需要访问您的权限. (android.permission.RECEIVE_BOOT_COMPLETED)'; + case 'buttons.login': return '登录'; + case 'buttons.signup': return '注册'; + case 'buttons.logout': return '退出'; + case 'buttons.ignore': return '忽略'; + case 'buttons.turnOn': return '开启'; + case 'buttons.turnOff': return '关闭'; + case 'bottomSheets.login.header': return '请填写登录信息'; + case 'bottomSheets.login.form.account.title': return '账号'; + case 'bottomSheets.login.form.account.hintText': return '请输入账号'; + case 'bottomSheets.login.form.account.errorText': return '请输入账号'; + case 'bottomSheets.login.form.account.errorText2': return '请输入至少8个字符'; + case 'bottomSheets.login.form.password.title': return '密码'; + case 'bottomSheets.login.form.password.hintText': return '请输入密码'; + case 'bottomSheets.login.form.password.errorText': return '请输入密码'; + case 'bottomSheets.login.form.password.errorText2': return '请输入至少8个字符'; + case 'bottomSheets.login.form.privacy.title': return '隐私协议'; + case 'bottomSheets.login.form.privacy.prefix': return '我已仔细阅读并同意'; + case 'bottomSheets.login.form.privacy.privacy': return '隐私政策'; + case 'bottomSheets.login.form.privacy.and': return '以及'; + case 'bottomSheets.login.form.privacy.terms': return '条款和条件'; + case 'bottomSheets.login.form.privacy.errorText': return '请同意隐私协议'; + case 'bottomSheets.login.tips.prefix': return '已有账号, '; + case 'bottomSheets.login.tips.suffix': return '去登录'; + case 'bottomSheets.signup.header': return '请填写注册信息'; + case 'bottomSheets.signup.form.account.helperText': return '只能包含英文, 数字或下划线, 且只能以字母开头, 至少8个字符'; + case 'bottomSheets.signup.form.account.errorText2': return '账号只能包含英文,数字或下划线, 且只能以字母开头, 至少8个字符'; + case 'bottomSheets.signup.form.nickname.title': return '昵称'; + case 'bottomSheets.signup.form.nickname.hintText': return '请输入昵称'; + case 'bottomSheets.signup.form.nickname.helperText': return '不能多于20个字符'; + case 'bottomSheets.signup.form.nickname.errorText': return '昵称长度不能大于20'; + case 'bottomSheets.signup.form.email.title': return '邮箱'; + case 'bottomSheets.signup.form.email.hintText': return '请输入邮箱'; + case 'bottomSheets.signup.form.email.errorText': return '请输入邮箱'; + case 'bottomSheets.signup.form.email.errorText2': return '邮箱格式错误'; + case 'bottomSheets.signup.form.password.helperText': return '请输入至少8个字符'; + case 'bottomSheets.signup.form.repeatPassword.title': return '账号'; + case 'bottomSheets.signup.form.repeatPassword.hintText': return '请再次输入密码'; + case 'bottomSheets.signup.form.repeatPassword.errorText': return '请再次输入密码'; + case 'bottomSheets.signup.form.repeatPassword.errorText2': return '两次输入的密码不一样'; + case 'bottomSheets.signup.tips.prefix': return '还没有账号, '; + case 'bottomSheets.signup.tips.suffix': return '去注册'; + case 'bottomSheets.store.title': return '请选择您的操作'; + case 'bottomSheets.store.code.title': return '复制淘口令'; + case 'bottomSheets.store.code.description': return '直播平台、时间等'; + case 'bottomSheets.store.link.title': return '打开淘宝店地址'; + case 'bottomSheets.store.link.description': return '寒潮啦! 来件卫衣吧~~'; + case 'dialogs.license.title': return '隐私条款'; + case 'dialogs.license.contentContent': return '信鸽 非常重视你的隐私保护和个人信息保护.'; + case 'dialogs.license.contentTip': return '以下是该APP所需的权限列表:'; + case 'dialogs.license.contentPrefix': return '在使用APP服务前,请认真阅读 '; + case 'dialogs.license.contentUserAgreement': return '《隐私政策》'; + case 'dialogs.license.contentAnd': return '和'; + case 'dialogs.license.contentPrivacyAgreement': return '《用户服务协议》'; + case 'dialogs.license.contentSuffix': return ', 你同意并接受全部条款后开始使用我们的服务.'; + case 'dialogs.license.iosPermissions.0': return '为了让您拍摄照片, 信鸽 需要访问您的相机. (NSCameraUsageDescription)'; + case 'dialogs.license.iosPermissions.1': return '为了让您上传图片, 信鸽 需要访问您的照片. (NSPhotoLibraryUsageDescription)'; + case 'dialogs.license.androidPermissions.0': return '用于应用程序和服务器之间的数据交互,信鸽 需要访问您的互联网. (android.permission.INTERNET)'; + case 'dialogs.license.androidPermissions.1': return '为了给您发送通知, 信鸽 需要获取您的权限. (android.permission.POST_NOTIFICATIONS)'; + case 'dialogs.license.androidPermissions.2': return '为了让您上传图片, 信鸽 需要访问您的存储. (android.permission.READ_EXTERNAL_STORAGE)'; + case 'dialogs.license.androidPermissions.3': return '为了让您保存图片, 信鸽 需要访问您的存储. (android.permission.WRITE_EXTERNAL_STORAGE)'; + case 'dialogs.license.androidPermissions.4': return '为了让您上传图片, 信鸽 需要访问您的照片. (android.permission.READ_MEDIA_IMAGES)'; + case 'dialogs.license.androidPermissions.5': return '为了让您上传视频, 信鸽 需要访问您的视频. (android.permission.READ_MEDIA_VIDEO)'; + case 'dialogs.license.androidPermissions.6': return '为了让您拍摄照片, 信鸽 需要访问您的相机. (android.permission.CAMERA)'; + case 'dialogs.license.androidPermissions.7': return '为了向您发送本地通知, 信鸽 需要访问您的权限. (android.permission.RECEIVE_BOOT_COMPLETED)'; + case 'dialogs.album.title': return '允许访问您的相册'; + case 'dialogs.album.description': return '请前往您的手机设置授予信鸽访问您相册的权限.'; case 'locales.en': return 'English'; case 'locales.zh': return '中文'; default: return null; diff --git a/lib/i18n/strings.i18n.json b/lib/i18n/strings.i18n.json index 44629ba0..ca65baeb 100644 --- a/lib/i18n/strings.i18n.json +++ b/lib/i18n/strings.i18n.json @@ -1,24 +1,230 @@ { "appName": "Homing Pigeon", + "common": { + "copied": "Copied", + "success": "Succeeded\uD83D\uDE0A", + "failure": "Failed\uD83D\uDE2D", + "noData": "No data, click to reload\uD83D\uDE2D" + }, "pages": { - "homePage": { - "title": "Homing Pigeon" + "home": { + "primary": { + "title": "Primary", + "rating": { + "title": "Movie rating", + "description": "Rate the movies you’ve watched~~" + }, + "live": { + "title": "Live broadcast preview", + "description": "Go to the details" + }, + "settings": { + "title": "Settings" + } + }, + "other": { + "title": "Others", + "notifications": { + "title": "Reminders", + "description": "Get the live broadcast platform, time, etc." + }, + "store": { + "title": "TAOBAO: Serious", + "description": "The cold wave is coming! Bring on a sweatshirt~~" + }, + "emoji": { + "title": "Emojis\uD83D\uDC31", + "description": "Contributions welcome~~" + }, + "feedback": { + "title": "Feedback", + "description": "No matter you encounter any questions, comments or suggestions, you can give us feedback..." + }, + "roadmap": { + "title": "Roadmap", + "description": "View development plans and progress\uD83D\uDE04" + } + }, + "version": "Version" + }, + "emoji": { + "title": "Emojis~", + "tips": { + "title": "Contributions are welcome, Wow~", + "prefix": "Welcome", + "button": " [click here] ", + "suffix": "to contribute, it can be emoticons, creative copywriting, or some embarrassing pictures or screenshots of cats, etc.\uD83D\uDE04" + }, + "dialogs": { + "upload": { + "buttons": { + "upload": "Upload" + }, + "header": "Please select emojis you want to upload", + "tips": { + "prefix": "You can upload up to 9 images", + "suffix": "Image size must be between 50KB and 15MB" + }, + "form": { + "emojis": { + "errorText": "Please select emojis you want to upload" + } + }, + "uploadFailed": "File upload failed\uD83D\uDE2D" + } + } + }, + "feedback": { + "title": "Feedback", + "tips": { + "title": "Comments or suggestions are welcome, wow~", + "prefix": "No matter you encounter any questions, comments or suggestions, you can", + "button": " [click here] ", + "suffix": "to give feedback." + }, + "dialogs": { + "upload": { + "buttons": { + "upload": "Submit" + }, + "header": "Please fill in the feedback info", + "form": { + "title": { + "title": "Title", + "hintText": "Please enter a title", + "errorText": "Please enter a title" + }, + "description": { + "title": "Description", + "hintText": "Please enter a description", + "errorText": "Please enter a description" + }, + "assets": { + "title": "Picture or video", + "prefix": "You can upload up to 9 pictures or videos", + "suffix": "Image size must be between 50KB and 15MB, video size must be between 50KB and 20MB" + } + }, + "error": { + "image": "Uploaded images must be between 15KB and 15MB", + "video": "Uploaded videos must be between 15KB and 15MB" + }, + "uploadFailed": "文件上传失败\uD83D\uDE2D" + } + } + }, + "feedbackDetail": { + "title": "Feedback details" + }, + "live": { + "title": "Live streaming~" + }, + "movie": { + "title": "Movie" + }, + "roadmap": { + "title": "Roadmap" + }, + "social": { + "title": "Social" } }, "buttons": { "agree": "Agree", - "cancel": "Cancel" + "cancel": "Cancel", + "login": "Login", + "signup": "Sign up", + "logout": "Logout", + "ignore": "Ignore", + "turnOn": "Turn on", + "turnOff": "Turn off" + }, + "bottomSheets": { + "login": { + "header": "Please fill in your login information", + "form": { + "account": { + "title": "Account", + "hintText": "Please enter your account", + "errorText": "Please enter your account", + "errorText2": "Please enter at least 8 characters" + }, + "password": { + "title": "Password", + "hintText": "Please enter your password", + "errorText": "Please enter your password", + "errorText2": "Please enter at least 8 characters" + }, + "privacy": { + "title": "Privacy", + "prefix": "I have read carefully and agree", + "privacy": " Privacy Policy ", + "and": "&", + "terms": " terms and Conditions", + "errorText": "Please agree to the privacy agreement" + } + }, + "tips": { + "prefix": "Already have an account, ", + "suffix": "go to login" + } + }, + "signup": { + "header": "Please fill in the registration information", + "form": { + "account": { + "helperText": "The account number can only contain letters, numbers or underscores, and can only start with a letter and be at least 8 characters long.", + "errorText2": "The account number can only contain letters, numbers or underscores, and can only start with a letter and be at least 8 characters long." + }, + "nickname": { + "title": "Nickname", + "hintText": "Please enter your nickname", + "helperText": "Nickname cannot be longer than 20 characters", + "errorText": "Nickname cannot be longer than 20 characters" + }, + "email": { + "title": "Email", + "hintText": "Please enter your email", + "errorText": "Please enter your email", + "errorText2": "The email format you entered is wrong" + }, + "password": { + "helperText": "Please enter at least 8 characters" + }, + "repeatPassword": { + "title": "Repeat password", + "hintText": "Please enter your password again", + "errorText": "Please enter your password again", + "errorText2": "The passwords entered twice are different" + } + }, + "tips": { + "prefix": "No account yet, ", + "suffix": "go to register" + } + }, + "store": { + "title": "Please select to continue", + "code": { + "title": "Copy Taobao code", + "description": "Get the live broadcast platform, time, etc." + }, + "link": { + "title": "Open store link", + "description": "The cold wave is coming! Bring on a sweatshirt~~" + } + } }, "dialogs": { - "licenseDialog": { - "licenseDialogTitle": "Terms and Conditions", - "licenseDialogContentContent": "Protecting user's privacy and personal information is a fundamental principle of Homing Pigeon.", - "licenseDialogContentTip": "Below is a list of permissions required by this APP:", - "licenseDialogContentPrefix": "Before you use this APP's services, please carefully read and agree to the ", - "licenseDialogContentUserAgreement": "User Agreement", - "licenseDialogContentAnd": " and ", - "licenseDialogContentPrivacyAgreement": "Privacy Agreement", - "licenseDialogContentSuffix": ", start using our services after you agree and accept all terms.", + "license": { + "title": "Terms and Conditions", + "contentContent": "Protecting user's privacy and personal information is a fundamental principle of Homing Pigeon.", + "contentTip": "Below is a list of permissions required by this APP:", + "contentPrefix": "Before you use this APP's services, please carefully read and agree to the ", + "contentUserAgreement": "User Agreement", + "contentAnd": " and ", + "contentPrivacyAgreement": "Privacy Agreement", + "contentSuffix": ", start using our services after you agree and accept all terms.", "iosPermissions": [ "For you to take pictures, Homing Pigeon needs access to your Camera. (NSCameraUsageDescription)", "For you to upload pictures, Homing Pigeon needs access to your Photos. (NSPhotoLibraryUsageDescription)" @@ -33,6 +239,10 @@ "For you to take pictures, Homing Pigeon needs access to your Camera. (android.permission.CAMERA)", "In order to send you local notifications, Homing Pigeon needs access to your permission. (android.permission.RECEIVE_BOOT_COMPLETED)" ] + }, + "album": { + "title": "Allow access to your album", + "description": "Please go to your phone Settings to grant Homing Pigeon the permission to visit your album." } }, "locales(map)": { diff --git a/lib/i18n/strings_zh.i18n.json b/lib/i18n/strings_zh.i18n.json index b7296a35..a2e2cc46 100644 --- a/lib/i18n/strings_zh.i18n.json +++ b/lib/i18n/strings_zh.i18n.json @@ -1,24 +1,230 @@ { "appName": "信鸽", + "common": { + "copied": "已复制", + "success": "成功啦\uD83D\uDE0A", + "failure": "失败啦\uD83D\uDE2D", + "noData": "没有数据, 点击以重新加载\uD83D\uDE2D" + }, "pages": { - "homePage": { - "title": "信鸽" + "home": { + "primary": { + "title": "主要功能", + "rating": { + "title": "电影打分系统", + "description": "给看过的电影打个分吧~~" + }, + "live": { + "title": "直播预告", + "description": "查看详情" + }, + "settings": { + "title": "开播通知设置" + } + }, + "other": { + "title": "其他功能", + "notifications": { + "title": "直播信息/提醒群", + "description": "直播平台、时间等" + }, + "store": { + "title": "小德官方店: 喜瑞斯", + "description": "寒潮啦! 来件卫衣吧~~" + }, + "emoji": { + "title": "小德表情包\uD83D\uDC31", + "description": "欢迎投稿~~" + }, + "feedback": { + "title": "意见/建议", + "description": "无论您遇到任何问题、意见或建议, 均可反馈..." + }, + "roadmap": { + "title": "路线图", + "description": "查看开发计划和进度\uD83D\uDE04" + } + }, + "version": "版本号" + }, + "emoji": { + "title": "表情库~", + "tips": { + "title": "欢迎投稿,嗷呜~", + "prefix": "欢迎", + "button": " [点击此处] ", + "suffix": "投稿,可以是表情包,可以是文案创意,也可以是一些令猫尴尬的图片或截图等~\uD83D\uDE04" + }, + "dialogs": { + "upload": { + "buttons": { + "upload": "上传" + }, + "header": "请选择要上传的表情", + "tips": { + "prefix": "您最多可以上传9张图片", + "suffix": "图片大小必须在50KB到15MB之间" + }, + "form": { + "emojis": { + "errorText": "请选择要上传的表情" + } + }, + "uploadFailed": "文件上传失败\uD83D\uDE2D" + } + } + }, + "feedback": { + "title": "意见或建议", + "tips": { + "title": "欢迎提意见或建议,嗷呜~", + "prefix": "无论您遇到任何问题、意见或建议,均可", + "button": " [点击此处] ", + "suffix": "进行反馈." + }, + "dialogs": { + "upload": { + "buttons": { + "upload": "提交" + }, + "header": "请填写反馈内容", + "form": { + "title": { + "title": "标题", + "hintText": "请输入标题", + "errorText": "请输入标题" + }, + "description": { + "title": "描述", + "hintText": "请输入描述", + "errorText": "请输入描述" + }, + "assets": { + "title": "图片或视频", + "prefix": "您最多可以上传9张图片或视频", + "suffix": "图片大小必须在50KB到15MB之间, 视频大小必须在50KB到20MB之间" + } + }, + "error": { + "image": "上传的图片必须在15KB至15MB之间", + "video": "上传的视频必须在15KB至20MB之间" + }, + "uploadFailed": "文件上传失败\uD83D\uDE2D" + } + } + }, + "feedbackDetail": { + "title": "反馈详情" + }, + "live": { + "title": "直播~" + }, + "movie": { + "title": "电影" + }, + "roadmap": { + "title": "路线图" + }, + "social": { + "title": "社交" } }, "buttons": { "agree": "同意", - "cancel": "再想想" + "cancel": "再想想", + "login": "登录", + "signup": "注册", + "logout": "退出", + "ignore": "忽略", + "turnOn": "开启", + "turnOff": "关闭" + }, + "bottomSheets": { + "login": { + "header": "请填写登录信息", + "form": { + "account": { + "title": "账号", + "hintText": "请输入账号", + "errorText": "请输入账号", + "errorText2": "请输入至少8个字符" + }, + "password": { + "title": "密码", + "hintText": "请输入密码", + "errorText": "请输入密码", + "errorText2": "请输入至少8个字符" + }, + "privacy": { + "title": "隐私协议", + "prefix": "我已仔细阅读并同意", + "privacy": "隐私政策", + "and": "以及", + "terms": "条款和条件", + "errorText": "请同意隐私协议" + } + }, + "tips": { + "prefix": "已有账号, ", + "suffix": "去登录" + } + }, + "signup": { + "header": "请填写注册信息", + "form": { + "account": { + "helperText": "只能包含英文, 数字或下划线, 且只能以字母开头, 至少8个字符", + "errorText2": "账号只能包含英文,数字或下划线, 且只能以字母开头, 至少8个字符" + }, + "nickname": { + "title": "昵称", + "hintText": "请输入昵称", + "helperText": "不能多于20个字符", + "errorText": "昵称长度不能大于20" + }, + "email": { + "title": "邮箱", + "hintText": "请输入邮箱", + "errorText": "请输入邮箱", + "errorText2": "邮箱格式错误" + }, + "password": { + "helperText": "请输入至少8个字符" + }, + "repeatPassword": { + "title": "账号", + "hintText": "请再次输入密码", + "errorText": "请再次输入密码", + "errorText2": "两次输入的密码不一样" + } + }, + "tips": { + "prefix": "还没有账号, ", + "suffix": "去注册" + } + }, + "store": { + "title": "请选择您的操作", + "code": { + "title": "复制淘口令", + "description": "直播平台、时间等" + }, + "link": { + "title": "打开淘宝店地址", + "description": "寒潮啦! 来件卫衣吧~~" + } + } }, "dialogs": { - "licenseDialog": { - "licenseDialogTitle": "隐私条款", - "licenseDialogContentContent": "信鸽 非常重视你的隐私保护和个人信息保护.", - "licenseDialogContentTip": "以下是该APP所需的权限列表:", - "licenseDialogContentPrefix": "在使用APP服务前,请认真阅读 ", - "licenseDialogContentUserAgreement": "《隐私政策》", - "licenseDialogContentAnd": "和", - "licenseDialogContentPrivacyAgreement": "《用户服务协议》", - "licenseDialogContentSuffix": ", 你同意并接受全部条款后开始使用我们的服务.", + "license": { + "title": "隐私条款", + "contentContent": "信鸽 非常重视你的隐私保护和个人信息保护.", + "contentTip": "以下是该APP所需的权限列表:", + "contentPrefix": "在使用APP服务前,请认真阅读 ", + "contentUserAgreement": "《隐私政策》", + "contentAnd": "和", + "contentPrivacyAgreement": "《用户服务协议》", + "contentSuffix": ", 你同意并接受全部条款后开始使用我们的服务.", "iosPermissions": [ "为了让您拍摄照片, 信鸽 需要访问您的相机. (NSCameraUsageDescription)", "为了让您上传图片, 信鸽 需要访问您的照片. (NSPhotoLibraryUsageDescription)" @@ -33,6 +239,10 @@ "为了让您拍摄照片, 信鸽 需要访问您的相机. (android.permission.CAMERA)", "为了向您发送本地通知, 信鸽 需要访问您的权限. (android.permission.RECEIVE_BOOT_COMPLETED)" ] + }, + "album": { + "title": "允许访问您的相册", + "description": "请前往您的手机设置授予信鸽访问您相册的权限." } }, "locales(map)": { diff --git a/lib/main_common.dart b/lib/main_common.dart index 83cd1189..8814dbdf 100644 --- a/lib/main_common.dart +++ b/lib/main_common.dart @@ -202,9 +202,6 @@ Future runMainApp() async { ); } - // initialize with the right locale - LocaleSettings.useDeviceLocale(); - // TODO(kjxbyz): FIXME: upgrade socket_io_client to 3.0.0 final socket = socket_io.io( Constants.wsPrefix, @@ -297,6 +294,9 @@ Future runMainApp() async { ); } + // initialize with the right locale + LocaleSettings.useDeviceLocale(); + runApp(TranslationProvider(child: child)); } diff --git a/lib/main_external.dart b/lib/main_external.dart index 6e27599e..734db46f 100644 --- a/lib/main_external.dart +++ b/lib/main_external.dart @@ -1,13 +1,13 @@ import 'dart:async'; import 'package:flutter/widgets.dart'; +import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:homing_pigeon/app/config.dart'; import 'package:homing_pigeon/main_common.dart'; Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - AppConfig.create( - flavor: Flavor.external, - ); + final widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); + FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); + AppConfig.create(flavor: Flavor.external); await runMainApp(); } diff --git a/lib/main_internal.dart b/lib/main_internal.dart index 39e1fe20..7bc7a37e 100644 --- a/lib/main_internal.dart +++ b/lib/main_internal.dart @@ -1,11 +1,13 @@ import 'dart:async'; import 'package:flutter/widgets.dart'; +import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:homing_pigeon/app/config.dart'; import 'package:homing_pigeon/main_common.dart'; Future main() async { - WidgetsFlutterBinding.ensureInitialized(); + final widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); + FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); AppConfig.create(); await runMainApp(); } diff --git a/lib/modules/app/views/app_view.dart b/lib/modules/app/views/app_view.dart index 2597b85c..162b3ce9 100644 --- a/lib/modules/app/views/app_view.dart +++ b/lib/modules/app/views/app_view.dart @@ -1,21 +1,26 @@ +import 'package:async/async.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_native_splash/flutter_native_splash.dart'; +import 'package:homing_pigeon/app/config.dart'; import 'package:homing_pigeon/app/manager.dart'; import 'package:homing_pigeon/app/navigator.dart'; -import 'package:homing_pigeon/common/api/auth_api.dart'; +// import 'package:homing_pigeon/common/api/auth_api.dart'; import 'package:homing_pigeon/common/api/config_api.dart'; import 'package:homing_pigeon/common/constants/constants.dart'; import 'package:homing_pigeon/common/constants/keys.dart'; +import 'package:homing_pigeon/common/extensions/single.dart'; import 'package:homing_pigeon/common/http/utils/handle_errors.dart'; import 'package:homing_pigeon/common/utils/run_once.dart'; import 'package:homing_pigeon/common/utils/sp_util.dart'; -import 'package:homing_pigeon/common/utils/string_util.dart'; import 'package:homing_pigeon/i18n/i18n.dart'; import 'package:homing_pigeon/modules/app/app.dart'; import 'package:homing_pigeon/modules/home/home.dart'; +import 'package:homing_pigeon/theme/colors.dart'; import 'package:homing_pigeon/theme/theme.dart'; +import 'package:jpush_flutter2/jpush_flutter2.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:upgrader/upgrader.dart'; @@ -45,6 +50,9 @@ const double offset = 20; class _AppViewState extends State { final easyLoading = EasyLoading.init(); + final _memoizer = AsyncMemoizer(); + Future? _future; + @override void initState() { super.initState(); @@ -53,69 +61,90 @@ class _AppViewState extends State { @override Widget build(BuildContext context) { - return MaterialApp( - debugShowCheckedModeBanner: false, - navigatorKey: AppNavigator.key, - theme: AppTheme.light, - darkTheme: AppTheme.dark, - locale: TranslationProvider.of(context).flutterLocale, - supportedLocales: AppLocaleUtils.supportedLocales, - localizationsDelegates: GlobalMaterialLocalizations.delegates, - navigatorObservers: [ - if (Constants.sentryEnabled) SentryNavigatorObserver(), - ], - home: UpgradeAlert( + return BlocBuilder( + builder: (context, state) => MaterialApp( + debugShowCheckedModeBanner: false, navigatorKey: AppNavigator.key, - child: navigateToPage(context), + theme: AppTheme.light, + darkTheme: AppTheme.dark, + locale: TranslationProvider.of(context).flutterLocale, + supportedLocales: AppLocaleUtils.supportedLocales, + localizationsDelegates: GlobalMaterialLocalizations.delegates, + navigatorObservers: [ + if (Constants.sentryEnabled) SentryNavigatorObserver(), + ], + home: FutureBuilder( + future: _future ??= navigateToPage(), + builder: ( + BuildContext context, + AsyncSnapshot snapshot, + ) { + if (snapshot.connectionState == ConnectionState.done) { + final child = snapshot.data; + return UpgradeAlert(child: child); + } else { + // 请求未结束,显示loading + return const Center( + child: CircularProgressIndicator( + color: primaryColor, + ), + ).nestedColoredBox(color: Colors.white); + } + }, + ), + builder: (BuildContext context, Widget? child) { + final isDark = Theme.of(context).brightness == Brightness.dark; + EasyLoading.instance.loadingStyle = + isDark ? EasyLoadingStyle.light : EasyLoadingStyle.dark; + final newChild = easyLoading(context, child); + return MediaQuery( + /// 设置文字大小不随系统设置改变 + data: MediaQuery.of(context).copyWith( + textScaler: TextScaler.noScaling, + ), + child: newChild, + ); + }, ), - builder: (BuildContext context, Widget? child) { - final isDark = Theme.of(context).brightness == Brightness.dark; - EasyLoading.instance.loadingStyle = - isDark ? EasyLoadingStyle.light : EasyLoadingStyle.dark; - final newChild = easyLoading(context, child); - return MediaQuery( - /// 设置文字大小不随系统设置改变 - data: - MediaQuery.of(context).copyWith(textScaler: TextScaler.noScaling), - child: newChild, - ); - }, ); } - Widget navigateToPage(BuildContext context) { - final user = BlocProvider.of(context).state.user; - final token = SpUtil.getString(Keys.tokenKey); + Future navigateToPage() async { + return _memoizer.runOnce(() async { + try { + // final res = await AuthApi.profile(); - AppView.runOnce(() { - if (StringUtil.isNotBlank(token)) { - /// 设置消息推送收集开关 - // if (Platform.isIOS || - // (Platform.isAndroid && AppConfig.shared.isInternal)) { - // JPushFlutter.setAuth(auth: true); - // } + // remove the splash screen + FlutterNativeSplash.remove(); + + if (AppConfig.shared.isInternal) { + final licenseValue = SpUtil.getBool(Keys.licenseKey) ?? true; + await JPushFlutter.setAuth(auth: licenseValue); + } - if (user == null) { - AuthApi.profile().then((value) { - if (value != null) { - BlocProvider.of(context).addUser(value); + // if (res != null) { + // BlocProvider.of(context).addUser(res); - if (!AppManager.instance.jPushInitialized) { - initJPush(); - } + AppView.runOnce(() { + if (AppConfig.shared.isInternal && + !AppManager.instance.jPushInitialized) { + initJPush(); + } - if (!AppManager.instance.firebaseInitialized) { - initFirebase(); - } + if (AppConfig.shared.isExternal && + !AppManager.instance.firebaseInitialized) { + initFirebase(); } - }).onError((error, stackTrace) { - ErrorHandler.handle(error, stackTrace: stackTrace); }); - } + // } + } on Exception catch (error, stackTrace) { + // remove the splash screen + FlutterNativeSplash.remove(); + ErrorHandler.handle(error, stackTrace: stackTrace); } - }); - return const HomeView(); + return const HomeView(); + }); } void _loadConfigs() { diff --git a/lib/modules/detail/views/emoji_view.dart b/lib/modules/detail/views/emoji_view.dart index 88bbd6fb..70a838a9 100644 --- a/lib/modules/detail/views/emoji_view.dart +++ b/lib/modules/detail/views/emoji_view.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; +import 'package:homing_pigeon/app/navigator.dart'; import 'package:homing_pigeon/common/api/emoji_api.dart'; import 'package:homing_pigeon/common/enums/enums.dart'; import 'package:homing_pigeon/common/exception/exception.dart'; @@ -21,6 +22,7 @@ import 'package:homing_pigeon/common/utils/string_util.dart'; import 'package:homing_pigeon/common/utils/upload_util.dart'; import 'package:homing_pigeon/common/widgets/header.dart'; import 'package:homing_pigeon/common/widgets/widgets.dart'; +import 'package:homing_pigeon/i18n/i18n.dart'; import 'package:homing_pigeon/modules/detail/detail.dart'; import 'package:homing_pigeon/theme/colors.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -62,18 +64,19 @@ class _EmojiViewState extends State { @override Widget build(BuildContext context) { + final t = Translations.of(context); final isDark = Theme.of(context).brightness == Brightness.dark; final bottom = MediaQuery.of(context).padding.bottom; return Scaffold( appBar: HpAppBar( isDark: isDark, - titleName: '表情库~', + titleName: t.pages.emoji.title, ), body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '欢迎投稿,嗷呜~', + t.pages.emoji.tips.title, style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, @@ -89,14 +92,14 @@ class _EmojiViewState extends State { color: isDark ? Colors.white : primaryTextColor, ), children: [ - const TextSpan(text: '欢迎'), + TextSpan(text: t.pages.emoji.tips.prefix), TextSpan( - text: ' [点击此处] ', + text: t.pages.emoji.tips.button, recognizer: TapGestureRecognizer() ..onTap = showUploadBottomSheet, style: const TextStyle(color: primaryColor), ), - const TextSpan(text: '投稿,可以是表情包,可以是文案创意,也可以是一些令猫尴尬的图片或截图等~😄'), + TextSpan(text: t.pages.emoji.tips.suffix), ], ), ).nestedPadding(padding: const EdgeInsets.only(bottom: 10)), @@ -120,6 +123,7 @@ class _EmojiViewState extends State { } Widget _buildBody() { + final t = Translations.of(context); final bottom = MediaQuery.of(context).padding.bottom; if (!loading && items.isNotEmpty) { return MasonryGridView.count( @@ -158,9 +162,9 @@ class _EmojiViewState extends State { tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), onPressed: _load, - child: const Text( - '没有数据, 点击以重新加载', - style: TextStyle( + child: Text( + t.common.noData, + style: const TextStyle( fontSize: 12, color: placeholderTextColor, ), @@ -175,6 +179,7 @@ class _EmojiViewState extends State { void showUploadBottomSheet() { const spacing = 8.0; const padding = 10.0; + final t = Translations.of(context); final width = MediaQuery.sizeOf(context).width; final height = MediaQuery.sizeOf(context).height; final top = MediaQuery.of(context).padding.top; @@ -194,46 +199,46 @@ class _EmojiViewState extends State { final items = _fileWrappers .mapIndexed( (index, element) { - if (kDebugMode) { - print(element.file.path); - } - return Stack( - children: [ - Image.file( - element.file, - fit: BoxFit.cover, - errorBuilder: (context, url, error) => const Icon( - Icons.error, - color: errorTextColor, - size: 24, - ), - ).nestedSizedBox(width: itemWidth, height: itemWidth), - Positioned( - top: 2, - right: 2, - child: const Icon( - Icons.clear, - color: warnTextColor, - size: 14, - ) - .nestedDecoratedBox( - decoration: BoxDecoration( - color: backgroundColor, - borderRadius: BorderRadius.circular(9), - ), - ) - .nestedSizedBox(width: 18, height: 18) - .nestedTap( - () => setInnerState( - () => _fileWrappers = _fileWrappers - ..removeAt(index), + if (kDebugMode) { + print(element.file.path); + } + return Stack( + children: [ + Image.file( + element.file, + fit: BoxFit.cover, + errorBuilder: (context, url, error) => const Icon( + Icons.error, + color: errorTextColor, + size: 24, + ), + ).nestedSizedBox(width: itemWidth, height: itemWidth), + Positioned( + top: 2, + right: 2, + child: const Icon( + Icons.clear, + color: warnTextColor, + size: 14, + ) + .nestedDecoratedBox( + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(9), + ), + ) + .nestedSizedBox(width: 18, height: 18) + .nestedTap( + () => setInnerState( + () => _fileWrappers = _fileWrappers + ..removeAt(index), + ), + ), ), - ), - ), - ], - ); - }, - ) + ], + ); + }, + ) .cast() .toList(); @@ -245,7 +250,9 @@ class _EmojiViewState extends State { color: primaryColor, ) .nestedCenter() - .nestedColoredBox(color: isDark ? secondaryTextColor : primaryGrayColor) + .nestedColoredBox( + color: isDark ? secondaryTextColor : primaryGrayColor, + ) .nestedSizedBox(width: itemWidth, height: itemWidth) .nestedInkWell(onTap: () => _pickImages(setInnerState)), ); @@ -253,27 +260,29 @@ class _EmojiViewState extends State { return ModalBottomSheet( callback: _uploadFiles, - buttonText: '上传', + buttonText: t.pages.emoji.dialogs.upload.buttons.upload, constraints: BoxConstraints( minHeight: 350, maxHeight: (height - top - bottom) * 0.7, ), - header: const HpHeader(title: '请选择要上传的表情'), + header: HpHeader(title: t.pages.emoji.dialogs.upload.header), items: [ - const Text.rich( + Text.rich( TextSpan( children: [ - TextSpan(text: '您最多可以上传9张图片('), TextSpan( - text: '图片大小必须在50KB到15MB之间', - style: TextStyle( + text: '${t.pages.emoji.dialogs.upload.tips.prefix}(', + ), + TextSpan( + text: t.pages.emoji.dialogs.upload.tips.suffix, + style: const TextStyle( color: warnTextColor, ), ), - TextSpan(text: ')'), + const TextSpan(text: ')'), ], ), - style: TextStyle( + style: const TextStyle( fontSize: 12, color: placeholderTextColor, ), @@ -294,7 +303,8 @@ class _EmojiViewState extends State { autovalidateMode: AutovalidateMode.onUserInteraction, validator: (value) { if (value == null || value.isEmpty) { - return '请选择上传的图片'; + return t + .pages.emoji.dialogs.upload.form.emojis.errorText; } return null; }, @@ -363,12 +373,12 @@ class _EmojiViewState extends State { .contains(status), ); if (denied) { + final t = Translations.of(AppNavigator.key.currentContext!); DialogUtil.showCustomDialog( - title: 'Allow access to your album', - content: - 'Please go to your phone Settings to grant Homing Pigeon the permission to visit your album.', - cancelText: 'Ignore', - okText: 'Turn On', + title: t.dialogs.album.title, + content: t.dialogs.album.description, + cancelText: t.buttons.ignore, + okText: t.buttons.turnOn, onOK: () async { NavigatorUtil.pop(); await AppSettings.openAppSettings(); @@ -408,8 +418,9 @@ class _EmojiViewState extends State { }, ); if (limiter != null) { + final t = Translations.of(AppNavigator.key.currentContext!); await EasyLoading.showToast( - '上传的图片必须在15KB至15MB之间.', + t.pages.emoji.dialogs.upload.tips.suffix, ); return; } @@ -430,6 +441,7 @@ class _EmojiViewState extends State { Future _uploadFiles() async { if (_formKey.currentState!.validate()) { + final t = Translations.of(context); try { final uploadFileFutures = _fileWrappers .map( @@ -441,7 +453,9 @@ class _EmojiViewState extends State { final fileModels = (await Future.wait(uploadFileFutures)).whereNotNull().toList(); if (fileModels.isEmpty) { - await EasyLoading.showToast('File upload failed'); + await EasyLoading.showToast( + t.pages.emoji.dialogs.upload.uploadFailed, + ); return; } final emojis = fileModels @@ -455,7 +469,7 @@ class _EmojiViewState extends State { ) .toList(); await EmojiApi.multiAddEmoji(emojis); - await EasyLoading.showSuccess('Success'); + await EasyLoading.showSuccess(t.common.success); NavigatorUtil.pop(); _load(); } on Exception catch (error, stackTrace) { @@ -463,7 +477,7 @@ class _EmojiViewState extends State { error, stackTrace: stackTrace, postProcessor: (_, msg) { - EasyLoading.showError(msg ?? 'Failure'); + EasyLoading.showError(msg ?? t.common.failure); }, ); } @@ -514,13 +528,15 @@ class _EmojiViewState extends State { } }, ).onError((error, stackTrace) { + final context = AppNavigator.key.currentContext!; + final t = Translations.of(context); ErrorHandler.handle( error, stackTrace: stackTrace, postProcessor: (_, msg) { if (operation == Operation.none) { setState(() => loading = false); - EasyLoading.showError(msg ?? 'Failure'); + EasyLoading.showError(msg ?? t.common.failure); } else if (operation == Operation.refresh) { _controller.finishRefresh(IndicatorResult.fail); } else if (operation == Operation.load) { diff --git a/lib/modules/detail/views/feedback_detail_view.dart b/lib/modules/detail/views/feedback_detail_view.dart index dc45066e..f8362345 100644 --- a/lib/modules/detail/views/feedback_detail_view.dart +++ b/lib/modules/detail/views/feedback_detail_view.dart @@ -2,6 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:easy_refresh/easy_refresh.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:homing_pigeon/app/navigator.dart'; import 'package:homing_pigeon/common/api/feedback_api.dart'; import 'package:homing_pigeon/common/enums/enums.dart'; import 'package:homing_pigeon/common/extensions/extensions.dart'; @@ -9,6 +10,7 @@ import 'package:homing_pigeon/common/http/utils/handle_errors.dart'; import 'package:homing_pigeon/common/models/models.dart'; import 'package:homing_pigeon/common/utils/string_util.dart'; import 'package:homing_pigeon/common/widgets/widgets.dart'; +import 'package:homing_pigeon/i18n/i18n.dart'; import 'package:homing_pigeon/theme/colors.dart'; import 'package:reorderables/reorderables.dart'; @@ -67,12 +69,13 @@ class _FeedbackDetailViewState extends State { @override Widget build(BuildContext context) { + final t = Translations.of(context); final isDark = Theme.of(context).brightness == Brightness.dark; final bottom = MediaQuery.of(context).padding.bottom; return Scaffold( appBar: HpAppBar( isDark: isDark, - titleName: '反馈详情', + titleName: t.pages.feedbackDetail.title, ), body: EasyRefresh( controller: _controller, @@ -90,6 +93,7 @@ class _FeedbackDetailViewState extends State { } Widget _buildBody() { + final t = Translations.of(context); final isDark = Theme.of(context).brightness == Brightness.dark; final height = MediaQuery.sizeOf(context).height; final top = MediaQuery.of(context).padding.top; @@ -193,9 +197,9 @@ class _FeedbackDetailViewState extends State { tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), onPressed: _load, - child: const Text( - '没有数据, 点击以重新加载', - style: TextStyle( + child: Text( + t.common.noData, + style: const TextStyle( fontSize: 12, color: placeholderTextColor, ), @@ -230,13 +234,14 @@ class _FeedbackDetailViewState extends State { } }, ).onError((error, stackTrace) { + final t = Translations.of(AppNavigator.key.currentContext!); ErrorHandler.handle( error, stackTrace: stackTrace, postProcessor: (_, msg) { if (operation == Operation.none) { setState(() => _loading = false); - EasyLoading.showError(msg ?? 'Failure'); + EasyLoading.showError(msg ?? t.common.failure); } else if (operation == Operation.refresh) { _controller.finishRefresh(IndicatorResult.fail); } diff --git a/lib/modules/detail/views/feedback_view.dart b/lib/modules/detail/views/feedback_view.dart index efc73632..1ff60acb 100644 --- a/lib/modules/detail/views/feedback_view.dart +++ b/lib/modules/detail/views/feedback_view.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:form_builder_validators/form_builder_validators.dart'; +import 'package:homing_pigeon/app/navigator.dart'; import 'package:homing_pigeon/common/api/feedback_api.dart'; import 'package:homing_pigeon/common/enums/enums.dart'; import 'package:homing_pigeon/common/exception/exception.dart'; @@ -21,6 +22,7 @@ import 'package:homing_pigeon/common/utils/string_util.dart'; import 'package:homing_pigeon/common/utils/upload_util.dart'; import 'package:homing_pigeon/common/widgets/header.dart'; import 'package:homing_pigeon/common/widgets/widgets.dart'; +import 'package:homing_pigeon/i18n/i18n.dart'; import 'package:homing_pigeon/modules/detail/detail.dart'; import 'package:homing_pigeon/theme/colors.dart'; import 'package:keyboard_dismisser/keyboard_dismisser.dart'; @@ -70,19 +72,20 @@ class _FeedbackViewState extends State { @override Widget build(BuildContext context) { + final t = Translations.of(context); final isDark = Theme.of(context).brightness == Brightness.dark; final bottom = MediaQuery.of(context).padding.bottom; return Scaffold( resizeToAvoidBottomInset: false, appBar: HpAppBar( isDark: isDark, - titleName: '意见或建议', + titleName: t.pages.feedback.title, ), body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '欢迎提意见或建议,嗷呜~', + t.pages.feedback.tips.title, style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, @@ -94,16 +97,16 @@ class _FeedbackViewState extends State { Text.rich( TextSpan( children: [ - const TextSpan(text: '无论您遇到任何问题、意见或建议,均可'), + TextSpan(text: t.pages.feedback.tips.prefix), TextSpan( - text: '[点击此处]', + text: t.pages.feedback.tips.button, style: const TextStyle( color: primaryColor, ), recognizer: TapGestureRecognizer() ..onTap = showUploadBottomSheet, ), - const TextSpan(text: '进行反馈。'), + TextSpan(text: t.pages.feedback.tips.suffix), ], ), style: TextStyle( @@ -172,6 +175,7 @@ class _FeedbackViewState extends State { } if (!loading && items.isEmpty) { + final t = Translations.of(context); final height = MediaQuery.sizeOf(context).height; return NoData( icon: IconButton.outlined( @@ -194,9 +198,9 @@ class _FeedbackViewState extends State { tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), onPressed: _load, - child: const Text( - '没有数据, 点击以重新加载', - style: TextStyle( + child: Text( + t.common.noData, + style: const TextStyle( fontSize: 12, color: placeholderTextColor, ), @@ -211,6 +215,7 @@ class _FeedbackViewState extends State { void showUploadBottomSheet() { const spacing = 8.0; const padding = 10.0; + final t = Translations.of(context); final width = MediaQuery.sizeOf(context).width; final height = MediaQuery.sizeOf(context).height; final top = MediaQuery.of(context).padding.top; @@ -295,15 +300,15 @@ class _FeedbackViewState extends State { maxHeight: (height - top - bottom) * 0.7, ), callback: _submit, - buttonText: '提交', - header: const HpHeader(title: '请填写反馈内容'), + buttonText: t.pages.feedback.dialogs.upload.buttons.upload, + header: HpHeader(title: t.pages.feedback.dialogs.upload.header), items: [ FormBuilder( key: _formKey, child: Column( children: [ BaseFormItem( - title: '标题', + title: t.pages.feedback.dialogs.upload.form.title.title, showTip: false, padding: EdgeInsets.zero, child: FormBuilderField( @@ -352,7 +357,7 @@ class _FeedbackViewState extends State { ), gapPadding: 0, ), - hintText: '请输入标题', + hintText: t.pages.feedback.dialogs.upload.form.title.hintText, helperStyle: const TextStyle( color: secondaryTextColor, fontSize: 10, @@ -390,7 +395,7 @@ class _FeedbackViewState extends State { }, validator: FormBuilderValidators.compose([ FormBuilderValidators.required( - errorText: '请输入标题', + errorText: t.pages.feedback.dialogs.upload.form.title.errorText, ), ]), name: 'title', @@ -399,7 +404,7 @@ class _FeedbackViewState extends State { ), ), BaseFormItem( - title: '描述', + title: t.pages.feedback.dialogs.upload.form.description.title, showTip: false, child: FormBuilderField( focusNode: descriptionFocusNode, @@ -447,7 +452,7 @@ class _FeedbackViewState extends State { ), gapPadding: 0, ), - hintText: '请输入描述', + hintText: t.pages.feedback.dialogs.upload.form.description.hintText, helperStyle: const TextStyle( color: secondaryTextColor, fontSize: 10, @@ -485,7 +490,7 @@ class _FeedbackViewState extends State { }, validator: FormBuilderValidators.compose([ FormBuilderValidators.required( - errorText: '请输入描述', + errorText: t.pages.feedback.dialogs.upload.form.description.errorText, ), ]), name: 'description', @@ -503,26 +508,26 @@ class _FeedbackViewState extends State { ), ), BaseFormItem( - title: '图片或视频', + title: t.pages.feedback.dialogs.upload.form.assets.title, showTip: false, required: false, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text.rich( + Text.rich( TextSpan( children: [ - TextSpan(text: '您最多可以上传9张图片或视频('), + TextSpan(text: '${t.pages.feedback.dialogs.upload.form.assets.prefix}('), TextSpan( - text: '图片大小必须在50KB到15MB之间, 视频大小必须在50KB到20MB之间', - style: TextStyle( + text: t.pages.feedback.dialogs.upload.form.assets.suffix, + style: const TextStyle( color: warnTextColor, ), ), - TextSpan(text: ')'), + const TextSpan(text: ')'), ], ), - style: TextStyle( + style: const TextStyle( fontSize: 12, color: placeholderTextColor, ), @@ -585,12 +590,12 @@ class _FeedbackViewState extends State { ].contains(status), ); if (denied) { + final t = Translations.of(AppNavigator.key.currentContext!); DialogUtil.showCustomDialog( - title: 'Allow access to your album', - content: 'Please go to your phone Settings to grant ' - 'Homing Pigeon the permission to visit your album.', - cancelText: 'Ignore', - okText: 'Turn On', + title: t.dialogs.album.title, + content: t.dialogs.album.description, + cancelText: t.buttons.ignore, + okText: t.buttons.turnOn, onOK: () async { NavigatorUtil.pop(); await AppSettings.openAppSettings(); @@ -637,14 +642,15 @@ class _FeedbackViewState extends State { (await Future.wait(fileWrapperFutures)).whereNotNull().toList(); final limiter = fileWrappers.firstWhereOrNull(tester); if (limiter != null) { + final t = Translations.of(AppNavigator.key.currentContext!); if (limiter.asset.type == AssetType.image) { await EasyLoading.showToast( - '上传的图片必须在15KB至15MB之间.', + t.pages.feedback.dialogs.upload.error.image, ); return; } else if (limiter.asset.type == AssetType.video) { await EasyLoading.showToast( - '上传的视频必须在15KB至20MB之间.', + t.pages.feedback.dialogs.upload.error.video, ); return; } @@ -703,11 +709,12 @@ class _FeedbackViewState extends State { _load(); } } on Exception catch (error, stackTrace) { + final t = Translations.of(AppNavigator.key.currentContext!); ErrorHandler.handle( error, stackTrace: stackTrace, postProcessor: (_, msg) { - EasyLoading.showError(msg ?? 'Failure'); + EasyLoading.showError(msg ?? t.common.failure); }, ); } @@ -764,13 +771,15 @@ class _FeedbackViewState extends State { } }, ).onError((error, stackTrace) { + final context = AppNavigator.key.currentContext!; + final t = Translations.of(context); ErrorHandler.handle( error, stackTrace: stackTrace, postProcessor: (_, msg) { if (operation == Operation.none) { setState(() => loading = false); - EasyLoading.showError(msg ?? 'Failure'); + EasyLoading.showError(msg ?? t.common.failure); } else if (operation == Operation.refresh) { _controller.finishRefresh(IndicatorResult.fail); } else if (operation == Operation.load) { diff --git a/lib/modules/detail/views/live_view.dart b/lib/modules/detail/views/live_view.dart index 701e6e42..337e81c4 100644 --- a/lib/modules/detail/views/live_view.dart +++ b/lib/modules/detail/views/live_view.dart @@ -4,11 +4,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:gap/gap.dart'; +import 'package:homing_pigeon/app/navigator.dart'; import 'package:homing_pigeon/common/enums/enums.dart'; import 'package:homing_pigeon/common/extensions/single.dart'; import 'package:homing_pigeon/common/http/utils/handle_errors.dart'; import 'package:homing_pigeon/common/utils/string_util.dart'; import 'package:homing_pigeon/common/widgets/widgets.dart'; +import 'package:homing_pigeon/i18n/i18n.dart'; import 'package:homing_pigeon/theme/colors.dart'; import 'package:youtube_player_flutter/youtube_player_flutter.dart'; @@ -64,6 +66,7 @@ class _LiveViewState extends State { @override Widget build(BuildContext context) { + final t = Translations.of(context); final bottom = MediaQuery.of(context).padding.bottom; final isDark = Theme.of(context).brightness == Brightness.dark; return YoutubePlayerBuilder( @@ -95,7 +98,7 @@ class _LiveViewState extends State { isDark: isDark, titleName: StringUtil.getValue( _videoMetaData?.title, - defaultVal: 'Live', + defaultVal: t.pages.live.title, ), ), body: EasyRefresh( @@ -110,7 +113,10 @@ class _LiveViewState extends State { //some other widgets if (kDebugMode) ...[ const Gap(10), - ElevatedButton(onPressed: _load, child: const Text('Login')), + ElevatedButton( + onPressed: _load, + child: Text(t.buttons.login), + ), ], ], ), @@ -138,16 +144,18 @@ class _LiveViewState extends State { } } - Future _load({Operation operation = Operation.none}) async { - try { - - } on Exception catch (error, stackTrace) { + Future _load({ + Operation operation = Operation.none, + }) async { + try {} on Exception catch (error, stackTrace) { + final context = AppNavigator.key.currentContext!; + final t = Translations.of(context); ErrorHandler.handle( error, stackTrace: stackTrace, postProcessor: (_, msg) { if (operation == Operation.none) { - EasyLoading.showError(msg ?? 'Failure'); + EasyLoading.showError(msg ?? t.common.failure); } else if (operation == Operation.refresh) { _easyRefreshController.finishRefresh(IndicatorResult.fail); } else if (operation == Operation.load) { diff --git a/lib/modules/detail/views/movie_view.dart b/lib/modules/detail/views/movie_view.dart index 722fb864..46045cd0 100644 --- a/lib/modules/detail/views/movie_view.dart +++ b/lib/modules/detail/views/movie_view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:homing_pigeon/common/widgets/widgets.dart'; +import 'package:homing_pigeon/i18n/i18n.dart'; class MovieView extends StatefulWidget { const MovieView({super.key}); @@ -11,14 +12,15 @@ class MovieView extends StatefulWidget { class _MovieViewState extends State { @override Widget build(BuildContext context) { + final t = Translations.of(context); final isDark = Theme.of(context).brightness == Brightness.dark; return Scaffold( appBar: HpAppBar( isDark: isDark, - titleName: 'Movie', + titleName: t.pages.movie.title, ), - body: const Center( - child: Text('Movie'), + body: Center( + child: Text(t.pages.movie.title), ), ); } diff --git a/lib/modules/detail/views/roadmap_view.dart b/lib/modules/detail/views/roadmap_view.dart index e56bb2d3..ddb50d55 100644 --- a/lib/modules/detail/views/roadmap_view.dart +++ b/lib/modules/detail/views/roadmap_view.dart @@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:homing_pigeon/app/navigator.dart'; import 'package:homing_pigeon/common/api/roadmap_api.dart'; import 'package:homing_pigeon/common/enums/enums.dart'; import 'package:homing_pigeon/common/extensions/single.dart'; @@ -13,6 +14,7 @@ import 'package:homing_pigeon/common/utils/color_util.dart'; import 'package:homing_pigeon/common/utils/navigator_util.dart'; import 'package:homing_pigeon/common/utils/string_util.dart'; import 'package:homing_pigeon/common/widgets/widgets.dart'; +import 'package:homing_pigeon/i18n/i18n.dart'; import 'package:homing_pigeon/theme/colors.dart'; import 'package:markdown/markdown.dart' as md; import 'package:syncfusion_flutter_calendar/calendar.dart'; @@ -89,13 +91,14 @@ class _RoadmapViewState extends State { @override Widget build(BuildContext context) { + final t = Translations.of(context); final isDark = Theme.of(context).brightness == Brightness.dark; final height = MediaQuery.sizeOf(context).height; final top = MediaQuery.of(context).padding.top; return Scaffold( appBar: HpAppBar( isDark: isDark, - titleName: '路线图', + titleName: t.pages.roadmap.title, ), body: EasyRefresh( controller: _controller, @@ -172,13 +175,15 @@ class _RoadmapViewState extends State { }); }, ).onError((error, stackTrace) { + final context = AppNavigator.key.currentContext!; + final t = Translations.of(context); ErrorHandler.handle( error, stackTrace: stackTrace, postProcessor: (_, msg) { setState(() => _items = []); if (operation == Operation.none) { - EasyLoading.showError(msg ?? 'Failure'); + EasyLoading.showError(msg ?? t.common.failure); } else if (operation == Operation.refresh) { _controller.finishRefresh(IndicatorResult.fail); } @@ -188,13 +193,14 @@ class _RoadmapViewState extends State { } void showCalendarModalBottomSheet(RoadmapModel roadmap) { + final t = Translations.of(context); showModalBottomSheet( context: context, isDismissible: false, isScrollControlled: true, enableDrag: false, builder: (BuildContext context) => ModalBottomSheet( - buttonText: '关闭', + buttonText: t.buttons.turnOff, contentPadding: const EdgeInsets.symmetric(horizontal: 10), margin: const EdgeInsets.symmetric(vertical: 10), callback: NavigatorUtil.pop, diff --git a/lib/modules/detail/views/social_view.dart b/lib/modules/detail/views/social_view.dart index 97316bb3..b5b4072a 100644 --- a/lib/modules/detail/views/social_view.dart +++ b/lib/modules/detail/views/social_view.dart @@ -3,11 +3,13 @@ import 'dart:async'; import 'package:easy_refresh/easy_refresh.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:homing_pigeon/app/navigator.dart'; import 'package:homing_pigeon/common/api/social_api.dart'; import 'package:homing_pigeon/common/enums/enums.dart'; import 'package:homing_pigeon/common/http/utils/handle_errors.dart'; import 'package:homing_pigeon/common/models/models.dart'; import 'package:homing_pigeon/common/widgets/widgets.dart'; +import 'package:homing_pigeon/i18n/i18n.dart'; import 'package:homing_pigeon/modules/detail/detail.dart'; import 'package:homing_pigeon/theme/colors.dart'; @@ -45,12 +47,13 @@ class _SocialViewState extends State @override Widget build(BuildContext context) { super.build(context); + final t = Translations.of(context); final isDark = Theme.of(context).brightness == Brightness.dark; final bottom = MediaQuery.of(context).padding.bottom; return Scaffold( appBar: HpAppBar( isDark: isDark, - titleName: '社交', + titleName: t.pages.social.title, ), body: EasyRefresh( controller: _controller, @@ -90,9 +93,9 @@ class _SocialViewState extends State tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), onPressed: _load, - child: const Text( - '没有数据, 点击以重新加载', - style: TextStyle( + child: Text( + t.common.noData, + style: const TextStyle( fontSize: 12, color: placeholderTextColor, ), @@ -169,13 +172,15 @@ class _SocialViewState extends State } }, ).onError((error, stackTrace) { + final context = AppNavigator.key.currentContext!; + final t = Translations.of(context); ErrorHandler.handle( error, stackTrace: stackTrace, postProcessor: (_, msg) { if (operation == Operation.none) { setState(() => loading = false); - EasyLoading.showError(msg ?? 'Failure'); + EasyLoading.showError(msg ?? t.common.failure); } else if (operation == Operation.refresh) { _controller.finishRefresh(IndicatorResult.fail); } else if (operation == Operation.load) { diff --git a/lib/modules/home/views/home_view.dart b/lib/modules/home/views/home_view.dart index 3c2763a9..4e30c147 100644 --- a/lib/modules/home/views/home_view.dart +++ b/lib/modules/home/views/home_view.dart @@ -45,7 +45,7 @@ class HomeView extends StatefulWidget { const double carouselHeight = 250; class _HomeViewState extends State - with AutomaticKeepAliveClientMixin { + with SingleTickerProviderStateMixin { final _loginFormKey = GlobalKey(); final _signupFormKey = GlobalKey(); final ScrollController _scrollController = ScrollController(); @@ -88,7 +88,6 @@ class _HomeViewState extends State @override Widget build(BuildContext context) { - super.build(context); return Scaffold( resizeToAvoidBottomInset: false, body: _buildScaffoldBody(), @@ -130,6 +129,7 @@ class _HomeViewState extends State } Widget _buildScaffoldBody() { + final t = Translations.of(context); final configs = BlocProvider.of(context).state.configs; final roadmapConfig = configs?.firstWhereOrNull((config) => config.key == 'roadmap'); @@ -146,56 +146,56 @@ class _HomeViewState extends State // Add the app bar to the CustomScrollView. _buildSliverAppBar(), Section( - title: '主要功能', + title: t.pages.home.primary.title, items: [ SectionItem( - title: '电影打分系统', - tips: '给看过的电影打个分吧~~', + title: t.pages.home.primary.rating.title, + tips: t.pages.home.primary.rating.description, onTap: () => NavigatorUtil.push(const MovieView()), ), if (AppConfig.shared.isExternal) SectionItem( - title: '直播预告', - tips: '查看详情', + title: t.pages.home.primary.live.title, + tips: t.pages.home.primary.live.description, onTap: () => NavigatorUtil.push(const LiveView()), ), SectionItem( - title: '开播通知设置', + title: t.pages.home.primary.settings.title, onTap: () => NavigatorUtil.push(const LiveView()), showBorder: false, ), ], ), Section( - title: '其他功能', + title: t.pages.home.other.title, items: [ SectionItem( - title: '直播信息/提醒群', - tips: '直播平台、时间等', + title: t.pages.home.other.notifications.title, + tips: t.pages.home.other.notifications.title, onTap: () => NavigatorUtil.push(const SocialView()), ), SectionItem( - title: '小德官方店: 喜瑞斯', - tips: '寒潮啦! 来件卫衣吧~~', + title: t.pages.home.other.store.title, + tips: t.pages.home.other.store.title, tipsColor: errorTextColor, showBack: false, onTap: showShopModalBottomSheet, ), SectionItem( - title: '小德表情包🐱', - tips: '欢迎投稿~~', + title: t.pages.home.other.emoji.title, + tips: t.pages.home.other.emoji.description, onTap: () => NavigatorUtil.push(const EmojiView()), ), SectionItem( - title: '意见/建议', - tips: '无论您遇到任何问题、意见或建议, 均可反馈...', + title: t.pages.home.other.feedback.title, + tips: t.pages.home.other.feedback.description, onTap: () => NavigatorUtil.push(const FeedbackView()), showBorder: showRoadmap, ), if (showRoadmap) SectionItem( - title: '路线图', - tips: '查看开发计划或进度😄', + title: t.pages.home.other.roadmap.title, + tips: t.pages.home.other.roadmap.description, onTap: () => NavigatorUtil.push(const RoadmapView()), showBorder: false, ), @@ -205,7 +205,7 @@ class _HomeViewState extends State SliverList.list( children: [ Text( - '版本号: $version+$buildNumber($flavorName)', + '${t.pages.home.version}: $version+$buildNumber($flavorName)', style: const TextStyle(fontSize: 12, color: secondaryTextColor), textAlign: TextAlign.center, ).nestedPadding( @@ -286,8 +286,9 @@ class _HomeViewState extends State stretch: true, // backgroundColor: Colors.white, expandedHeight: expandedHeight, + centerTitle: true, title: expandedHeight == null || isSliverAppBarExpanded - ? Text(t.pages.homePage.title) + ? Text(t.appName) : null, systemOverlayStyle: SystemUiOverlayStyle( statusBarColor: Colors.transparent, @@ -384,7 +385,184 @@ class _HomeViewState extends State ); } + // 登录接口 + void _login() { + final t = Translations.of(context); + if (_loginFormKey.currentState!.validate()) { + final fields = _loginFormKey.currentState!.instantValue; + final account = fields['account'] as String; + final password = fields['password'] as String; + + EasyLoading.show(); + AuthApi.login(account: account, password: password).then((value) { + if (value != null) { + NavigatorUtil.pop(); + EasyLoading.showSuccess(t.common.success); + SpUtil.putString( + Keys.tokenKey, + StringUtil.getValue(value.accessToken), + ); + SpUtil.putString( + Keys.userIdKey, + StringUtil.getValue(value.user?.id), + ); + initJPush(); + initFirebase(); + BlocProvider.of(context).addUser(value.user); + return; + } + EasyLoading.showError(t.common.failure); + }).onError((error, stackTrace) { + ErrorHandler.handle( + error, + stackTrace: stackTrace, + postProcessor: (_, msg) { + EasyLoading.showError(msg ?? t.common.failure); + }, + ); + }); + } + } + + // 注册接口 + void _register() { + final t = Translations.of(context); + if (_signupFormKey.currentState!.validate()) { + final fields = _signupFormKey.currentState!.instantValue; + final account = fields['account'] as String; + final nickname = fields['nickname'] as String?; + final email = fields['email'] as String; + final password = fields['password'] as String; + + EasyLoading.show(); + AuthApi.register( + username: account, + password: password, + email: email, + nickname: nickname, + ).then((value) { + if (value != null) { + NavigatorUtil.pop(); + EasyLoading.showSuccess(t.common.success); + SpUtil.putString( + Keys.tokenKey, + StringUtil.getValue(value.accessToken), + ); + SpUtil.putString( + Keys.userIdKey, + StringUtil.getValue(value.user?.id), + ); + initJPush(); + initFirebase(); + BlocProvider.of(context).addUser(value.user); + return; + } + EasyLoading.showError(t.common.failure); + }).onError((error, stackTrace) { + ErrorHandler.handle( + error, + stackTrace: stackTrace, + postProcessor: (_, msg) { + EasyLoading.showError(msg ?? t.common.failure); + }, + ); + }); + } + } + + // 退出接口 + void _logout() { + NavigatorUtil.pop(); + BlocProvider.of(context).addUser(null); + SpUtil.remove(Keys.tokenKey); + SpUtil.remove(Keys.userIdKey); + } + + // 加载数据 + void _load() { + final context = AppNavigator.key.currentContext!; + final t = Translations.of(context); + setState(() => _loading = true); + CarouselApi.getCarouselList().then((carousels) { + setState(() { + _loading = false; + _carousels = carousels; + }); + }).onError((error, stackTrace) { + ErrorHandler.handle( + error, + stackTrace: stackTrace, + postProcessor: (_, msg) { + setState(() { + _loading = false; + _error = msg ?? t.common.failure; + }); + }, + ); + }); + } + + void showShopModalBottomSheet() { + final t = Translations.of(context); + final configs = BlocProvider.of(context).state.configs; + final tbConfig = + configs?.firstWhereOrNull((config) => config.key == 'taobao'); + + const crossAxisAlignment = CrossAxisAlignment.center; + const padding = EdgeInsets.zero; + showModalBottomSheet( + context: context, + isDismissible: false, + isScrollControlled: true, + enableDrag: false, + builder: (BuildContext context) => ModalBottomSheet( + buttonText: t.buttons.cancel, + callback: NavigatorUtil.pop, + header: HpHeader( + title: t.bottomSheets.store.title, + hideCancel: true, + ), + items: [ + if (StringUtil.isNotBlank(tbConfig?.value)) + SectionItem( + title: t.bottomSheets.store.code.title, + tips: t.bottomSheets.store.code.description, + showBack: false, + contentPadding: padding, + innerPadding: padding, + crossAxisAlignment: crossAxisAlignment, + onTap: () => FlutterClipboard.copy(tbConfig!.value!).then( + (value) { + EasyLoading.showSuccess(t.common.copied); + NavigatorUtil.pop(); + }, + ), + ), + SectionItem( + title: t.bottomSheets.store.link.title, + tips: t.bottomSheets.store.link.description, + tipsColor: errorTextColor, + showBack: false, + showBorder: false, + contentPadding: padding, + innerPadding: padding, + crossAxisAlignment: crossAxisAlignment, + onTap: () async { + NavigatorUtil.pop(); + final uri = Uri.parse('https://chenyifaer.taobao.com'); + if (await canLaunchUrl(uri)) { + await launchUrl(uri); + } + }, + ), + ], + ), + ); + } + + // 登录/注册弹窗 void showLoginBottomSheet() { + final t = Translations.of(context); final width = MediaQuery.sizeOf(context).width; final height = MediaQuery.sizeOf(context).height; final top = MediaQuery.of(context).padding.top; @@ -400,6 +578,7 @@ class _HomeViewState extends State enableDrag: false, builder: (BuildContext ctx) { final isDark = Theme.of(ctx).brightness == Brightness.dark; + final buttonText = !_isRegistered ? t.buttons.login : t.buttons.signup; return StatefulBuilder( builder: (BuildContext ctx1, StateSetter setInnerState) { return KeyboardDismisser( @@ -408,16 +587,18 @@ class _HomeViewState extends State maxHeight: height - top - buttonHeight - bottom, ), callback: !_isRegistered ? _login : _register, - buttonText: !_isRegistered ? '登录' : '注册', + buttonText: buttonText, header: Row( children: [ Text( - '请填写${!_isRegistered ? '登录' : '注册'}信息', + !_isRegistered + ? t.bottomSheets.login.header + : t.bottomSheets.signup.header, style: TextStyle( fontSize: 16, color: isDark ? Colors.white : primaryTextColor, ), - maxLines: 1, + maxLines: 2, overflow: TextOverflow.ellipsis, ) .nestedPadding( @@ -472,7 +653,7 @@ class _HomeViewState extends State child: Column( children: [ BaseFormItem( - title: '账号', + title: t.bottomSheets.login.form.account.title, showTip: false, padding: EdgeInsets.zero, child: FormBuilderField( @@ -519,10 +700,13 @@ class _HomeViewState extends State ), gapPadding: 0, ), - hintText: '请输入账号', + hintText: t.bottomSheets.login.form + .account.hintText, helperText: _isRegistered - ? '只能包含英文, 数字或下划线, 且只能以字母开头, 至少8个字符' + ? t.bottomSheets.signup.form.account + .helperText : null, + helperMaxLines: 2, helperStyle: const TextStyle( color: secondaryTextColor, fontSize: 10, @@ -556,13 +740,16 @@ class _HomeViewState extends State }, validator: FormBuilderValidators.compose([ FormBuilderValidators.required( - errorText: '请输入账号', + errorText: + t.bottomSheets.login.form.account.errorText, ), FormBuilderValidators.match( r'^[a-zA-Z][a-zA-Z0-9_]{7,}$', errorText: _isRegistered - ? '账号只能包含英文,数字或下划线, 且只能以字母开头, 至少8个字符' - : '至少8个字符', + ? t.bottomSheets.signup.form.account + .errorText2 + : t.bottomSheets.login.form.account + .errorText2, ), // TODO(kjxbyz): 与数据库联动,账号唯一 ]), @@ -573,7 +760,7 @@ class _HomeViewState extends State ), if (_isRegistered) ...[ BaseFormItem( - title: '昵称', + title: t.bottomSheets.signup.form.nickname.title, required: false, showTip: false, child: FormBuilderField( @@ -626,9 +813,13 @@ class _HomeViewState extends State ), gapPadding: 0, ), - hintText: '请输入昵称', - helperText: - _isRegistered ? '不能多于20个字符' : null, + hintText: t.bottomSheets.signup.form + .nickname.hintText, + helperText: _isRegistered + ? t.bottomSheets.signup.form + .nickname.helperText + : null, + helperMaxLines: 2, helperStyle: const TextStyle( color: secondaryTextColor, fontSize: 10, @@ -666,7 +857,8 @@ class _HomeViewState extends State validator: FormBuilderValidators.compose([ FormBuilderValidators.maxLength( 20, - errorText: '昵称长度不能大于20', + errorText: t.bottomSheets.signup.form.nickname + .errorText, ), ]), name: 'nickname', @@ -675,7 +867,7 @@ class _HomeViewState extends State ), ), BaseFormItem( - title: '邮箱', + title: t.bottomSheets.signup.form.email.title, showTip: false, child: FormBuilderField( focusNode: emailFocusNode, @@ -724,7 +916,14 @@ class _HomeViewState extends State ), gapPadding: 0, ), - hintText: '请输入邮箱', + hintText: t.bottomSheets.signup.form + .email.hintText, + helperMaxLines: 2, + helperStyle: const TextStyle( + color: secondaryTextColor, + fontSize: 10, + fontWeight: FontWeight.w400, + ), errorText: field.errorText, errorStyle: const TextStyle( fontSize: 12, @@ -756,10 +955,12 @@ class _HomeViewState extends State }, validator: FormBuilderValidators.compose([ FormBuilderValidators.required( - errorText: '请输入邮箱', + errorText: t + .bottomSheets.signup.form.email.errorText, ), FormBuilderValidators.email( - errorText: '邮箱格式错误', + errorText: t.bottomSheets.signup.form.email + .errorText2, ), // TODO(kjxbyz): 与数据库联动,邮箱唯一 ]), @@ -770,7 +971,7 @@ class _HomeViewState extends State ), ], BaseFormItem( - title: '密码', + title: t.bottomSheets.login.form.password.title, showTip: false, child: FormBuilderField( focusNode: passwordFocusNode, @@ -846,9 +1047,13 @@ class _HomeViewState extends State ), gapPadding: 0, ), - hintText: '请输入密码', - helperText: - _isRegistered ? '不能少于8个字符' : null, + hintText: t.bottomSheets.login.form + .password.hintText, + helperText: _isRegistered + ? t.bottomSheets.signup.form + .password.helperText + : null, + helperMaxLines: 2, helperStyle: const TextStyle( color: secondaryTextColor, fontSize: 10, @@ -883,7 +1088,8 @@ class _HomeViewState extends State ), if (_isRegistered) BaseFormItem( - title: '重复密码', + title: t.bottomSheets.signup.form + .repeatPassword.title, showTip: false, child: FormBuilderField( focusNode: repeatPasswordFocusNode, @@ -982,7 +1188,13 @@ class _HomeViewState extends State ), gapPadding: 0, ), - hintText: '请再次输入密码', + hintText: t + .bottomSheets + .signup + .form + .repeatPassword + .hintText, + helperMaxLines: 2, errorText: repeatPwdField .errorText, errorStyle: const TextStyle( @@ -1025,14 +1237,20 @@ class _HomeViewState extends State validator: FormBuilderValidators.compose([ FormBuilderValidators.required( - errorText: '请再次输入密码', + errorText: t.bottomSheets.signup + .form.repeatPassword.errorText, ), if (StringUtil.isNotBlank( field.value, )) FormBuilderValidators.equal( field.value!, - errorText: '两次输入的密码不一样', + errorText: t + .bottomSheets + .signup + .form + .repeatPassword + .errorText2, ), ]), name: 'repeatPassword', @@ -1045,11 +1263,13 @@ class _HomeViewState extends State }, validator: FormBuilderValidators.compose([ FormBuilderValidators.required( - errorText: '请输入密码', + errorText: t + .bottomSheets.login.form.password.errorText, ), FormBuilderValidators.minLength( 8, - errorText: '请至少输入8个字符', + errorText: t.bottomSheets.login.form.password + .errorText2, ), ]), name: 'password', @@ -1059,13 +1279,14 @@ class _HomeViewState extends State ), BaseFormItem( child: FormBuilderField( - name: 'privacy', + name: t.bottomSheets.login.form.privacy.title, initialValue: false, autovalidateMode: AutovalidateMode.onUserInteraction, validator: (value) { if (!(value ?? false)) { - return '请同意隐私协议'; + return t + .bottomSheets.login.form.privacy.errorText; } return null; }, @@ -1104,11 +1325,13 @@ class _HomeViewState extends State RichText( text: TextSpan( children: [ - const TextSpan( - text: '我已仔细阅读并同意', + TextSpan( + text: t.bottomSheets.login.form + .privacy.prefix, ), TextSpan( - text: '隐私政策', + text: t.bottomSheets.login.form + .privacy.privacy, recognizer: TapGestureRecognizer() ..onTap = () async { // https://www.chenyifaer.com/homing-pigeon/zh/legal/privacy/ @@ -1127,11 +1350,13 @@ class _HomeViewState extends State fontWeight: FontWeight.w400, ), ), - const TextSpan( - text: '以及', + TextSpan( + text: t.bottomSheets.login.form + .privacy.and, ), TextSpan( - text: '条款和条件', + text: t.bottomSheets.login.form + .privacy.terms, recognizer: TapGestureRecognizer() ..onTap = () async { // https://www.chenyifaer.com/homing-pigeon/zh/legal/terms-of-use/ @@ -1197,7 +1422,9 @@ class _HomeViewState extends State text: TextSpan( children: [ TextSpan( - text: !_isRegistered ? '还没有账号, ' : '已有账号, ', + text: !_isRegistered + ? t.bottomSheets.signup.tips.prefix + : t.bottomSheets.login.tips.prefix, style: TextStyle( color: isDark ? secondaryBorderColor @@ -1207,7 +1434,9 @@ class _HomeViewState extends State ), ), TextSpan( - text: !_isRegistered ? '去注册' : '去登录', + text: !_isRegistered + ? t.bottomSheets.signup.tips.suffix + : t.bottomSheets.login.tips.suffix, recognizer: TapGestureRecognizer() ..onTap = () async { setInnerState(() { @@ -1242,13 +1471,15 @@ class _HomeViewState extends State ); } + // 退出弹窗 void showLogoutBottomSheet() { + final t = Translations.of(context); final height = MediaQuery.sizeOf(context).height; final top = MediaQuery.of(context).padding.top; final bottom = MediaQuery.of(context).padding.bottom; showModalBottomSheet( - context: AppNavigator.key.currentContext!, + context: context, isScrollControlled: true, enableDrag: false, builder: (BuildContext ctx) => StatefulBuilder( @@ -1257,180 +1488,11 @@ class _HomeViewState extends State child: ModalBottomSheet( constraints: BoxConstraints(maxHeight: height - top - bottom), callback: _logout, - buttonText: '退出', + buttonText: t.buttons.logout, ), ); }, ), ); } - - // 登录接口 - void _login() { - if (_loginFormKey.currentState!.validate()) { - final fields = _loginFormKey.currentState!.instantValue; - final account = fields['account'] as String; - final password = fields['password'] as String; - - EasyLoading.show(); - AuthApi.login(account: account, password: password).then((value) { - if (value != null) { - NavigatorUtil.pop(); - EasyLoading.showSuccess('Success'); - SpUtil.putString( - Keys.tokenKey, - StringUtil.getValue(value.accessToken), - ); - SpUtil.putString( - Keys.userIdKey, - StringUtil.getValue(value.user?.id), - ); - initJPush(); - initFirebase(); - BlocProvider.of(context).addUser(value.user); - return; - } - EasyLoading.showError('Failure'); - }).onError((error, stackTrace) { - ErrorHandler.handle( - error, - stackTrace: stackTrace, - postProcessor: (_, msg) { - EasyLoading.showError(msg ?? 'Failure'); - }, - ); - }); - } - } - - // 注册接口 - void _register() { - if (_signupFormKey.currentState!.validate()) { - final fields = _signupFormKey.currentState!.instantValue; - final account = fields['account'] as String; - final nickname = fields['nickname'] as String?; - final email = fields['email'] as String; - final password = fields['password'] as String; - - EasyLoading.show(); - AuthApi.register( - username: account, - password: password, - email: email, - nickname: nickname, - ).then((value) { - if (value != null) { - NavigatorUtil.pop(); - EasyLoading.showSuccess('Success'); - SpUtil.putString( - Keys.tokenKey, - StringUtil.getValue(value.accessToken), - ); - SpUtil.putString( - Keys.userIdKey, - StringUtil.getValue(value.user?.id), - ); - initJPush(); - initFirebase(); - BlocProvider.of(context).addUser(value.user); - return; - } - EasyLoading.showError('Failure'); - }).onError((error, stackTrace) { - ErrorHandler.handle( - error, - stackTrace: stackTrace, - postProcessor: (_, msg) { - EasyLoading.showError(msg ?? 'Failure'); - }, - ); - }); - } - } - - // 退出接口 - void _logout() { - NavigatorUtil.pop(); - BlocProvider.of(context).addUser(null); - SpUtil.remove(Keys.tokenKey); - SpUtil.remove(Keys.userIdKey); - } - - void showShopModalBottomSheet() { - final configs = BlocProvider.of(context).state.configs; - final tbConfig = - configs?.firstWhereOrNull((config) => config.key == 'taobao'); - - const crossAxisAlignment = CrossAxisAlignment.center; - const padding = EdgeInsets.zero; - showModalBottomSheet( - context: context, - isDismissible: false, - isScrollControlled: true, - enableDrag: false, - builder: (BuildContext context) => ModalBottomSheet( - buttonText: '取消', - callback: NavigatorUtil.pop, - header: const HpHeader(title: '请选择您的操作', hideCancel: true), - items: [ - if (StringUtil.isNotBlank(tbConfig?.value)) - SectionItem( - title: '复制淘口令', - tips: '直播平台、时间等', - showBack: false, - contentPadding: padding, - innerPadding: padding, - crossAxisAlignment: crossAxisAlignment, - onTap: () => - FlutterClipboard.copy(tbConfig!.value!).then((value) { - EasyLoading.showSuccess('Copied'); - NavigatorUtil.pop(); - }), - ), - SectionItem( - title: '打开淘宝店地址', - tips: '寒潮啦! 来件卫衣吧~~', - tipsColor: errorTextColor, - showBack: false, - showBorder: false, - contentPadding: padding, - innerPadding: padding, - crossAxisAlignment: crossAxisAlignment, - onTap: () async { - NavigatorUtil.pop(); - final uri = Uri.parse('https://chenyifaer.taobao.com'); - if (await canLaunchUrl(uri)) { - await launchUrl(uri); - } - }, - ), - ], - ), - ); - } - - Future _load() async { - try { - setState(() => _loading = true); - final carousels = await CarouselApi.getCarouselList(); - setState(() { - _loading = false; - _carousels = carousels; - }); - } on Exception catch (error, stackTrace) { - ErrorHandler.handle( - error, - stackTrace: stackTrace, - postProcessor: (_, msg) { - setState(() { - _loading = false; - _error = msg ?? 'Failure'; - }); - }, - ); - } - } - - @override - bool get wantKeepAlive => true; } diff --git a/lib/modules/home/widgets/section.dart b/lib/modules/home/widgets/section.dart index 0457406f..5f4654f0 100644 --- a/lib/modules/home/widgets/section.dart +++ b/lib/modules/home/widgets/section.dart @@ -101,6 +101,7 @@ class SectionItem extends StatelessWidget { style: TextStyle( fontSize: 18, color: isDark ? secondaryGrayColor : primaryTextColor, + fontWeight: FontWeight.w400, ), maxLines: 1, overflow: TextOverflow.ellipsis, @@ -108,7 +109,11 @@ class SectionItem extends StatelessWidget { if (tips != null) Text( tips!, - style: TextStyle(fontSize: 12, color: tipsColor), + style: TextStyle( + fontSize: 12, + color: tipsColor, + fontWeight: FontWeight.w400, + ), maxLines: 1, overflow: TextOverflow.ellipsis, ).nestedPadding(padding: const EdgeInsets.only(top: 6)), diff --git a/pubspec.lock b/pubspec.lock index 909a1727..756a069f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -67,7 +67,7 @@ packages: source: hosted version: "1.5.0" async: - dependency: transitive + dependency: "direct main" description: name: async sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" diff --git a/pubspec.yaml b/pubspec.yaml index 035dae25..a25f9f9c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,6 +34,7 @@ dependencies: git: url: https://github.com/spencerccf/app_settings args: ^2.5.0 + async: ^2.11.0 bloc: ^8.1.4 cached_network_image: ^3.3.1 carousel_slider: ^4.2.1