鸿蒙端提交

This commit is contained in:
Developer
2026-06-18 03:09:19 +08:00
parent 70830b0991
commit 6a02a313b2
20 changed files with 232 additions and 114 deletions

1
.gitignore vendored
View File

@@ -59,3 +59,4 @@ app.*.map.json
# Trae IDE
.trae/
docs/toolsapi/thinkphp

View File

@@ -2,7 +2,45 @@
所有重要变更均记录于此文件。格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/)。
> 保留最近 10 个版本v6.79.0 ~ v6.88.0)。更早版本已归档至软件特性功能文档。
> 保留最近 10 个版本v6.80.0 ~ v6.89.0)。更早版本已归档至软件特性功能文档。
***
## [v6.89.0] - 2026-06-17
### 🛠 评分弹窗商店名称多语言 + Beta问卷按钮隐藏跨平台修复
#### 1. "给个好评"弹窗商店名称由硬编码"Google Play"改为多语言"应用商店"
- **需求**: Android 端点击"给个好评"后,跳转确认弹窗显示硬编码英文"Google Play",未接入多语言系统,风格不统一
- **实现**:
- `t_about.dart` 新增 `appStore` 翻译字段(构造函数 + 字段定义 + toMap + fromMap
- 14 种语言文件全部补充 `appStore` 翻译:
- zh_cn: 应用商店 / zh_tw: 應用商店 / en: App Store / ru: Магазин приложений
- pt: Loja de aplicativos / ko: 앱 스토어 / ja: アプリストア / it: App Store
- hi: ऐप स्टोर / fr: App Store / es: Tienda de aplicaciones / de: App Store
- bn: অ্যাপ স্টোর / ar: متجر التطبيقات
- `app_store_service.dart``getStoreName` 方法Android 分支由 `return 'Google Play'` 改为 `return t.about.appStore`
- **影响**: `profile_page.dart``about_page.dart` 的"给个好评"/"评价应用"入口弹窗文案自动跟随系统语言
#### 2. Beta 页面"填写问卷"按钮提交后隐藏逻辑跨平台生效
- **问题**: 问卷提交后按钮只在 iOS 端隐藏Android 等端不隐藏
- **根因**:
1. `_QuestionnaireSheet` 不符合条件关闭时调用 `_markQuestionnaireSubmitted()``await``Navigator.pop` 可能在 SharedPreferences 写入完成前执行
2. Sheet 关闭后仅依赖 `_loadQuestionnaireSubmitted()` 异步重读 SharedPreferences 更新 UI跨平台存在时序差异iOS NSUserDefaults 内存同步快Android SharedPreferences.apply 异步落盘)
- **修复**:
- `_QuestionnaireSheet` 的两处关闭按钮改为 `Navigator.pop(context, true)` 返回已提交标记
- `_showQuestionnaire` 接收 Sheet 返回值,`submitted == true` 时立即 `setState` 更新 `_questionnaireSubmitted`,不再依赖 SharedPreferences 时序
- 不符合条件关闭分支改为 `async` + `await _markQuestionnaireSubmitted()`,并在 await 前获取 `Navigator.of(context)` 避免 `use_build_context_synchronously`
- 保留 `_loadQuestionnaireSubmitted()` 作为兜底,确保与持久化状态最终一致
- **效果**: 所有平台iOS/Android/Windows/macOS问卷提交后按钮立即隐藏
#### 修改文件
| 文件 | 变更 |
|---|---|
| `l10n/types/t_about.dart` | 新增 `appStore` 字段(构造/定义/toMap/fromMap |
| `l10n/languages/*.dart` (14 个) | 补充 `appStore` 多语言翻译 |
| `core/services/app_store_service.dart` | Android 端商店名称改用 `t.about.appStore` |
| `features/settings/presentation/experimental_features_page.dart` | 问卷 Sheet 返回值即时更新 UI + await 修复时序 |
***
@@ -312,49 +350,3 @@
| `l10n/languages/en.dart` | 新增英文翻译Remember Account |
| `features/auth/presentation/login_form_sections.dart` | `PasswordFormSection` 新增 `isRemembered`/`onToggleRemember` 参数,将忘记密码按钮改为 Row 布局(左:记住账户复选框,右:忘记密码) |
| `features/auth/presentation/login_page.dart` | 新增 `_rememberAccount` 状态、`_saveRememberAccount()` 方法;`_loadLastLoginAccount()` 读取 `remember_account` 偏好;`_handlePasswordLogin()` 登录成功后保存/清除账户 |
***
## [v6.79.0] - 2026-06-17
### 🔒 隐私合规 — 修复安卓端自启动问题androidx.glance.appwidget
#### 问题描述
1. 应用商店审核发现:`androidx.glance.appwidget` SDK 在应用退出后触发自启动1次/秒),无隐私文本覆盖
2. 审核依据:《个人信息保护法》要求 APP 未向用户明示且未经用户同意,不得存在频繁自启动行为
3. 根因:`home_widget` 包引入了 `androidx.glance:glance-appwidget:1.1.1` 依赖,项目未使用 Glance Widget 但该库被打包进 APK其内部 `GlanceAppWidgetReceiver`/`GlanceAppWidgetService` 被系统广播触发导致自启动
4. 次要问题8个桌面小部件 Provider 在系统定时 `APPWIDGET_UPDATE` 广播触发时,未检查隐私协议状态即执行数据读取
#### 修复内容
**1. 彻底移除 androidx.glance.appwidget 依赖**
| 文件 | 变更 |
|---|---|
| `packages/home_widget/android/build.gradle` | 移除 `implementation "androidx.glance:glance-appwidget:1.1.1"` 依赖 |
| `HomeWidgetGlanceWidgetReceiver.kt` | 删除未使用的 Glance Receiver 源文件 |
| `HomeWidgetGlanceState.kt` | 删除未使用的 Glance State 源文件 |
**2. AndroidManifest 排除 Glance 组件合并**
| 文件 | 变更 |
|---|---|
| `AndroidManifest.xml` | 新增 `tools:node="remove"` 移除 `GlanceAppWidgetReceiver``GlanceAppWidgetService`,防止残留库通过 manifest merge 注入 |
**3. 所有 Widget Provider 增加隐私协议守门**
| 文件 | 变更 |
|---|---|
| `PrivacyAwareHomeWidgetProvider.kt` | 新建基类,在 `onUpdate` 中检查 `agreement_accepted` 标志,未同意时显示占位视图不读取任何业务数据 |
| `widget_privacy_placeholder.xml` | 新建隐私占位布局,提示"请先同意隐私政策" |
| `DailySentenceProvider.kt` | 改为继承 `PrivacyAwareHomeWidgetProvider``onUpdate``onUpdateWithAgreement` |
| `ReadlaterProvider.kt` | 同上 |
| `DailyCardProvider.kt` | 同上 |
| `FortuneProvider.kt` | 同上 |
| `CountdownProvider.kt` | 同上 |
| `PomodoroProvider.kt` | 同上 |
| `SolarTermProvider.kt` | 同上 |
| `CheckinProvider.kt` | 同上 |
| `CtcLatestNoteProvider.kt` | 同上 |
#### 合规影响
- `androidx.glance.appwidget` 自启动行为彻底消除(依赖移除 + Manifest 排除 + 源文件删除三重防护)
- Widget Provider 在用户未同意隐私政策前不执行任何数据操作,仅显示占位提示
- 与现有 `SplashActivity` 协议守门机制形成完整闭环

View File

@@ -3,7 +3,7 @@
/// 创建时间: 2026-06-17
/// 更新时间: 2026-06-17
/// 作用: 根据平台和语言地区生成正确的应用商店URL
/// 上次更新: 初始版本支持iOS/Android/鸿蒙/Windows/macOS多平台多地区
/// 上次更新: Android端商店名称由硬编码"Google Play"改为多语言"应用商店"(t.about.appStore)
/// ============================================================
import 'package:flutter/widgets.dart';
@@ -78,14 +78,16 @@ class AppStoreService {
/// [locale] 当前语言Locale用于判断地区
static Uri getIOSAppStoreUrl(Locale locale) {
final countryCode = locale.countryCode ?? '';
final appId = _iosAppIdsByRegion[countryCode.toUpperCase()] ??
_iosDefaultAppId;
final appId =
_iosAppIdsByRegion[countryCode.toUpperCase()] ?? _iosDefaultAppId;
// App Store URL格式: https://apps.apple.com/{region}/app/id{appId}
// 如果有地区代码,加入地区路径以正确跳转
final region = countryCode.isNotEmpty ? '$countryCode/' : '';
final url = 'https://apps.apple.com/${region}app/id$appId';
Log.d('AppStoreService: iOS URL = $url (region: $countryCode, appId: $appId)');
Log.d(
'AppStoreService: iOS URL = $url (region: $countryCode, appId: $appId)',
);
return Uri.parse(url);
}
@@ -167,9 +169,15 @@ class AppStoreService {
}
/// 获取应用商店显示名称
///
/// 根据当前平台返回对应应用商店的本地化名称。
/// - iOS/macOS: App Store
/// - Android: 应用商店(多语言,使用 t.about.appStore
/// - 鸿蒙: 华为应用市场(多语言)
/// - Windows: Microsoft Store
static String getStoreName(T t) {
if (pu.isIOS) return 'App Store';
if (pu.isAndroid) return 'Google Play';
if (pu.isAndroid) return t.about.appStore;
if (pu.isOhos) return t.about.huaweiStore;
if (pu.isWindows) return 'Microsoft Store';
if (pu.isMacOS) return 'App Store';

View File

@@ -3,7 +3,7 @@
/// 创建时间: 2026-05-30
/// 更新时间: 2026-06-17
/// 作用: 展示开发中/测试中/预览中的功能列表和问题列表接入远程FeatureFlag服务
/// 上次更新: 问卷进度实时保存(草稿持久化)、输入法遮挡修复、硬编码替换为多语言翻译键
/// 上次更新: 修复问卷提交后按钮隐藏只在iOS端生效的问题——Sheet返回值即时更新UI + await修复时序
/// ============================================================
import 'package:flutter/cupertino.dart';
@@ -108,34 +108,41 @@ class _ExperimentalFeaturesPageState
),
// 底部问卷按钮(提交后隐藏)
if (!_questionnaireSubmitted)
Padding(
padding: const EdgeInsets.fromLTRB(
AppSpacing.md, AppSpacing.sm, AppSpacing.md, AppSpacing.md,
),
child: SizedBox(
width: double.infinity,
child: CupertinoButton(
color: ext.accent,
borderRadius: BorderRadius.circular(10),
padding: const EdgeInsets.symmetric(vertical: 14),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(CupertinoIcons.question_circle_fill, size: 18, color: ext.textOnAccent),
const SizedBox(width: 6),
Text(
t.beta.questionnaireBtn,
style: AppTypography.subhead.copyWith(
Padding(
padding: const EdgeInsets.fromLTRB(
AppSpacing.md,
AppSpacing.sm,
AppSpacing.md,
AppSpacing.md,
),
child: SizedBox(
width: double.infinity,
child: CupertinoButton(
color: ext.accent,
borderRadius: BorderRadius.circular(10),
padding: const EdgeInsets.symmetric(vertical: 14),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
CupertinoIcons.question_circle_fill,
size: 18,
color: ext.textOnAccent,
fontWeight: FontWeight.w600,
),
),
],
const SizedBox(width: 6),
Text(
t.beta.questionnaireBtn,
style: AppTypography.subhead.copyWith(
color: ext.textOnAccent,
fontWeight: FontWeight.w600,
),
),
],
),
onPressed: () => _showQuestionnaire(ext, t),
),
onPressed: () => _showQuestionnaire(ext, t),
),
),
),
],
),
),
@@ -145,15 +152,22 @@ class _ExperimentalFeaturesPageState
// ---- 问卷 ----
/// 弹出问卷Sheet
///
/// Sheet 关闭后返回是否已提交:
/// - 优先使用返回值立即更新 UI避免 SharedPreferences 跨平台时序差异)
/// - 再异步读取 SharedPreferences 作为兜底,确保状态最终一致
Future<void> _showQuestionnaire(AppThemeExtension ext, T t) async {
await showCupertinoModalPopup<void>(
final submitted = await showCupertinoModalPopup<bool>(
context: context,
builder: (_) => _QuestionnaireSheet(ext: ext, t: t),
);
// Sheet关闭后刷新问卷提交状态
if (mounted) {
_loadQuestionnaireSubmitted();
if (!mounted) return;
// 立即根据 Sheet 返回值更新 UI所有平台一致生效
if (submitted == true && !_questionnaireSubmitted) {
setState(() => _questionnaireSubmitted = true);
}
// 异步刷新作为兜底,确保与持久化状态一致
_loadQuestionnaireSubmitted();
}
// ---- 分段控制器 ----
@@ -234,7 +248,11 @@ class _ExperimentalFeaturesPageState
);
}
Widget _buildFlagsList(AppThemeExtension ext, T t, List<FeatureFlagItem> flags) {
Widget _buildFlagsList(
AppThemeExtension ext,
T t,
List<FeatureFlagItem> flags,
) {
// 仅显示服务端启用的功能标志
final visibleFlags = flags.where((f) => f.enabled).toList();
@@ -262,7 +280,12 @@ class _ExperimentalFeaturesPageState
ext: ext,
t: t,
onToggle: (key, enabled) {
_showToggleConfirmDialog(ext, t, visibleFlags[index], enabled);
_showToggleConfirmDialog(
ext,
t,
visibleFlags[index],
enabled,
);
},
);
},
@@ -674,7 +697,10 @@ class _RemoteFeatureCard extends StatelessWidget {
Icon(CupertinoIcons.group_solid, size: 12, color: ext.textHint),
const SizedBox(width: 4),
Text(
t.beta.rolloutPercentage.replaceAll('{0}', '${(flag.rolloutPercentage * 100).toInt()}'),
t.beta.rolloutPercentage.replaceAll(
'{0}',
'${(flag.rolloutPercentage * 100).toInt()}',
),
style: AppTypography.caption2.copyWith(color: ext.textHint),
),
if (flag.targetGroup != null) ...[
@@ -692,12 +718,15 @@ class _RemoteFeatureCard extends StatelessWidget {
/// 显示关联问题数量
Widget _buildIssueCount() {
final pendingCount =
flag.issues.where((i) => i.status == IssueStatus.pending).length;
final fixingCount =
flag.issues.where((i) => i.status == IssueStatus.fixing).length;
final fixedCount =
flag.issues.where((i) => i.status == IssueStatus.fixed).length;
final pendingCount = flag.issues
.where((i) => i.status == IssueStatus.pending)
.length;
final fixingCount = flag.issues
.where((i) => i.status == IssueStatus.fixing)
.length;
final fixedCount = flag.issues
.where((i) => i.status == IssueStatus.fixed)
.length;
return Row(
children: [
@@ -917,16 +946,31 @@ class _QuestionnaireSheetState extends State<_QuestionnaireSheet> {
void _answer(bool yes) {
if (_step == 0) {
// 问题1: 了解Google Play
if (!yes) { setState(() => _step = -1); _clearDraft(); return; }
setState(() => _step = 1); _saveDraft();
if (!yes) {
setState(() => _step = -1);
_clearDraft();
return;
}
setState(() => _step = 1);
_saveDraft();
} else if (_step == 1) {
// 问题2: 有GMS设备
if (!yes) { setState(() => _step = -1); _clearDraft(); return; }
setState(() => _step = 2); _saveDraft();
if (!yes) {
setState(() => _step = -1);
_clearDraft();
return;
}
setState(() => _step = 2);
_saveDraft();
} else if (_step == 2) {
// 问题3: 愿意参与内测
if (!yes) { setState(() => _step = -1); _clearDraft(); return; }
setState(() => _step = 3); _saveDraft();
if (!yes) {
setState(() => _step = -1);
_clearDraft();
return;
}
setState(() => _step = 3);
_saveDraft();
}
}
@@ -946,7 +990,10 @@ class _QuestionnaireSheetState extends State<_QuestionnaireSheet> {
// 提交成功,保存标记并清除草稿
await _markQuestionnaireSubmitted();
_clearDraft();
setState(() { _step = 4; _isSubmitting = false; });
setState(() {
_step = 4;
_isSubmitting = false;
});
} else {
AppToast.showError(widget.t.beta.qSubmitFailed);
setState(() => _isSubmitting = false);
@@ -982,7 +1029,8 @@ class _QuestionnaireSheetState extends State<_QuestionnaireSheet> {
children: [
// 拖拽指示器
Container(
width: 36, height: 5,
width: 36,
height: 5,
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: ext.textHint.withValues(alpha: 0.3),
@@ -991,7 +1039,10 @@ class _QuestionnaireSheetState extends State<_QuestionnaireSheet> {
),
if (_step >= 0 && _step <= 3) ...[
// 进度
Text('${_step + 1}/4', style: AppTypography.caption1.copyWith(color: ext.textHint)),
Text(
'${_step + 1}/4',
style: AppTypography.caption1.copyWith(color: ext.textHint),
),
const SizedBox(height: 12),
// 问题
Text(
@@ -1008,7 +1059,13 @@ class _QuestionnaireSheetState extends State<_QuestionnaireSheet> {
child: CupertinoButton(
color: ext.accent,
borderRadius: BorderRadius.circular(10),
child: Text(t.beta.qYes, style: TextStyle(color: ext.textOnAccent, fontWeight: FontWeight.w600)),
child: Text(
t.beta.qYes,
style: TextStyle(
color: ext.textOnAccent,
fontWeight: FontWeight.w600,
),
),
onPressed: () => _answer(true),
),
),
@@ -1017,7 +1074,10 @@ class _QuestionnaireSheetState extends State<_QuestionnaireSheet> {
child: CupertinoButton(
color: ext.bgElevated,
borderRadius: BorderRadius.circular(10),
child: Text(t.beta.qNo, style: TextStyle(color: ext.textSecondary)),
child: Text(
t.beta.qNo,
style: TextStyle(color: ext.textSecondary),
),
onPressed: () => _answer(false),
),
),
@@ -1045,7 +1105,13 @@ class _QuestionnaireSheetState extends State<_QuestionnaireSheet> {
borderRadius: BorderRadius.circular(10),
child: _isSubmitting
? CupertinoActivityIndicator(color: ext.textOnAccent)
: Text(t.beta.qSubmit, style: TextStyle(color: ext.textOnAccent, fontWeight: FontWeight.w600)),
: Text(
t.beta.qSubmit,
style: TextStyle(
color: ext.textOnAccent,
fontWeight: FontWeight.w600,
),
),
onPressed: _isSubmitting ? null : _submitEmail,
),
),
@@ -1054,39 +1120,68 @@ class _QuestionnaireSheetState extends State<_QuestionnaireSheet> {
// 不符合条件
Icon(CupertinoIcons.info_circle, size: 48, color: ext.textHint),
const SizedBox(height: 12),
Text(t.beta.qEndThankYou, style: AppTypography.headline.copyWith(color: ext.textPrimary)),
Text(
t.beta.qEndThankYou,
style: AppTypography.headline.copyWith(color: ext.textPrimary),
),
const SizedBox(height: 8),
Text(t.beta.qEndNotQualified, style: AppTypography.subhead.copyWith(color: ext.textSecondary), textAlign: TextAlign.center),
Text(
t.beta.qEndNotQualified,
style: AppTypography.subhead.copyWith(color: ext.textSecondary),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
SizedBox(
width: double.infinity,
child: CupertinoButton(
color: ext.bgElevated,
borderRadius: BorderRadius.circular(10),
child: Text(t.beta.close, style: TextStyle(color: ext.textSecondary)),
onPressed: () {
child: Text(
t.beta.close,
style: TextStyle(color: ext.textSecondary),
),
onPressed: () async {
// 不符合条件关闭时也保存标记并清除草稿
_markQuestionnaireSubmitted();
// 使用 await 确保写入完成后再关闭,避免跨平台时序问题
final navigator = Navigator.of(context);
await _markQuestionnaireSubmitted();
_clearDraft();
Navigator.pop(context);
if (mounted) navigator.pop(true);
},
),
),
] else ...[
// 完成
Icon(CupertinoIcons.checkmark_circle_fill, size: 48, color: ext.successColor),
Icon(
CupertinoIcons.checkmark_circle_fill,
size: 48,
color: ext.successColor,
),
const SizedBox(height: 12),
Text(t.beta.qSubmitSuccess, style: AppTypography.headline.copyWith(color: ext.textPrimary)),
Text(
t.beta.qSubmitSuccess,
style: AppTypography.headline.copyWith(color: ext.textPrimary),
),
const SizedBox(height: 8),
Text(t.beta.qEndThanks, style: AppTypography.subhead.copyWith(color: ext.textSecondary), textAlign: TextAlign.center),
Text(
t.beta.qEndThanks,
style: AppTypography.subhead.copyWith(color: ext.textSecondary),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
SizedBox(
width: double.infinity,
child: CupertinoButton(
color: ext.accent,
borderRadius: BorderRadius.circular(10),
child: Text(t.beta.gotIt, style: TextStyle(color: ext.textOnAccent, fontWeight: FontWeight.w600)),
onPressed: () => Navigator.pop(context),
child: Text(
t.beta.gotIt,
style: TextStyle(
color: ext.textOnAccent,
fontWeight: FontWeight.w600,
),
),
onPressed: () => Navigator.pop(context, true),
),
),
],

View File

@@ -1367,6 +1367,7 @@ const ar = T(
rateDialogContent2: 'دعمكم هو حافزنا',
laterButton: 'لاحقاً',
huaweiStore: 'Huawei AppGallery',
appStore: 'متجر التطبيقات',
goRate: 'تقييم',
emailHint1: 'إذا لم يكن هناك رد خلال 24 ساعة، جرب بريداً آخر',
emailHint2: 'أي بريد إلكتروني مناسب للتواصل',

View File

@@ -1376,6 +1376,7 @@ const bn = T(
rateDialogContent2: 'আপনার সমর্থন আমাদের অনুপ্রেরণা',
laterButton: 'পরে',
huaweiStore: 'Huawei AppGallery',
appStore: 'অ্যাপ স্টোর',
goRate: 'মূল্যায়ন',
emailHint1: '২৪ ঘন্টায় কোনো উত্তর না পেলে অন্য ইমেইল চেষ্টা করুন',
emailHint2: 'যেকোনো ইমেইল দিয়ে যোগাযোগ করুন',

View File

@@ -1375,6 +1375,7 @@ const de = T(
rateDialogContent2: 'Ihre Unterstützung ist unsere Motivation',
laterButton: 'Später',
huaweiStore: 'Huawei AppGallery',
appStore: 'App Store',
goRate: 'Bewerten',
emailHint1: 'Wenn innerhalb von 24h keine Antwort, andere E-Mail versuchen',
emailHint2: 'Jede E-Mail ist für die Kontaktaufnahme geeignet',

View File

@@ -1386,6 +1386,7 @@ const en = T(
rateDialogContent2: 'Your support is our motivation',
laterButton: 'Later',
huaweiStore: 'Huawei AppGallery',
appStore: 'App Store',
goRate: 'Rate',
emailHint1: 'If no reply within 24h, try another email',
emailHint2: 'Any email is fine to contact',

View File

@@ -1385,6 +1385,7 @@ const es = T(
rateDialogContent2: 'Tu apoyo es nuestra motivación',
laterButton: 'Más tarde',
huaweiStore: 'Huawei AppGallery',
appStore: 'Tienda de aplicaciones',
goRate: 'Valorar',
emailHint1: 'Sin respuesta en 24h, prueba otro correo',
emailHint2: 'Cualquier correo es válido para contactar',

View File

@@ -1391,6 +1391,7 @@ const fr = T(
rateDialogContent2: 'Votre soutien est notre motivation',
laterButton: 'Plus tard',
huaweiStore: 'Huawei AppGallery',
appStore: 'App Store',
goRate: 'Évaluer',
emailHint1: 'Sans réponse sous 24h, essayez un autre e-mail',
emailHint2: 'Tout e-mail est valable pour nous contacter',

View File

@@ -1359,6 +1359,7 @@ const hi = T(
rateDialogContent2: 'आपका समर्थन हमारी प्रेरणा है',
laterButton: 'बाद में',
huaweiStore: 'Huawei AppGallery',
appStore: 'ऐप स्टोर',
goRate: 'रेट करें',
emailHint1: '24 घंटे में कोई जवाब नहीं, दूसरा ईमेल आज़माएं',
emailHint2: 'कोई भी ईमेल संपर्क के लिए ठीक है',

View File

@@ -1384,6 +1384,7 @@ const it = T(
rateDialogContent2: 'Il tuo supporto è la nostra motivazione',
laterButton: 'Più tardi',
huaweiStore: 'Huawei AppGallery',
appStore: 'App Store',
goRate: 'Valuta',
emailHint1: 'Se nessuna risposta entro 24h, prova un\'altra email',
emailHint2: 'Qualsiasi email va bene per contattarci',

View File

@@ -1337,6 +1337,7 @@ const ja = T(
rateDialogContent2: 'あなたのサポートが私たちの原動力です',
laterButton: '後で',
huaweiStore: 'Huawei AppGallery',
appStore: 'アプリストア',
goRate: '評価する',
emailHint1: '24時間以内に返信がない場合は別のメールをお試しください',
emailHint2: 'どのメールでもご連絡いただけます',

View File

@@ -1339,6 +1339,7 @@ const ko = T(
rateDialogContent2: '여러분의 지원이 우리의 원동력입니다',
laterButton: '나중에',
huaweiStore: 'Huawei AppGallery',
appStore: '앱 스토어',
goRate: '평가하기',
emailHint1: '24시간 내 답장이 없으면 다른 이메일을 시도하세요',
emailHint2: '어떤 이메일로든 연락 가능합니다',

View File

@@ -1382,6 +1382,7 @@ const pt = T(
rateDialogContent2: 'Seu apoio é nossa motivação',
laterButton: 'Mais tarde',
huaweiStore: 'Huawei AppGallery',
appStore: 'Loja de aplicativos',
goRate: 'Avaliar',
emailHint1: 'Sem resposta em 24h, tente outro e-mail',
emailHint2: 'Qualquer e-mail serve para contato',

View File

@@ -1378,6 +1378,7 @@ const ru = T(
rateDialogContent2: 'Ваша поддержка — наша мотивация',
laterButton: 'Позже',
huaweiStore: 'Huawei AppGallery',
appStore: 'Магазин приложений',
goRate: 'Оценить',
emailHint1: 'Если нет ответа 24ч, попробуйте другой email',
emailHint2: 'Любой email подходит для связи',

View File

@@ -1318,6 +1318,7 @@ const zhCN = T(
rateDialogContent2: '您的支持是我们前进的动力',
laterButton: '下次再说',
huaweiStore: '华为应用市场',
appStore: '应用商店',
goRate: '去评价',
emailHint1: '若超24小时无回复可更换其他邮箱',
emailHint2: '任意邮箱均可联系',

View File

@@ -1317,6 +1317,7 @@ const zhTW = T(
rateDialogContent2: '您的支持是我們前進的動力',
laterButton: '下次再說',
huaweiStore: '華為應用市場',
appStore: '應用商店',
goRate: '去評價',
emailHint1: '若超24小時無回覆可更換其他信箱',
emailHint2: '任意信箱均可聯繫',

View File

@@ -124,6 +124,7 @@ class TAbout {
required this.rateDialogContent2,
required this.laterButton,
required this.huaweiStore,
required this.appStore,
required this.goRate,
required this.emailHint1,
required this.emailHint2,
@@ -526,6 +527,9 @@ class TAbout {
/// 华为应用市场
final String huaweiStore;
/// 应用商店通用名称用于Android端评分跳转弹窗
final String appStore;
/// 去评价
final String goRate;
@@ -717,6 +721,7 @@ class TAbout {
'rateDialogContent2': rateDialogContent2,
'laterButton': laterButton,
'huaweiStore': huaweiStore,
'appStore': appStore,
'goRate': goRate,
'emailHint1': emailHint1,
'emailHint2': emailHint2,
@@ -1090,6 +1095,9 @@ class TAbout {
huaweiStore: map['huaweiStore']?.isNotEmpty == true
? map['huaweiStore']!
: (fallback?.huaweiStore ?? ''),
appStore: map['appStore']?.isNotEmpty == true
? map['appStore']!
: (fallback?.appStore ?? ''),
goRate: map['goRate']?.isNotEmpty == true
? map['goRate']!
: (fallback?.goRate ?? ''),

View File

@@ -17,7 +17,7 @@ import flutter_app_group_directory
import flutter_image_compress_macos
import flutter_inappwebview_macos
import flutter_local_notifications
import flutter_secure_storage_darwin
import flutter_secure_storage_macos
import flutter_tts
import flutter_webrtc
import gal
@@ -54,7 +54,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin"))
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
FlutterTtsPlugin.register(with: registry.registrar(forPlugin: "FlutterTtsPlugin"))
FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin"))
GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin"))