feat: 重构 Reminder Notification 系统并更新应用包名

This commit is contained in:
qzl
2026-03-30 18:36:57 +08:00
parent 9fb2a6857b
commit 91bf3c3f96
90 changed files with 5133 additions and 3017 deletions
@@ -160,7 +160,7 @@ class _EditProfileScreenState extends State<EditProfileScreen> {
);
return;
}
if (newUsername.length < 3 || newUsername.length > 30) {
if (newUsername.length > 30) {
Toast.show(
context,
context.l10n.settingsEditProfileUsernameLengthInvalid,
@@ -1,11 +1,15 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:social_app/core/config/env.dart';
import 'package:social_app/app/di/injection.dart';
import 'package:social_app/app/router/app_routes.dart';
import 'package:social_app/app/services/app_prewarm_orchestrator.dart';
import 'package:social_app/core/l10n/l10n.dart';
import 'package:social_app/core/theme/design_tokens.dart';
import 'package:social_app/core/auth/session_controller.dart';
import 'package:social_app/data/cache/cache_store.dart';
import 'package:social_app/core/inbox/inbox_sync_store.dart';
import 'package:social_app/features/contacts/data/models/user_profile.dart';
import 'package:social_app/features/contacts/data/repositories/friend_repository.dart';
import 'package:social_app/shared/widgets/app_button.dart';
@@ -14,6 +18,7 @@ import 'package:social_app/shared/widgets/app_pressable.dart';
import 'package:social_app/shared/widgets/destructive_action_sheet.dart';
import 'package:social_app/shared/widgets/toast/toast.dart';
import 'package:social_app/shared/widgets/toast/toast_type.dart';
import 'package:social_app/shared/widgets/shared_divider.dart';
import 'package:social_app/core/utils/phone_display_formatter.dart';
import 'package:social_app/features/settings/data/apis/settings_api.dart';
import 'package:social_app/features/settings/data/apis/automation_jobs_api.dart';
@@ -171,21 +176,24 @@ class _SettingsScreenState extends State<SettingsScreen> {
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 64,
height: 64,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(32),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withValues(alpha: 0.2),
blurRadius: 12,
offset: const Offset(0, 4),
),
],
GestureDetector(
onTap: _onTapEditProfile,
child: Container(
width: 64,
height: 64,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(32),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withValues(alpha: 0.2),
blurRadius: 12,
offset: const Offset(0, 4),
),
],
),
clipBehavior: Clip.antiAlias,
child: _buildAvatarImage(_user?.avatarUrl),
),
clipBehavior: Clip.antiAlias,
child: _buildAvatarImage(_user?.avatarUrl),
),
const SizedBox(width: AppSpacing.lg),
Expanded(
@@ -599,19 +607,25 @@ class _SettingsScreenState extends State<SettingsScreen> {
title: context.l10n.settingsMenuNotifications,
onTap: () {},
),
_buildDivider(),
SharedDivider(),
_buildMenuItem(
icon: Icons.bookmark,
title: context.l10n.memoryTitle,
onTap: () => context.push(AppRoutes.settingsMemory),
),
_buildDivider(),
SharedDivider(),
_buildMenuItem(
icon: Icons.system_update,
title: context.l10n.settingsMenuCheckUpdates,
trailing: 'v${Env.version}',
onTap: _checkForUpdates,
),
SharedDivider(),
_buildMenuItem(
icon: Icons.cleaning_services_outlined,
title: context.l10n.settingsMenuClearCache,
onTap: _clearLocalCache,
),
],
),
);
@@ -673,16 +687,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
);
}
Widget _buildDivider() {
final colorScheme = Theme.of(context).colorScheme;
return Container(
height: 1,
margin: const EdgeInsets.symmetric(horizontal: 14),
color: colorScheme.outlineVariant,
);
}
Future<void> _onTapEditProfile() async {
final changed = await context.push<bool>(AppRoutes.settingsEditProfile);
if (changed == true && mounted) {
@@ -769,11 +773,17 @@ class _SettingsScreenState extends State<SettingsScreen> {
);
if (shouldUpdate == true && result.downloadUrl != null && mounted) {
Toast.show(
context,
context.l10n.settingsDownloadLink(result.downloadUrl!),
type: ToastType.info,
);
final uri = Uri.tryParse(result.downloadUrl!);
final launched =
uri != null &&
await launchUrl(uri, mode: LaunchMode.externalApplication);
if (!launched && mounted) {
Toast.show(
context,
context.l10n.settingsDownloadLink(result.downloadUrl!),
type: ToastType.info,
);
}
}
} catch (e) {
if (!mounted) return;
@@ -785,6 +795,46 @@ class _SettingsScreenState extends State<SettingsScreen> {
}
}
Future<void> _clearLocalCache() async {
final confirmed = await showDestructiveActionSheet(
context,
title: context.l10n.settingsClearCacheTitle,
message: context.l10n.settingsClearCacheMessage,
confirmText: context.l10n.settingsClearCacheAction,
);
if (!confirmed || !mounted) {
return;
}
try {
await sl<HybridCacheStore>().clearByPrefix('cache:');
final userId = _user?.id;
if (userId != null && userId.isNotEmpty) {
await sl<AppPrewarmOrchestrator>().ensureStartedFor(userId);
}
await sl<InboxSyncStore>().refreshSnapshot();
if (!mounted) {
return;
}
Toast.show(
context,
context.l10n.settingsClearCacheSuccess,
type: ToastType.success,
);
} catch (_) {
if (!mounted) {
return;
}
Toast.show(
context,
context.l10n.settingsClearCacheFailed,
type: ToastType.error,
);
}
}
Widget _buildLogoutAction() {
return SizedBox(
width: double.infinity,