From 9a58f6ca19f7be86e90d1b742bef419967f32e53 Mon Sep 17 00:00:00 2001 From: Developer Date: Tue, 31 Mar 2026 07:56:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E7=BB=86=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 46 +- lib/views/active/rate.dart | 2 +- lib/views/home/home-load.dart | 35 ++ lib/views/home/home_page.dart | 123 +++--- lib/views/home/home_part.dart | 18 +- lib/views/profile/app-info.dart | 44 +- lib/views/profile/guide/permission.dart | 392 ++++++++++-------- lib/views/profile/settings/app_fun.dart | 149 ++++++- lib/views/profile/settings/learn-us.dart | 116 ++++++ macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 9 + pubspec.yaml | 4 + 12 files changed, 683 insertions(+), 257 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7786e9..c698694 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,48 @@ All notable changes to this project will be documented in this file. --- +## [1.3.9] - 2026-03-31 + +### 新增 +- 🆔 **UDID 设备信息显示** + - 在应用信息页面的设备信息列表中添加 UDID 显示 + - 使用 `flutter_udid` 库获取跨平台设备唯一标识 + - 支持点击复制 UDID 功能,带主题色 SnackBar 提示 + - 将 AppInfoPage 从 StatelessWidget 改为 StatefulWidget + - 添加 `_loadUdid()` 方法异步加载 UDID + - 在技术栈卡片中添加 flutter_udid 说明 + - 在开源协议对话框中添加 flutter_udid 条目 + - 涉及文件: + - `lib/views/profile/app-info.dart` - 添加 UDID 获取和显示 + +### 新增 +- 👥 **QQ 交流群卡片** + - 在了解我们页面的"官方网站"卡片下方添加 QQ 群卡片 + - 群号显示:271129018 + - 点击群号可复制到剪贴板 + - 蓝色主题色(Icons.group) + - 提示"💡 点击群号可复制" + - 涉及文件: + - `lib/views/profile/settings/learn-us.dart` - 添加 QQ 群卡片 + +--- + +## [1.3.8] - 2026-03-31 + +### 新增 +- 🎛️ **隐藏次要按钮功能** + - 在功能设置页面添加"隐藏次要按钮"开关 + - 开启后隐藏主页的"上一条"和"分享"悬浮按钮 + - 默认关闭,状态保存到 SharedPreferences + - 使用 `SecondaryButtonsManager` 单例管理状态 + - 实时响应开关状态变化,无需重启应用 + - 涉及文件: + - `lib/views/profile/settings/app_fun.dart` - 添加开关和状态管理 + - `lib/views/home/home-load.dart` - 添加 SecondaryButtonsManager 管理类 + - `lib/views/home/home_page.dart` - 使用 ValueListenableBuilder 监听状态变化 + +--- + ## [1.3.7] - 2026-03-31 ### 新增 @@ -55,7 +97,9 @@ All notable changes to this project will be documented in this file. ## 软件特性功能 ### 已开发完成 -- � **诗词卡片截图分享功能** - 主页点赞按钮上方添加悬浮分享按钮、点击生成诗词卡片高清图片并分享、使用RepaintBoundary和GlobalKey实现Widget截图、集成share_plus库实现跨平台分享、包含生成中/成功/失败提示 +- 🎛️ **隐藏次要按钮功能** - 在功能设置页面添加开关、开启后隐藏主页的"上一条"和"分享"悬浮按钮、默认关闭、状态保存到SharedPreferences、使用SecondaryButtonsManager单例管理、实时响应开关状态变化无需重启 + - 优先级:3 +- 📸 **诗词卡片截图分享功能** - 主页点赞按钮上方添加悬浮分享按钮、点击生成诗词卡片高清图片并分享、使用RepaintBoundary和GlobalKey实现Widget截图、集成share_plus库实现跨平台分享、包含生成中/成功/失败提示 - 优先级:4 - 📜 **诗词投稿功能** - 新增投稿页面、支持诗词收录申请表单、包含参考语句/分类选择/诗人和标题/关键词/诗词介绍/人机验证、实现相似度检测防止重复提交、平台字段自动获取设备类型 - 优先级:3 diff --git a/lib/views/active/rate.dart b/lib/views/active/rate.dart index 215b35d..b5cde2c 100644 --- a/lib/views/active/rate.dart +++ b/lib/views/active/rate.dart @@ -286,7 +286,7 @@ class _RatePageState extends State child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildSectionTitle('本周活跃趋势'), + _buildSectionTitle('本周活跃趋势(生成图片分享)'), const SizedBox(height: 16), // 热力图 - 使用 Wrap 防止溢出 Container( diff --git a/lib/views/home/home-load.dart b/lib/views/home/home-load.dart index 9d1ac3e..02b5eda 100644 --- a/lib/views/home/home-load.dart +++ b/lib/views/home/home-load.dart @@ -8,6 +8,41 @@ import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../../utils/http/poetry_api.dart'; +class SecondaryButtonsManager { + static const String _hideSecondaryButtonsKey = 'hide_secondary_buttons'; + + static SecondaryButtonsManager? _instance; + bool _isHidden = false; + final ValueNotifier _hiddenNotifier = ValueNotifier(false); + + SecondaryButtonsManager._internal(); + + factory SecondaryButtonsManager() { + _instance ??= SecondaryButtonsManager._internal(); + return _instance!; + } + + Future init() async { + final prefs = await SharedPreferences.getInstance(); + _isHidden = prefs.getBool(_hideSecondaryButtonsKey) ?? false; + _hiddenNotifier.value = _isHidden; + } + + bool get isHidden => _isHidden; + ValueNotifier get hiddenNotifier => _hiddenNotifier; + + Future setHidden(bool hidden) async { + _isHidden = hidden; + _hiddenNotifier.value = hidden; + final prefs = await SharedPreferences.getInstance(); + await prefs.setBool(_hideSecondaryButtonsKey, hidden); + } + + void dispose() { + _hiddenNotifier.value = false; + } +} + class AutoRefreshManager { static const String _autoRefreshKey = 'auto_refresh_enabled'; static const Duration _refreshInterval = Duration(seconds: 5); diff --git a/lib/views/home/home_page.dart b/lib/views/home/home_page.dart index aa86df5..06d234d 100644 --- a/lib/views/home/home_page.dart +++ b/lib/views/home/home_page.dart @@ -60,12 +60,17 @@ class _HomePageState extends State _initDebugInfo(); _initOfflineDataManager(); _initAudioManager(); + _initSecondaryButtonsManager(); // 延迟加载诗词,确保页面先显示 WidgetsBinding.instance.addPostFrameCallback((_) { _loadPoetry(); }); } + Future _initSecondaryButtonsManager() async { + await SecondaryButtonsManager().init(); + } + Future _initAudioManager() async { await AudioManager().init(); } @@ -772,63 +777,71 @@ class _HomePageState extends State onRefresh: _refreshPoetry, child: FadeTransition( opacity: _fadeAnimation, - child: Stack( - children: [ - SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics(), // 确保可以下拉刷新 - padding: const EdgeInsets.symmetric(vertical: 16), - child: Column( - children: [ - PoetryCard( - poetryData: _poetryData!, - keywordList: _keywordList, - onTap: _loadNextPoetry, - sectionLoadingStates: _sectionLoadingStates, - repaintKey: _repaintKey, + child: ValueListenableBuilder( + valueListenable: SecondaryButtonsManager().hiddenNotifier, + builder: (context, hideSecondaryButtons, child) { + return Stack( + children: [ + SingleChildScrollView( + physics: + const AlwaysScrollableScrollPhysics(), // 确保可以下拉刷新 + padding: const EdgeInsets.symmetric(vertical: 16), + child: Column( + children: [ + PoetryCard( + poetryData: _poetryData!, + keywordList: _keywordList, + onTap: _loadNextPoetry, + sectionLoadingStates: _sectionLoadingStates, + repaintKey: _repaintKey, + ), + const SizedBox(height: 160), // 为悬浮按钮留出更多空间 + ], ), - const SizedBox(height: 160), // 为悬浮按钮留出更多空间 - ], - ), - ), - // 调试信息气泡 - Positioned( - bottom: 66, - left: 0, - right: 0, - child: Center(child: _buildDebugInfoBubble()), - ), - // 悬浮上一条按钮 - 左边上方 - Positioned( - left: 16, - bottom: 100, - child: FloatingPreviousButton( - onPrevious: _loadPreviousPoetry, - ), - ), - // 悬浮下一条按钮 - 左边下方 - Positioned( - left: 16, - bottom: 32, - child: FloatingNextButton(onNext: _loadNextPoetry), - ), - // 悬浮分享按钮 - 右边上方 - Positioned( - right: 16, - bottom: 100, - child: FloatingShareButton(onShare: _sharePoetryImage), - ), - // 悬浮点赞按钮 - 右边(仅在线状态显示) - if (isOnline) - Positioned( - right: 16, - bottom: 32, - child: FloatingLikeButton( - isLiked: _isLiked, - isLoadingLike: _isLoadingLike, - onToggleLike: _toggleLike, ), - ), - ], + // 调试信息气泡 + Positioned( + bottom: 66, + left: 0, + right: 0, + child: Center(child: _buildDebugInfoBubble()), + ), + // 悬浮上一条按钮 - 左边上方(根据设置显示/隐藏) + if (!hideSecondaryButtons) + Positioned( + left: 16, + bottom: 100, + child: FloatingPreviousButton( + onPrevious: _loadPreviousPoetry, + ), + ), + // 悬浮下一条按钮 - 左边下方 + Positioned( + left: 16, + bottom: 32, + child: FloatingNextButton(onNext: _loadNextPoetry), + ), + // 悬浮分享按钮 - 右边上方(根据设置显示/隐藏) + if (!hideSecondaryButtons) + Positioned( + right: 16, + bottom: 100, + child: FloatingShareButton(onShare: _sharePoetryImage), + ), + // 悬浮点赞按钮 - 右边(仅在线状态显示) + if (isOnline) + Positioned( + right: 16, + bottom: 32, + child: FloatingLikeButton( + isLiked: _isLiked, + isLoadingLike: _isLoadingLike, + onToggleLike: _toggleLike, + ), + ), + ], + ); + }, ), ), ); diff --git a/lib/views/home/home_part.dart b/lib/views/home/home_part.dart index 2737351..0852b08 100644 --- a/lib/views/home/home_part.dart +++ b/lib/views/home/home_part.dart @@ -158,7 +158,7 @@ class _PoetryCardState extends State { ], ), ), - if (_showCopyTip) _buildCopyTip(), + _buildCopyTip(), ], ), ); @@ -225,6 +225,10 @@ class _PoetryCardState extends State { } Widget _buildCopyTip() { + if (!_globalTipsEnabled || !_showCopyTip) { + return const SizedBox.shrink(); + } + return Positioned( top: 56, right: 24, @@ -243,21 +247,21 @@ class _PoetryCardState extends State { ), ], ), - child: Row( + child: const Row( mainAxisSize: MainAxisSize.min, children: [ - const Icon(Icons.info_outline, color: Colors.white, size: 16), - const SizedBox(width: 6), + Icon(Icons.info_outline, color: Colors.white, size: 16), + SizedBox(width: 6), Text( - _globalTipsEnabled ? '点击任意区域加载下一条,长按复制,下拉刷新' : '', + '点击任意区域加载下一条,长按复制,下拉刷新', style: TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w500, ), ), - const SizedBox(width: 4), - const Icon(Icons.close, color: Colors.white, size: 14), + SizedBox(width: 4), + Icon(Icons.close, color: Colors.white, size: 14), ], ), ), diff --git a/lib/views/profile/app-info.dart b/lib/views/profile/app-info.dart index 5564466..d888a8f 100644 --- a/lib/views/profile/app-info.dart +++ b/lib/views/profile/app-info.dart @@ -4,16 +4,47 @@ import 'dart:io' as io show Platform; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:platform_info/platform_info.dart'; +import 'package:flutter_udid/flutter_udid.dart'; import '../../../constants/app_constants.dart'; /// 时间: 2026-03-26 /// 功能: 应用信息页面 /// 介绍: 展示应用版本、技术栈、构建信息、设备信息等 -/// 最新变化: 新建页面 +/// 最新变化: 添加 UDID 显示 -class AppInfoPage extends StatelessWidget { +class AppInfoPage extends StatefulWidget { const AppInfoPage({super.key}); + @override + State createState() => _AppInfoPageState(); +} + +class _AppInfoPageState extends State { + String _udid = '获取中...'; + + @override + void initState() { + super.initState(); + _loadUdid(); + } + + Future _loadUdid() async { + try { + final String udid = await FlutterUdid.udid; + if (mounted) { + setState(() { + _udid = udid; + }); + } + } catch (e) { + if (mounted) { + setState(() { + _udid = '获取失败'; + }); + } + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -203,6 +234,7 @@ class AppInfoPage extends StatelessWidget { _buildInfoItem('Flutter', '跨平台UI框架', Icons.flutter_dash), _buildInfoItem('Dart', '编程语言', Icons.code), _buildInfoItem('shared_preferences', '本地存储', Icons.storage), + _buildInfoItem('flutter_udid', '设备唯一标识', Icons.perm_identity), ], ), ); @@ -329,6 +361,7 @@ class AppInfoPage extends StatelessWidget { {'name': 'Shared Preferences', 'license': 'BSD 3-Clause'}, {'name': 'Dio', 'license': 'MIT'}, {'name': 'Platform Info', 'license': 'MIT'}, + {'name': 'flutter_udid', 'license': 'MIT'}, ]; showDialog( @@ -448,7 +481,6 @@ class AppInfoPage extends StatelessWidget { const Divider(height: 1), _buildInfoItem('后端语言', 'PHP', Icons.php), _buildInfoItem('Web服务器', 'Nginx', Icons.web), - // _buildInfoItem('更新日志', '更现代的玻璃拟态设计风格,紫色更浓郁', Icons.devices), ], ), ); @@ -592,6 +624,7 @@ class AppInfoPage extends StatelessWidget { _buildInfoItem('设备类型', deviceType, Icons.devices), _buildInfoItem('构建模式', buildMode, Icons.build), _buildInfoItem('运行环境', runtimeEnv, Icons.code), + _buildCopyableItem(context, 'UDID', _udid, Icons.perm_identity), Padding( padding: const EdgeInsets.all(16), child: Container( @@ -781,10 +814,7 @@ class AppInfoPage extends StatelessWidget { ), ], ), - child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - - ], - ), + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: []), ); } diff --git a/lib/views/profile/guide/permission.dart b/lib/views/profile/guide/permission.dart index d1a5e2c..2c82981 100644 --- a/lib/views/profile/guide/permission.dart +++ b/lib/views/profile/guide/permission.dart @@ -50,21 +50,20 @@ class _PermissionPageState extends State { elevation: 0, centerTitle: true, leading: IconButton( - icon: const Icon(Icons.arrow_back), + icon: Icon(Icons.arrow_back, color: AppConstants.primaryColor), onPressed: () => Navigator.pop(context), ), + actions: [ + IconButton( + icon: Icon(Icons.info_outline, color: AppConstants.primaryColor), + onPressed: _showPermissionInfoDialog, + ), + ], ), body: ListView( padding: const EdgeInsets.all(16), children: [ - _buildPermissionGroup('基础权限', [ - _buildPermissionItem( - '震动反馈', - '操作时的震动反馈,提升交互体验', - Icons.vibration, - _vibrationEnabled, - null, - ), + _buildPermissionGroup('权限列表', [ _buildPermissionItem( '网络访问', '访问网络获取诗词内容和数据', @@ -72,6 +71,14 @@ class _PermissionPageState extends State { _networkEnabled, null, ), + _buildPermissionItem( + '震动反馈', + '操作时的震动反馈,提升交互体验', + Icons.vibration, + _vibrationEnabled, + null, + ), + _buildPermissionItem( '剪切板', '复制诗词内容到剪切板', @@ -79,15 +86,35 @@ class _PermissionPageState extends State { _clipboardEnabled, null, ), + _buildPermissionItem( + '播放声音', + '播放内置提示音', + Icons.audio_file, + _clipboardEnabled, + null, + ), + _buildPermissionItem( + '分享能力', + '调用系统分享接口', + Icons.share, + _clipboardEnabled, + null, + ), ]), const SizedBox(height: 16), _buildPermissionGroup('权限说明', [ _buildInfoItem('震动反馈', '用于点赞、收藏等操作的触觉反馈,提升用户体验。'), _buildInfoItem('网络访问', '用于获取诗词内容、排行榜数据、用户信息等。'), _buildInfoItem('剪切板', '用于复制诗词内容,方便用户分享和记录。'), + _buildInfoItem('播放声音', '用于主页点击提示音,提升用户体验。'), + _buildInfoItem('分享能力', '用于分享诗词内容到社交媒体平台。'), ]), const SizedBox(height: 16), + _buildSandboxInfoCard(), + const SizedBox(height: 16), _buildProjectSupplement(), + const SizedBox(height: 24), + _buildBottomTip(), ], ), ); @@ -229,7 +256,7 @@ class _PermissionPageState extends State { fontWeight: FontWeight.w500, ), ), - const SizedBox(height: 4), + // const SizedBox(height: 4), Text( description, style: TextStyle( @@ -292,18 +319,18 @@ class _PermissionPageState extends State { Icons.lightbulb, () => _showSuggestionDialog(), ), - _buildSupplementItem( - 'Bug报告', - '报告遇到的问题', - Icons.bug_report, - () => _showBugReportDialog(), - ), - _buildSupplementItem( - '参与开发', - '成为贡献者', - Icons.code, - () => _showContributionDialog(), - ), + // _buildSupplementItem( + // 'Bug报告', + // '报告遇到的问题', + // Icons.bug_report, + // () => _showBugReportDialog(), + // ), + // _buildSupplementItem( + // '参与开发', + // '成为贡献者', + // Icons.code, + // () => _showContributionDialog(), + // ), ], ), ); @@ -373,19 +400,33 @@ class _PermissionPageState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - '感谢您的反馈!请详细描述您遇到的问题或建议。', - style: TextStyle(fontSize: 14, height: 1.5), - ), - const SizedBox(height: 16), - TextField( - maxLines: 5, - decoration: InputDecoration( - hintText: '请输入您的反馈内容...', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), + RichText( + text: TextSpan( + style: const TextStyle( + fontSize: 14, + height: 1.5, + color: Colors.black87, ), - contentPadding: const EdgeInsets.all(12), + children: [ + const TextSpan(text: '软件内暂时无法反馈,请前往应用商店搜索 '), + TextSpan( + text: '情景诗词', + style: TextStyle( + color: AppConstants.primaryColor, + fontWeight: FontWeight.bold, + ), + ), + const TextSpan(text: ' 在详细页面 点击提交心愿单'), + ], + ), + ), + const SizedBox(height: 12), + Text( + '记得五星好评 ⭐', + style: TextStyle( + fontSize: 14, + color: AppConstants.primaryColor, + fontWeight: FontWeight.w500, ), ), ], @@ -393,23 +434,10 @@ class _PermissionPageState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('取消'), - ), - ElevatedButton( - onPressed: () { - Navigator.pop(context); - ScaffoldMessenger.of( - context, - ).showSnackBar(const SnackBar(content: Text('反馈已提交,感谢您的支持!'))); - }, - style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), + child: Text( + '确定', + style: TextStyle(color: AppConstants.primaryColor), ), - child: const Text('提交'), ), ], ), @@ -432,19 +460,33 @@ class _PermissionPageState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - '我们非常期待您的创意!请描述您希望添加的功能。', - style: TextStyle(fontSize: 14, height: 1.5), - ), - const SizedBox(height: 16), - TextField( - maxLines: 5, - decoration: InputDecoration( - hintText: '请输入您的功能建议...', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), + RichText( + text: TextSpan( + style: const TextStyle( + fontSize: 14, + height: 1.5, + color: Colors.black87, ), - contentPadding: const EdgeInsets.all(12), + children: [ + const TextSpan(text: '软件内暂时无法反馈,请前往应用商店搜索 '), + TextSpan( + text: '情景诗词', + style: TextStyle( + color: AppConstants.primaryColor, + fontWeight: FontWeight.bold, + ), + ), + const TextSpan(text: ' 在详细页面 点击提交心愿单'), + ], + ), + ), + const SizedBox(height: 12), + Text( + '记得五星好评 ⭐', + style: TextStyle( + fontSize: 14, + color: AppConstants.primaryColor, + fontWeight: FontWeight.w500, ), ), ], @@ -452,148 +494,166 @@ class _PermissionPageState extends State { actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('取消'), - ), - ElevatedButton( - onPressed: () { - Navigator.pop(context); - ScaffoldMessenger.of( - context, - ).showSnackBar(const SnackBar(content: Text('建议已提交,我们会认真考虑!'))); - }, - style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), + child: Text( + '确定', + style: TextStyle(color: AppConstants.primaryColor), ), - child: const Text('提交'), ), ], ), ); } - void _showBugReportDialog() { + void _showPermissionInfoDialog() { showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: Row( children: [ - Icon(Icons.bug_report, color: AppConstants.primaryColor), + Icon(Icons.info, color: AppConstants.primaryColor), const SizedBox(width: 8), - const Text('Bug报告'), + const Text('基础权限说明'), ], ), - content: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - '请详细描述遇到的问题,我们会尽快修复。', - style: TextStyle(fontSize: 14, height: 1.5), - ), - const SizedBox(height: 16), - TextField( - maxLines: 5, - decoration: InputDecoration( - hintText: '请描述您遇到的问题...', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - contentPadding: const EdgeInsets.all(12), - ), - ), - ], + content: const Text( + '系统赋予的基础软件权限无法拒绝;自带权限默认开启,用户无需动态授权,系统层关闭后,将无法正常使用应用。', + style: TextStyle(fontSize: 14, height: 1.5), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('取消'), - ), - ElevatedButton( - onPressed: () { - Navigator.pop(context); - ScaffoldMessenger.of( - context, - ).showSnackBar(const SnackBar(content: Text('Bug报告已提交,感谢您的反馈!'))); - }, - style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), + child: Text( + '确定', + style: TextStyle(color: AppConstants.primaryColor), ), - child: const Text('提交'), ), ], ), ); } - void _showContributionDialog() { - showDialog( - context: context, - builder: (context) => AlertDialog( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), - title: Row( - children: [ - Icon(Icons.code, color: AppConstants.primaryColor), - const SizedBox(width: 8), - const Text('参与开发'), - ], - ), - content: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - '欢迎参与项目开发!请选择您希望参与的方式。', - style: TextStyle(fontSize: 14, height: 1.5), - ), - const SizedBox(height: 16), - _buildContributionOption('代码贡献', '提交代码改进'), - _buildContributionOption('文档完善', '完善项目文档'), - _buildContributionOption('测试反馈', '提供测试反馈'), - _buildContributionOption('设计建议', 'UI/UX设计建议'), - ], - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text('关闭'), - ), - ], - ), - ); - } - - Widget _buildContributionOption(String title, String description) { + Widget _buildSandboxInfoCard() { return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(12), + padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: Colors.grey[50], - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Colors.grey.withValues(alpha: 0.2)), + color: Colors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.05), + blurRadius: 10, + offset: const Offset(0, 2), + ), + ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - title, - style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: AppConstants.primaryColor.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + ), + child: Icon( + Icons.shield, + color: AppConstants.primaryColor, + size: 20, + ), + ), + const SizedBox(width: 12), + Text( + '沙盒运行说明', + style: TextStyle( + color: AppConstants.primaryColor, + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], ), - const SizedBox(height: 4), + const SizedBox(height: 12), + const Divider(height: 1), + const SizedBox(height: 12), Text( - description, - style: TextStyle(fontSize: 12, color: Colors.grey[600]), + '本软件严格遵循移动平台沙盒机制运行,确保您的数据安全:', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.grey[800], + ), ), + const SizedBox(height: 12), + _buildSandboxItem('📱 沙盒隔离', '软件在独立沙盒环境中运行,无法访问系统其他应用数据'), + const SizedBox(height: 8), + _buildSandboxItem('📄 无文件创建', '不会在设备上创建额外文件,所有数据通过网络获取'), + const SizedBox(height: 8), + _buildSandboxItem('🔒 权限透明', '仅使用必要权限,此类权限均为基础权限'), + const SizedBox(height: 8), + _buildSandboxItem('💾 本地存储', '仅使用 SharedPreferences 存储少量用户偏好设置'), ], ), ); } + + Widget _buildSandboxItem(String title, String description) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 4, + height: 4, + margin: const EdgeInsets.only(top: 8), + decoration: BoxDecoration( + color: AppConstants.primaryColor, + borderRadius: BorderRadius.circular(2), + ), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.grey[800], + ), + ), + const SizedBox(height: 4), + Text( + description, + style: TextStyle( + fontSize: 12, + color: Colors.grey[600], + height: 1.5, + ), + ), + ], + ), + ), + ], + ); + } + + Widget _buildBottomTip() { + return Center( + child: Padding( + padding: const EdgeInsets.only(bottom: 32), + child: Text( + '到底了', + style: TextStyle( + fontSize: 14, + color: Colors.grey[400], + fontWeight: FontWeight.w500, + ), + ), + ), + ); + } } diff --git a/lib/views/profile/settings/app_fun.dart b/lib/views/profile/settings/app_fun.dart index 67724c2..aeaaebc 100644 --- a/lib/views/profile/settings/app_fun.dart +++ b/lib/views/profile/settings/app_fun.dart @@ -23,14 +23,16 @@ class _AppFunSettingsPageState extends State { bool _debugInfoEnabled = false; bool _soundEnabled = false; // 默认关闭 bool _vibrationEnabled = true; - bool _darkModeEnabled = false; bool _preloadEnabled = true; bool _globalTipsEnabled = true; // 添加全局Tips开关状态 + bool _hideSecondaryButtons = false; // 隐藏次要按钮 static const String _autoRefreshKey = 'auto_refresh_enabled'; static const String _debugInfoKey = 'debug_info_enabled'; static const String _globalTipsKey = 'global_tips_enabled'; // 添加全局Tips开关key static const String _soundEnabledKey = 'sound_enabled'; // 声音反馈开关key + static const String _hideSecondaryButtonsKey = + 'hide_secondary_buttons'; // 隐藏次要按钮key @override void initState() { @@ -48,6 +50,8 @@ class _AppFunSettingsPageState extends State { prefs.getBool(_globalTipsKey) ?? true; // 加载全局Tips开关状态 _preloadEnabled = prefs.getBool('preload_enabled') ?? true; _soundEnabled = prefs.getBool(_soundEnabledKey) ?? false; // 加载声音反馈状态 + _hideSecondaryButtons = + prefs.getBool(_hideSecondaryButtonsKey) ?? false; // 加载隐藏次要按钮状态 }); } } @@ -96,6 +100,65 @@ class _AppFunSettingsPageState extends State { } } + // 设置震动反馈 + Future _setVibrationEnabled(bool value) async { + if (value && !_vibrationEnabled) { + // 从关闭到开启,显示提示对话框 + _showVibrationDialog(); + } else { + // 从开启到关闭,直接设置 + if (mounted) { + setState(() { + _vibrationEnabled = value; + }); + } + } + } + + // 显示震动提示对话框 + void _showVibrationDialog() { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('震动反馈'), + content: const Text('默认场景调用震动,未对软件震动做出优化,待收集建议改进'), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('取消'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + if (mounted) { + setState(() { + _vibrationEnabled = true; + }); + } + }, + child: Text( + '确定', + style: TextStyle(color: AppConstants.primaryColor), + ), + ), + ], + ), + ); + } + + // 设置隐藏次要按钮 + Future _setHideSecondaryButtons(bool value) async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setBool(_hideSecondaryButtonsKey, value); + // 更新管理器状态 + await SecondaryButtonsManager().setHidden(value); + if (mounted) { + setState(() { + _hideSecondaryButtons = value; + }); + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -145,14 +208,21 @@ class _AppFunSettingsPageState extends State { ), ]), const SizedBox(height: 16), - _buildSettingsGroup('显示设置', [ - _buildSwitchItem( + _buildSettingsGroup('主页显示设置', [ + _buildDevelopmentItem( 'Tap沉浸光感', - '开启后底栏显示类iOS26 风格\nbeta实验功能', + '开启后底栏显示类iOS26 风格', Icons.dark_mode, - _darkModeEnabled, - (value) => setState(() => _darkModeEnabled = value), ), + + _buildSwitchItem( + '隐藏次要按钮', + '开启后隐藏上一条和分享按钮', + Icons.share, + _hideSecondaryButtons, + _setHideSecondaryButtons, + ), + _buildFontSliderItem(), ]), const SizedBox(height: 16), @@ -184,30 +254,30 @@ class _AppFunSettingsPageState extends State { '操作时震动提示', Icons.vibration, _vibrationEnabled, - (value) => setState(() => _vibrationEnabled = value), + (value) => _setVibrationEnabled(value), ), ]), const SizedBox(height: 16), _buildSettingsGroup('高级设置', [ - _buildActionItem( - 'Beta开关 关闭软件', - '开发者选项', - Icons.developer_mode, - () => _showSnackBar('调试模式开发中'), - ), + // _buildActionItem( + // 'Beta开关 关闭软件', + // '开发者选项', + // Icons.developer_mode, + // () => _showSnackBar('调试模式开发中'), + // ), _buildActionItem( '重置设置', '恢复默认设置', Icons.restore, () => _showResetDialog(), ), - _buildActionItem( - '调试模式', - '开发者选项', - Icons.developer_mode, - () => _showSnackBar('调试模式开发中'), - ), + // _buildActionItem( + // '调试模式', + // '开发者选项', + // Icons.developer_mode, + // () => _showSnackBar('调试模式开发中'), + // ), ]), const SizedBox(height: 32), _buildVersionInfo(), @@ -337,6 +407,46 @@ class _AppFunSettingsPageState extends State { ); } + Widget _buildDevelopmentItem(String title, String subtitle, IconData icon) { + return ListTile( + leading: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.grey.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + ), + child: Icon(icon, color: Colors.grey, size: 20), + ), + title: Text( + title, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + color: Colors.grey[600], + ), + ), + subtitle: Text( + subtitle, + style: TextStyle(fontSize: 12, color: Colors.grey[400]), + ), + trailing: Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + decoration: BoxDecoration( + color: Colors.grey.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(12), + ), + child: Text( + '开发中', + style: TextStyle( + fontSize: 12, + color: Colors.grey[600], + fontWeight: FontWeight.w500, + ), + ), + ), + ); + } + Widget _buildVersionInfo() { return Container( padding: const EdgeInsets.all(20), @@ -399,7 +509,6 @@ class _AppFunSettingsPageState extends State { _soundEnabled = true; _vibrationEnabled = true; _globalTipsEnabled = true; // 重置全局Tips开关为开启 - _darkModeEnabled = false; }); _showSnackBar('已恢复默认设置'); }, diff --git a/lib/views/profile/settings/learn-us.dart b/lib/views/profile/settings/learn-us.dart index 3c96ef5..e146985 100644 --- a/lib/views/profile/settings/learn-us.dart +++ b/lib/views/profile/settings/learn-us.dart @@ -37,6 +37,8 @@ class LearnUsPage extends StatelessWidget { const SizedBox(height: 16), _buildOfficialSiteCard(), const SizedBox(height: 16), + _buildQQGroupCard(context), + const SizedBox(height: 16), _buildDeveloperCard(), const SizedBox(height: 16), _buildTeamCard(), @@ -231,6 +233,120 @@ class LearnUsPage extends StatelessWidget { ); } + Widget _buildQQGroupCard(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.05), + blurRadius: 10, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.blue.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + ), + child: Icon(Icons.group, color: Colors.blue[700], size: 20), + ), + const SizedBox(width: 12), + const Text( + 'QQ交流群', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + ], + ), + ), + const Divider(height: 1), + Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + '加入我们的QQ交流群,与其他诗词爱好者一起交流', + style: TextStyle(fontSize: 13, color: Colors.grey), + ), + const SizedBox(height: 12), + InkWell( + onTap: () => _copyQQGroupNumber(context), + borderRadius: BorderRadius.circular(8), + child: Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.grey[50], + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: AppConstants.primaryColor.withValues(alpha: 0.3), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.content_copy, + size: 16, + color: AppConstants.primaryColor, + ), + const SizedBox(width: 8), + Text( + '271129018', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: AppConstants.primaryColor, + ), + ), + ], + ), + ), + ), + const SizedBox(height: 8), + Text( + '💡 点击群号可复制', + style: TextStyle(fontSize: 12, color: Colors.grey[500]), + ), + ], + ), + ), + ], + ), + ); + } + + void _copyQQGroupNumber(BuildContext context) { + Clipboard.setData(const ClipboardData(text: '271129018')); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Row( + children: [ + Icon(Icons.check_circle, color: Colors.white, size: 20), + SizedBox(width: 8), + Text('QQ群号已复制到剪贴板'), + ], + ), + backgroundColor: AppConstants.primaryColor, + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + duration: const Duration(seconds: 2), + ), + ); + } + Widget _buildDeveloperCard() { return Container( decoration: BoxDecoration( diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 8baf9d9..f606be2 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,6 +7,7 @@ import Foundation import audioplayers_darwin import device_info_plus +import flutter_udid import path_provider_foundation import share_plus import shared_preferences_foundation @@ -14,6 +15,7 @@ import shared_preferences_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FlutterUdidPlugin.register(with: registry.registrar(forPlugin: "FlutterUdidPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 59b284f..d365150 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -227,6 +227,15 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_udid: + dependency: "direct main" + description: + path: "." + ref: HEAD + resolved-ref: "4bd2d6988e959e11779f9a72eaadb3f75de68a2d" + url: "https://gitcode.com/openharmony-sig/fluttertpc_flutter_udid.git" + source: git + version: "2.0.1" flutter_web_plugins: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index c1d79d4..53c1071 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,6 +46,10 @@ dependencies: git: url: https://gitcode.com/openharmony-sig/flutter_audioplayers.git path: packages/audioplayers + flutter_udid: + git: + url: https://gitcode.com/openharmony-sig/fluttertpc_flutter_udid.git + share_plus: path: packages/flutter_plus_plugins/packages/share_plus/share_plus