From ff08e6c12872439bed15579f355f2797e14e1fde Mon Sep 17 00:00:00 2001 From: Developer Date: Sun, 7 Jun 2026 08:16:20 +0800 Subject: [PATCH] =?UTF-8?q?=E9=B8=BF=E8=92=99=E7=AB=AF=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../services/image/image_import_service.dart | 6 +- .../spotlight_search_overlay.dart | 392 +++++++++--------- .../font_management_notifier.dart | 10 +- .../services/font_download_service.dart | 133 +++--- .../widgets/feedback/login_guard_widget.dart | 79 ++-- macos/Flutter/GeneratedPluginRegistrant.swift | 4 +- 6 files changed, 306 insertions(+), 318 deletions(-) diff --git a/lib/editor/services/image/image_import_service.dart b/lib/editor/services/image/image_import_service.dart index a99af031..d26530db 100644 --- a/lib/editor/services/image/image_import_service.dart +++ b/lib/editor/services/image/image_import_service.dart @@ -22,13 +22,13 @@ class ImageImportService { final result = await FilePicker.pickFiles(type: FileType.image); if (result == null || result.files.isEmpty) return null; final file = result.files.first; - // 优先通过路径读取,避免使用已废弃的 bytes 属性 + // 优先通过路径读取 if (file.path != null) { final f = File(file.path!); return await f.readAsBytes(); } - // 路径不可用时回退到 readAsBytes - return await file.readAsBytes(); + // 路径不可用时回退到 bytes 属性 + return file.bytes; } catch (e) { Log.e('图片导入失败', e); return null; diff --git a/lib/features/mine/profile/presentation/spotlight_search/spotlight_search_overlay.dart b/lib/features/mine/profile/presentation/spotlight_search/spotlight_search_overlay.dart index d1e35964..208732b7 100644 --- a/lib/features/mine/profile/presentation/spotlight_search/spotlight_search_overlay.dart +++ b/lib/features/mine/profile/presentation/spotlight_search/spotlight_search_overlay.dart @@ -75,8 +75,7 @@ class _SpotlightSearchDialog extends ConsumerStatefulWidget { _SpotlightSearchDialogState(); } -class _SpotlightSearchDialogState - extends ConsumerState<_SpotlightSearchDialog> +class _SpotlightSearchDialogState extends ConsumerState<_SpotlightSearchDialog> with SingleTickerProviderStateMixin { // ---- 控制器 ---- final _searchController = TextEditingController(); @@ -113,13 +112,10 @@ class _SpotlightSearchDialogState ); // 搜索框从上方滑入 - _slideAnimation = Tween( - begin: const Offset(0, -0.08), - end: Offset.zero, - ).animate(CurvedAnimation( - parent: _entryController, - curve: Curves.easeOutCubic, - )); + _slideAnimation = + Tween(begin: const Offset(0, -0.08), end: Offset.zero).animate( + CurvedAnimation(parent: _entryController, curve: Curves.easeOutCubic), + ); // 启动入场动画 _entryController.forward(); @@ -197,7 +193,9 @@ class _SpotlightSearchDialogState searchState.recentSearches.isNotEmpty) _buildRecentSearches(ext, searchState), if (searchState.results.isNotEmpty) - Expanded(child: _buildResults(ext, searchState)), + Expanded( + child: _buildResults(ext, searchState), + ), _buildShortcutHints(ext), ], ), @@ -270,11 +268,7 @@ class _SpotlightSearchDialogState child: Row( children: [ // 搜索图标 - Icon( - CupertinoIcons.search, - size: 20, - color: ext.textHint, - ), + Icon(CupertinoIcons.search, size: 20, color: ext.textHint), const SizedBox(width: AppSpacing.sm), // 输入框 Expanded( @@ -293,9 +287,7 @@ class _SpotlightSearchDialogState vertical: AppSpacing.sm + 2, ), onChanged: (value) { - ref - .read(spotlightSearchProvider.notifier) - .updateQuery(value); + ref.read(spotlightSearchProvider.notifier).updateQuery(value); }, ), ), @@ -303,24 +295,24 @@ class _SpotlightSearchDialogState // 清除按钮 if (state.query.isNotEmpty) GestureDetector( - onTap: () { - _searchController.clear(); - ref.read(spotlightSearchProvider.notifier).updateQuery(''); - _focusNode.requestFocus(); - }, - child: Container( - padding: const EdgeInsets.all(AppSpacing.xs), - decoration: BoxDecoration( - color: ext.overlaySubtle.withValues(alpha: 0.3), - shape: BoxShape.circle, - ), - child: Icon( - CupertinoIcons.xmark, - size: 12, - color: ext.textSecondary, - ), - ), - ) + onTap: () { + _searchController.clear(); + ref.read(spotlightSearchProvider.notifier).updateQuery(''); + _focusNode.requestFocus(); + }, + child: Container( + padding: const EdgeInsets.all(AppSpacing.xs), + decoration: BoxDecoration( + color: ext.overlaySubtle.withValues(alpha: 0.3), + shape: BoxShape.circle, + ), + child: Icon( + CupertinoIcons.xmark, + size: 12, + color: ext.textSecondary, + ), + ), + ) .animate() .fadeIn(duration: 150.ms) .scale( @@ -362,11 +354,7 @@ class _SpotlightSearchDialogState // 标题行 Row( children: [ - Icon( - CupertinoIcons.clock, - size: 14, - color: ext.textHint, - ), + Icon(CupertinoIcons.clock, size: 14, color: ext.textHint), const SizedBox(width: AppSpacing.xs), Text( '最近搜索', @@ -384,9 +372,7 @@ class _SpotlightSearchDialogState }, child: Text( '清除', - style: AppTypography.caption1.copyWith( - color: ext.accent, - ), + style: AppTypography.caption1.copyWith(color: ext.accent), ), ), ], @@ -411,49 +397,49 @@ class _SpotlightSearchDialogState label: '搜索 $keyword', button: true, child: GestureDetector( - onTap: () { - _searchController.text = keyword; - ref.read(spotlightSearchProvider.notifier).updateQuery(keyword); - _focusNode.requestFocus(); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: AppSpacing.sm, - vertical: AppSpacing.xs + 1, - ), - decoration: BoxDecoration( - color: ext.bgSecondary.withValues(alpha: 0.7), - borderRadius: AppRadius.pillBorder, - border: Border.all( - color: ext.overlaySubtle.withValues(alpha: 0.15), - width: 0.5, + onTap: () { + _searchController.text = keyword; + ref.read(spotlightSearchProvider.notifier).updateQuery(keyword); + _focusNode.requestFocus(); + }, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: AppSpacing.sm, + vertical: AppSpacing.xs + 1, + ), + decoration: BoxDecoration( + color: ext.bgSecondary.withValues(alpha: 0.7), + borderRadius: AppRadius.pillBorder, + border: Border.all( + color: ext.overlaySubtle.withValues(alpha: 0.15), + width: 0.5, + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + keyword, + style: AppTypography.caption1.copyWith( + color: ext.textSecondary, + ), + ), + const SizedBox(width: 2), + GestureDetector( + onTap: () { + ref + .read(spotlightSearchProvider.notifier) + .removeRecentSearch(keyword); + }, + child: Icon( + CupertinoIcons.xmark, + size: 10, + color: ext.textHint, + ), + ), + ], ), ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - keyword, - style: AppTypography.caption1.copyWith( - color: ext.textSecondary, - ), - ), - const SizedBox(width: 2), - GestureDetector( - onTap: () { - ref - .read(spotlightSearchProvider.notifier) - .removeRecentSearch(keyword); - }, - child: Icon( - CupertinoIcons.xmark, - size: 10, - color: ext.textHint, - ), - ), - ], - ), - ), ), ); } @@ -479,18 +465,17 @@ class _SpotlightSearchDialogState verticalOffset: 12.0, child: FadeInAnimation( child: switch (entry) { - SpotlightCategoryEntry(:final category) => - Semantics( - header: true, - child: _buildCategoryHeader(ext, category), - ), + SpotlightCategoryEntry(:final category) => Semantics( + header: true, + child: _buildCategoryHeader(ext, category), + ), SpotlightItemEntry(:final item) => _buildResultItem( - ext, - item, - state.results.indexOf(item), - state.selectedIndex, - state.query, - ), + ext, + item, + state.results.indexOf(item), + state.selectedIndex, + state.query, + ), }, ), ), @@ -511,10 +496,7 @@ class _SpotlightSearchDialogState ), child: Row( children: [ - Text( - cat.emoji, - style: const TextStyle(fontSize: 12), - ), + Text(cat.emoji, style: const TextStyle(fontSize: 12)), const SizedBox(width: AppSpacing.xs), Text( cat.label, @@ -543,90 +525,92 @@ class _SpotlightSearchDialogState button: true, selected: isSelected, child: GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () => _confirmAndNavigate(item), - child: MouseRegion( - onEnter: (_) { - // 鼠标悬停时更新选中 - ref.read(spotlightSearchProvider.notifier).selectItem(itemIndex); - }, - child: AnimatedContainer( - duration: const Duration(milliseconds: 180), - curve: Curves.easeOutCubic, - margin: const EdgeInsets.symmetric( - horizontal: AppSpacing.sm, - vertical: 1, - ), - padding: const EdgeInsets.symmetric( - horizontal: AppSpacing.sm, - vertical: AppSpacing.sm, - ), - decoration: BoxDecoration( - color: isSelected - ? ext.accent.withValues(alpha: 0.12) - : Colors.transparent, - borderRadius: AppRadius.mdBorder, - ), - child: Row( - children: [ - // 图标 - _buildItemIcon(ext, item), - const SizedBox(width: AppSpacing.sm + 2), - // 文字区域 - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // 名称(高亮关键词) - _buildHighlightedText(ext, item.name, query), - // 副标题 - if (item.subtitle != null) - Padding( - padding: const EdgeInsets.only(top: 1), - child: Text( - item.subtitle!, - style: AppTypography.caption2.copyWith( - color: ext.textHint, + behavior: HitTestBehavior.opaque, + onTap: () => _confirmAndNavigate(item), + child: MouseRegion( + onEnter: (_) { + // 鼠标悬停时更新选中 + ref.read(spotlightSearchProvider.notifier).selectItem(itemIndex); + }, + child: AnimatedContainer( + duration: const Duration(milliseconds: 180), + curve: Curves.easeOutCubic, + margin: const EdgeInsets.symmetric( + horizontal: AppSpacing.sm, + vertical: 1, + ), + padding: const EdgeInsets.symmetric( + horizontal: AppSpacing.sm, + vertical: AppSpacing.sm, + ), + decoration: BoxDecoration( + color: isSelected + ? ext.accent.withValues(alpha: 0.12) + : Colors.transparent, + borderRadius: AppRadius.mdBorder, + ), + child: Row( + children: [ + // 图标 + _buildItemIcon(ext, item), + const SizedBox(width: AppSpacing.sm + 2), + // 文字区域 + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 名称(高亮关键词) + _buildHighlightedText(ext, item.name, query), + // 副标题 + if (item.subtitle != null) + Padding( + padding: const EdgeInsets.only(top: 1), + child: Text( + item.subtitle!, + style: AppTypography.caption2.copyWith( + color: ext.textHint, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, ), - maxLines: 1, - overflow: TextOverflow.ellipsis, ), - ), - ], - ), - ), - // 分类标签 - Container( - padding: const EdgeInsets.symmetric( - horizontal: AppSpacing.sm - 2, - vertical: 2, - ), - decoration: BoxDecoration( - color: _categoryColor(item.category).withValues(alpha: 0.12), - borderRadius: AppRadius.pillBorder, - ), - child: Text( - item.category.label, - style: AppTypography.caption2.copyWith( - color: _categoryColor(item.category), - fontWeight: FontWeight.w500, + ], ), ), - ), - // 选中指示箭头 - if (isSelected) ...[ - const SizedBox(width: AppSpacing.xs), - Icon( - CupertinoIcons.chevron_right, - size: 14, - color: ext.accent, + // 分类标签 + Container( + padding: const EdgeInsets.symmetric( + horizontal: AppSpacing.sm - 2, + vertical: 2, + ), + decoration: BoxDecoration( + color: _categoryColor( + item.category, + ).withValues(alpha: 0.12), + borderRadius: AppRadius.pillBorder, + ), + child: Text( + item.category.label, + style: AppTypography.caption2.copyWith( + color: _categoryColor(item.category), + fontWeight: FontWeight.w500, + ), + ), ), + // 选中指示箭头 + if (isSelected) ...[ + const SizedBox(width: AppSpacing.xs), + Icon( + CupertinoIcons.chevron_right, + size: 14, + color: ext.accent, + ), + ], ], - ], + ), ), ), ), - ), ); } @@ -647,10 +631,7 @@ class _SpotlightSearchDialogState ], ), borderRadius: AppRadius.mdBorder, - border: Border.all( - color: catColor.withValues(alpha: 0.15), - width: 0.5, - ), + border: Border.all(color: catColor.withValues(alpha: 0.15), width: 0.5), ), child: Center( child: Text( @@ -744,10 +725,17 @@ class _SpotlightSearchDialogState } // ============================================================ - // 快捷键提示 + // 快捷键提示 — 响应式:竖屏2栏 / 横屏1栏 // ============================================================ Widget _buildShortcutHints(AppThemeExtension ext) { + final hints = [ + ('↑↓', '导航'), + ('↵', '打开'), + ('esc', '关闭'), + (io.Platform.isMacOS ? '⌘K' : 'Ctrl+J', '搜索'), + ]; + return Container( padding: const EdgeInsets.symmetric( horizontal: AppSpacing.md, @@ -761,17 +749,35 @@ class _SpotlightSearchDialogState ), ), ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - _buildHintKey(ext, '↑↓', '导航'), - _buildHintSeparator(ext), - _buildHintKey(ext, '↵', '打开'), - _buildHintSeparator(ext), - _buildHintKey(ext, 'esc', '关闭'), - _buildHintSeparator(ext), - _buildHintKey(ext, io.Platform.isMacOS ? '⌘K' : 'Ctrl+K', '搜索'), - ], + child: OrientationBuilder( + builder: (context, orientation) { + // 竖屏:2栏(Wrap自动换行,每行约2个) + if (orientation == Orientation.portrait) { + return Wrap( + alignment: WrapAlignment.center, + spacing: AppSpacing.md, + runSpacing: AppSpacing.xs, + children: hints + .map((h) => _buildHintKey(ext, h.$1, h.$2)) + .toList(), + ); + } + // 横屏:1栏单行 + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ...hints + .expand( + (h) => [ + _buildHintKey(ext, h.$1, h.$2), + _buildHintSeparator(ext), + ], + ) + .toList() + ..removeLast(), + ], + ); + }, ), ); } @@ -805,9 +811,7 @@ class _SpotlightSearchDialogState const SizedBox(width: 3), Text( label, - style: AppTypography.caption2.copyWith( - color: ext.textHint, - ), + style: AppTypography.caption2.copyWith(color: ext.textHint), ), ], ); diff --git a/lib/features/mine/settings/presentation/font_management_notifier.dart b/lib/features/mine/settings/presentation/font_management_notifier.dart index 54af6033..f1efa2b5 100644 --- a/lib/features/mine/settings/presentation/font_management_notifier.dart +++ b/lib/features/mine/settings/presentation/font_management_notifier.dart @@ -676,13 +676,14 @@ class FontManagementNotifier extends Notifier } if (zipBytes == null) { - // 使用 readAsBytes 替代已废弃的 bytes 属性 - zipBytes = await platformFile.readAsBytes(); - if (zipBytes.isEmpty) { + // 使用 bytes 属性读取文件数据 + final rawBytes = platformFile.bytes; + if (rawBytes == null || rawBytes.isEmpty) { Log.w('ZIP字体导入跳过: 无可用文件路径或数据'); AppToast.showWarning('无法读取ZIP文件数据'); return; } + zipBytes = rawBytes; } final archive = ZipDecoder().decodeBytes(zipBytes); @@ -696,8 +697,7 @@ class FontManagementNotifier extends Notifier if (name.endsWith('.ttf') || name.endsWith('.otf')) { try { final fileName = file.name.split('/').last; - final outputPath = - '${fontDir.path}/$fileName'; + final outputPath = '${fontDir.path}/$fileName'; await File(outputPath).writeAsBytes(file.content as List); final fontFamily = fileName.replaceAll( diff --git a/lib/features/mine/settings/services/font_download_service.dart b/lib/features/mine/settings/services/font_download_service.dart index ecc3bef3..fc8486ca 100644 --- a/lib/features/mine/settings/services/font_download_service.dart +++ b/lib/features/mine/settings/services/font_download_service.dart @@ -55,7 +55,8 @@ class FontDownloadService { static bool isValidFontFile(Uint8List bytes) { if (bytes.length < 4) return false; final h = bytes; - final isTtf = (h[0] == 0x00 && h[1] == 0x01 && h[2] == 0x00 && h[3] == 0x00) || + final isTtf = + (h[0] == 0x00 && h[1] == 0x01 && h[2] == 0x00 && h[3] == 0x00) || (h[0] == 0x74 && h[1] == 0x72 && h[2] == 0x75 && h[3] == 0x65); final isOtf = h[0] == 0x4F && h[1] == 0x54 && h[2] == 0x54 && h[3] == 0x4F; final isTtc = h[0] == 0x74 && h[1] == 0x74 && h[2] == 0x63 && h[3] == 0x66; @@ -86,10 +87,7 @@ class FontDownloadService { ProgressCallback? onProgress, }) async { if (pu.isWeb) { - return const FontDownloadResult( - success: false, - errorMsg: 'Web端暂不支持字体下载', - ); + return const FontDownloadResult(success: false, errorMsg: 'Web端暂不支持字体下载'); } try { @@ -104,9 +102,11 @@ class FontDownloadService { bool downloadSuccess = false; String? lastError; - for (int urlIdx = 0; - urlIdx < allUrls.length && !downloadSuccess; - urlIdx++) { + for ( + int urlIdx = 0; + urlIdx < allUrls.length && !downloadSuccess; + urlIdx++ + ) { final currentUrl = allUrls[urlIdx]; if (currentUrl.isEmpty) continue; @@ -115,9 +115,7 @@ class FontDownloadService { if (attempt > 0) { final delay = Duration(seconds: 1 << (attempt - 1)); await Future.delayed(delay); - Log.d( - '字体下载重试 [$displayName] URL#${urlIdx + 1} 第${attempt + 1}次', - ); + Log.d('字体下载重试 [$displayName] URL#${urlIdx + 1} 第${attempt + 1}次'); } await _dio.download( @@ -134,9 +132,7 @@ class FontDownloadService { if (await savedFile.exists()) { final bytes = await savedFile.readAsBytes(); if (!isValidFontFile(bytes)) { - Log.e( - '字体文件头验证失败 [$displayName]: 非 TTF/OTF/TTC 格式', - ); + Log.e('字体文件头验证失败 [$displayName]: 非 TTF/OTF/TTC 格式'); await savedFile.delete(); lastError = '文件格式无效'; continue; @@ -176,10 +172,7 @@ class FontDownloadService { ); } catch (e) { Log.e('字体下载异常: $displayName', e); - return FontDownloadResult( - success: false, - errorMsg: '下载异常: $e', - ); + return FontDownloadResult(success: false, errorMsg: '下载异常: $e'); } } @@ -189,10 +182,7 @@ class FontDownloadService { ProgressCallback? onProgress, }) async { if (pu.isWeb) { - return const FontDownloadResult( - success: false, - errorMsg: 'Web端暂不支持字体下载', - ); + return const FontDownloadResult(success: false, errorMsg: 'Web端暂不支持字体下载'); } try { @@ -215,8 +205,7 @@ class FontDownloadService { fontFamily = 'CustomFont_${DateTime.now().millisecondsSinceEpoch}'; } - final displayName = - name?.isNotEmpty == true ? name! : fontFamily; + final displayName = name?.isNotEmpty == true ? name! : fontFamily; final fileName = '$fontFamily.$ext'; final savePath = '${fontDir.path}/$fileName'; @@ -246,9 +235,7 @@ class FontDownloadService { if (await savedFile.exists()) { final bytes = await savedFile.readAsBytes(); if (!isValidFontFile(bytes)) { - Log.e( - 'URL字体文件头验证失败 [$displayName]: 非 TTF/OTF/TTC 格式', - ); + Log.e('URL字体文件头验证失败 [$displayName]: 非 TTF/OTF/TTC 格式'); await savedFile.delete(); lastError = '文件格式无效'; continue; @@ -259,14 +246,10 @@ class FontDownloadService { } } on DioException catch (e) { lastError = e.message ?? '网络错误'; - Log.w( - 'URL字体下载失败 [$displayName] 第${attempt + 1}次: $lastError', - ); + Log.w('URL字体下载失败 [$displayName] 第${attempt + 1}次: $lastError'); } catch (e) { lastError = e.toString(); - Log.w( - 'URL字体下载异常 [$displayName] 第${attempt + 1}次: $lastError', - ); + Log.w('URL字体下载异常 [$displayName] 第${attempt + 1}次: $lastError'); } } @@ -289,20 +272,14 @@ class FontDownloadService { ); } catch (e) { Log.e('URL字体下载异常', e); - return FontDownloadResult( - success: false, - errorMsg: '下载失败: $e', - ); + return FontDownloadResult(success: false, errorMsg: '下载失败: $e'); } } static Future> importLocalFonts() async { if (pu.isWeb) { return [ - const FontDownloadResult( - success: false, - errorMsg: 'Web端暂不支持字体导入', - ), + const FontDownloadResult(success: false, errorMsg: 'Web端暂不支持字体导入'), ]; } @@ -322,8 +299,7 @@ class FontDownloadService { final fileName = platformFile.name; final name = fileName.replaceAll(RegExp(r'\.(ttf|otf)$'), ''); final fontFamily = name.replaceAll(' ', ''); - final destPath = - '${fontDir.path}/$fileName'; + final destPath = '${fontDir.path}/$fileName'; Uint8List? fontBytes; @@ -340,9 +316,9 @@ class FontDownloadService { } if (fontBytes == null) { - // 使用 readAsBytes 替代已废弃的 bytes 属性 - final rawBytes = await platformFile.readAsBytes(); - if (rawBytes.isNotEmpty) { + // 使用 bytes 属性读取文件数据 + final rawBytes = platformFile.bytes; + if (rawBytes != null && rawBytes.isNotEmpty) { fontBytes = rawBytes; if (await File(destPath).exists()) { await File(destPath).delete(); @@ -350,59 +326,62 @@ class FontDownloadService { await File(destPath).writeAsBytes(rawBytes); } else { Log.w('字体导入跳过: $fileName — 无可用文件路径或数据'); - results.add(FontDownloadResult( - success: false, - errorMsg: '$name 无法读取文件数据', - fontFamily: fontFamily, - displayName: name, - )); + results.add( + FontDownloadResult( + success: false, + errorMsg: '$name 无法读取文件数据', + fontFamily: fontFamily, + displayName: name, + ), + ); continue; } } - if (!isValidFontFile(fontBytes)) { + if (!isValidFontFile(fontBytes!)) { if (await File(destPath).exists()) { await File(destPath).delete(); } - results.add(FontDownloadResult( - success: false, - errorMsg: '$name 格式无效', - fontFamily: fontFamily, - displayName: name, - )); + results.add( + FontDownloadResult( + success: false, + errorMsg: '$name 格式无效', + fontFamily: fontFamily, + displayName: name, + ), + ); continue; } final fileSize = await File(destPath).length(); - results.add(FontDownloadResult( - success: true, - savePath: destPath, - fileSize: fileSize, - fontFamily: fontFamily, - displayName: name, - )); + results.add( + FontDownloadResult( + success: true, + savePath: destPath, + fileSize: fileSize, + fontFamily: fontFamily, + displayName: name, + ), + ); } catch (e) { Log.e('单个字体导入失败: ${platformFile.name}', e); - results.add(FontDownloadResult( - success: false, - errorMsg: '${platformFile.name} 导入失败: $e', - )); + results.add( + FontDownloadResult( + success: false, + errorMsg: '${platformFile.name} 导入失败: $e', + ), + ); } } return results; } catch (e) { Log.e('字体导入失败', e); - return [ - FontDownloadResult(success: false, errorMsg: '导入失败: $e'), - ]; + return [FontDownloadResult(success: false, errorMsg: '导入失败: $e')]; } } - static Future loadFontIntoEngine( - String fontFamily, - String path, - ) async { + static Future loadFontIntoEngine(String fontFamily, String path) async { try { final file = File(path); if (!await file.exists()) return false; diff --git a/lib/shared/widgets/feedback/login_guard_widget.dart b/lib/shared/widgets/feedback/login_guard_widget.dart index a82dc939..2625fac4 100644 --- a/lib/shared/widgets/feedback/login_guard_widget.dart +++ b/lib/shared/widgets/feedback/login_guard_widget.dart @@ -84,47 +84,52 @@ class LoginGuardWidget extends ConsumerWidget { return Semantics( label: '$displayTitle. $displaySubtitle', - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: AppSpacing.md, - vertical: AppSpacing.xxl, - ), - child: GlassContainer( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(icon, size: 48, color: ext.textHint), - const SizedBox(height: AppSpacing.md), - Text( - displayTitle, - style: AppTypography.title3.copyWith(color: ext.textPrimary), - ), - const SizedBox(height: AppSpacing.sm), - Text( - displaySubtitle, - style: AppTypography.subhead.copyWith(color: ext.textSecondary), - textAlign: TextAlign.center, - ), - const SizedBox(height: AppSpacing.md), - CupertinoButton( - color: ext.accent, - borderRadius: AppRadius.pillBorder, - onPressed: () { - context.appPush(AppRoutes.login); - onLogin?.call(); - }, - child: Text( - displayButtonText, - style: AppTypography.body.copyWith( - color: CupertinoColors.white, - fontWeight: FontWeight.w600, + child: Center( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: AppSpacing.lg, + vertical: AppSpacing.xxl, + ), + child: GlassContainer( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon(icon, size: 48, color: ext.textHint), + const SizedBox(height: AppSpacing.md), + Text( + displayTitle, + style: AppTypography.title3.copyWith(color: ext.textPrimary), ), - ), + const SizedBox(height: AppSpacing.sm), + Text( + displaySubtitle, + style: AppTypography.subhead.copyWith( + color: ext.textSecondary, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: AppSpacing.md), + CupertinoButton( + color: ext.accent, + borderRadius: AppRadius.pillBorder, + onPressed: () { + context.appPush(AppRoutes.login); + onLogin?.call(); + }, + child: Text( + displayButtonText, + style: AppTypography.body.copyWith( + color: CupertinoColors.white, + fontWeight: FontWeight.w600, + ), + ), + ), + ], ), - ], + ), ), ), - ), ); } } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 6a19590a..d29810a7 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -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 @@ -55,7 +55,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"))