完善细类

This commit is contained in:
Developer
2026-03-31 07:56:35 +08:00
parent 66f72abab4
commit 9a58f6ca19
12 changed files with 683 additions and 257 deletions

View File

@@ -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.
## 软件特性功能
### 已开发完成
- <EFBFBD> **诗词卡片截图分享功能** - 主页点赞按钮上方添加悬浮分享按钮、点击生成诗词卡片高清图片并分享、使用RepaintBoundary和GlobalKey实现Widget截图、集成share_plus库实现跨平台分享、包含生成中/成功/失败提示
- 🎛️ **隐藏次要按钮功能** - 在功能设置页面添加开关、开启后隐藏主页的"上一条"和"分享"悬浮按钮、默认关闭、状态保存到SharedPreferences、使用SecondaryButtonsManager单例管理、实时响应开关状态变化无需重启
- 优先级3
- 📸 **诗词卡片截图分享功能** - 主页点赞按钮上方添加悬浮分享按钮、点击生成诗词卡片高清图片并分享、使用RepaintBoundary和GlobalKey实现Widget截图、集成share_plus库实现跨平台分享、包含生成中/成功/失败提示
- 优先级4
- 📜 **诗词投稿功能** - 新增投稿页面、支持诗词收录申请表单、包含参考语句/分类选择/诗人和标题/关键词/诗词介绍/人机验证、实现相似度检测防止重复提交、平台字段自动获取设备类型
- 优先级3

View File

@@ -286,7 +286,7 @@ class _RatePageState extends State<RatePage>
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionTitle('本周活跃趋势'),
_buildSectionTitle('本周活跃趋势(生成图片分享)'),
const SizedBox(height: 16),
// 热力图 - 使用 Wrap 防止溢出
Container(

View File

@@ -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<bool> _hiddenNotifier = ValueNotifier<bool>(false);
SecondaryButtonsManager._internal();
factory SecondaryButtonsManager() {
_instance ??= SecondaryButtonsManager._internal();
return _instance!;
}
Future<void> init() async {
final prefs = await SharedPreferences.getInstance();
_isHidden = prefs.getBool(_hideSecondaryButtonsKey) ?? false;
_hiddenNotifier.value = _isHidden;
}
bool get isHidden => _isHidden;
ValueNotifier<bool> get hiddenNotifier => _hiddenNotifier;
Future<void> 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);

View File

@@ -60,12 +60,17 @@ class _HomePageState extends State<HomePage>
_initDebugInfo();
_initOfflineDataManager();
_initAudioManager();
_initSecondaryButtonsManager();
// 延迟加载诗词,确保页面先显示
WidgetsBinding.instance.addPostFrameCallback((_) {
_loadPoetry();
});
}
Future<void> _initSecondaryButtonsManager() async {
await SecondaryButtonsManager().init();
}
Future<void> _initAudioManager() async {
await AudioManager().init();
}
@@ -772,63 +777,71 @@ class _HomePageState extends State<HomePage>
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<bool>(
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,
),
),
],
);
},
),
),
);

View File

@@ -158,7 +158,7 @@ class _PoetryCardState extends State<PoetryCard> {
],
),
),
if (_showCopyTip) _buildCopyTip(),
_buildCopyTip(),
],
),
);
@@ -225,6 +225,10 @@ class _PoetryCardState extends State<PoetryCard> {
}
Widget _buildCopyTip() {
if (!_globalTipsEnabled || !_showCopyTip) {
return const SizedBox.shrink();
}
return Positioned(
top: 56,
right: 24,
@@ -243,21 +247,21 @@ class _PoetryCardState extends State<PoetryCard> {
),
],
),
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),
],
),
),

View File

@@ -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<AppInfoPage> createState() => _AppInfoPageState();
}
class _AppInfoPageState extends State<AppInfoPage> {
String _udid = '获取中...';
@override
void initState() {
super.initState();
_loadUdid();
}
Future<void> _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: []),
);
}

View File

@@ -50,21 +50,20 @@ class _PermissionPageState extends State<PermissionPage> {
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<PermissionPage> {
_networkEnabled,
null,
),
_buildPermissionItem(
'震动反馈',
'操作时的震动反馈,提升交互体验',
Icons.vibration,
_vibrationEnabled,
null,
),
_buildPermissionItem(
'剪切板',
'复制诗词内容到剪切板',
@@ -79,15 +86,35 @@ class _PermissionPageState extends State<PermissionPage> {
_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<PermissionPage> {
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 4),
// const SizedBox(height: 4),
Text(
description,
style: TextStyle(
@@ -292,18 +319,18 @@ class _PermissionPageState extends State<PermissionPage> {
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<PermissionPage> {
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<PermissionPage> {
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<PermissionPage> {
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<PermissionPage> {
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,
),
),
),
);
}
}

View File

@@ -23,14 +23,16 @@ class _AppFunSettingsPageState extends State<AppFunSettingsPage> {
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<AppFunSettingsPage> {
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<AppFunSettingsPage> {
}
}
// 设置震动反馈
Future<void> _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<void> _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<AppFunSettingsPage> {
),
]),
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<AppFunSettingsPage> {
'操作时震动提示',
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<AppFunSettingsPage> {
);
}
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<AppFunSettingsPage> {
_soundEnabled = true;
_vibrationEnabled = true;
_globalTipsEnabled = true; // 重置全局Tips开关为开启
_darkModeEnabled = false;
});
_showSnackBar('已恢复默认设置');
},

View File

@@ -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(

View File

@@ -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"))

View File

@@ -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

View File

@@ -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