ver1.00.00
update3
This commit is contained in:
BIN
images/icon/icon.png
Normal file
BIN
images/icon/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 MiB |
@@ -1,9 +1,12 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:unionapp/pages/music/music_page.dart';
|
||||
import '../../service/recommendation_helper.dart';
|
||||
import '../../service/song_service.dart';
|
||||
import '../../tool/cacheImage.dart';
|
||||
import '../../tool/gradientText.dart';
|
||||
import '../../widgets/glowBlobConfig.dart';
|
||||
import '../music/adx.dart';
|
||||
import '../music/score_single.dart';
|
||||
import '../score/updateScorePage.dart';
|
||||
@@ -14,6 +17,10 @@ import '../../providers/user_provider.dart';
|
||||
import '../../model/song_model.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class HomePage extends StatelessWidget {
|
||||
final Function(int)? onSwitchTab;
|
||||
|
||||
@@ -24,298 +31,236 @@ class HomePage extends StatelessWidget {
|
||||
final userProvider = context.watch<UserProvider>();
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// ====================== 顶部 Header ======================
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 100,
|
||||
child: Stack(
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 30, top: 60),
|
||||
child: Text(
|
||||
"Tool",
|
||||
style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
|
||||
),
|
||||
body: Stack(
|
||||
children: [
|
||||
// 在 Stack 的底层调用
|
||||
LiquidGlowBackground(
|
||||
blurSigma: 60, // 模糊程度
|
||||
duration: const Duration(seconds: 10), // 动画周期
|
||||
blobs: [
|
||||
GlowBlobConfig(
|
||||
color: Colors.blueAccent.withOpacity(0.5),
|
||||
size: 250,
|
||||
begin: const Alignment(-0.8, -0.4), // 从左下
|
||||
end: const Alignment(-0.2, 0.2), // 移动到中央偏左
|
||||
),
|
||||
GlowBlobConfig(
|
||||
color: Colors.pinkAccent.withOpacity(0.4),
|
||||
size: 100,
|
||||
begin: const Alignment(-0.8, 0.9),
|
||||
end: const Alignment(0.3, 0.5),
|
||||
),
|
||||
GlowBlobConfig(
|
||||
color: Colors.white.withOpacity(0.3),
|
||||
size: 200,
|
||||
begin: const Alignment(2.0, -0.4), // 从正下方溢出处
|
||||
end: const Alignment(0.0, -0.5), // 向上浮动
|
||||
),
|
||||
],
|
||||
),
|
||||
// 2. 主内容层
|
||||
SafeArea(
|
||||
bottom: false,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// ====================== 顶部 Header ======================
|
||||
_buildHeader(userProvider),
|
||||
const SizedBox(height: 30),
|
||||
|
||||
// ====================== 横向卡片区域 ======================
|
||||
_buildHorizontalCards(context),
|
||||
|
||||
// ====================== 海报 ======================
|
||||
const PosterImage(imageUrl: 'https://cdn.godserver.cn/post/post%20unionapp1.png'),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// ====================== 用户数据展示卡片 ======================
|
||||
const _UserInfoCard(),
|
||||
const SizedBox(height: 30),
|
||||
|
||||
// ====================== 下部两栏布局 ======================
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 7,
|
||||
child: const _RecommendedSongsSection(),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Expanded(
|
||||
flex: 6,
|
||||
child: _buildQuickActionButtons(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
right: 20,
|
||||
top: 25,
|
||||
child: Row(
|
||||
children: [
|
||||
GradientText(
|
||||
data: userProvider.username,
|
||||
style: const TextStyle(fontSize: 19, fontWeight: FontWeight.bold),
|
||||
gradientLayers: [
|
||||
GradientLayer(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Colors.pinkAccent, Colors.orangeAccent],
|
||||
),
|
||||
blendMode: BlendMode.srcIn,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
child: SizedBox(
|
||||
width: 54,
|
||||
height: 54,
|
||||
child: userProvider.avatarUrl.isNotEmpty
|
||||
? Image.network(
|
||||
userProvider.avatarUrl,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: Container(
|
||||
color: Colors.grey[200],
|
||||
child: const Icon(Icons.person, size: 30),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 50), // 留出底部空间给发光球
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeader(userProvider) {
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
height: 100,
|
||||
child: Stack(
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 30, top: 60),
|
||||
child: Text(
|
||||
"Tool",
|
||||
style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 20,
|
||||
top: 25,
|
||||
child: Row(
|
||||
children: [
|
||||
GradientText(
|
||||
data: userProvider.username,
|
||||
style: const TextStyle(fontSize: 19, fontWeight: FontWeight.bold),
|
||||
gradientLayers: [
|
||||
GradientLayer(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Colors.pinkAccent, Colors.orangeAccent],
|
||||
),
|
||||
blendMode: BlendMode.srcIn,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
|
||||
// ====================== 横向卡片区域 ======================
|
||||
SizedBox(
|
||||
height: 180,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 10).copyWith(bottom: 30),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildCardWithTitle(
|
||||
context: context,
|
||||
title: "用户中心",
|
||||
icon: Icons.person_outline,
|
||||
targetIndex: 3,
|
||||
gradient: const LinearGradient(
|
||||
colors: [Colors.black, Colors.grey],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
shadowColor: Colors.black38,
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
|
||||
_buildCardWithTitle(
|
||||
context: context,
|
||||
title: "歌曲列表",
|
||||
icon: Icons.music_note_outlined,
|
||||
targetPage: const MusicPage(),
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFFff9a9e), Color(0xFFfecfef)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
shadowColor: const Color(0xFFff9a9e).withOpacity(0.6),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
|
||||
_buildCardWithTitle(
|
||||
context: context,
|
||||
title: "成绩管理",
|
||||
icon: Icons.score,
|
||||
targetIndex: 1,
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFF84fab0), Color(0xFF8fd3f4)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
shadowColor: const Color(0xFF84fab0).withOpacity(0.6),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
|
||||
_buildCardWithTitle(
|
||||
context: context,
|
||||
title: "娱乐功能",
|
||||
icon: Icons.kebab_dining_sharp,
|
||||
targetPage: const ScoreListPage(),
|
||||
gradient: const LinearGradient(
|
||||
colors: [Colors.lightBlueAccent, Colors.blueAccent],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
shadowColor: Colors.lightBlue.withOpacity(0.6),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
|
||||
_buildCardWithTitle(
|
||||
context: context,
|
||||
title: "评分列表",
|
||||
icon: Icons.star,
|
||||
targetPage: const ScoreListPage(),
|
||||
gradient: const LinearGradient(
|
||||
colors: [Colors.redAccent, Colors.pinkAccent],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
shadowColor: Colors.red.withOpacity(0.6),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
],
|
||||
const SizedBox(width: 8),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
child: SizedBox(
|
||||
width: 54,
|
||||
height: 54,
|
||||
child: userProvider.avatarUrl.isNotEmpty
|
||||
? Image.network(userProvider.avatarUrl, fit: BoxFit.cover)
|
||||
: Container(
|
||||
color: Colors.grey[200],
|
||||
child: const Icon(Icons.person, size: 30),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// ====================== 海报 ======================
|
||||
const PosterImage(imageUrl: 'https://cdn.godserver.cn/post/post%20unionapp1.png'),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// ====================== 用户数据展示卡片 ======================
|
||||
const _UserInfoCard(),
|
||||
const SizedBox(height: 30),
|
||||
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 左侧:智能推荐乐曲(占 6 份宽度)
|
||||
Expanded(
|
||||
flex: 7,
|
||||
child: const _RecommendedSongsSection(),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Expanded(
|
||||
flex: 6,
|
||||
child: _buildQuickActionButtons(context), // 快捷按钮组件
|
||||
),
|
||||
const SizedBox(width: 10), // 左右间距
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHorizontalCards(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: 180,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 10).copyWith(bottom: 30),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildCardWithTitle(
|
||||
context: context,
|
||||
title: "用户中心",
|
||||
icon: Icons.person_outline,
|
||||
targetIndex: 3,
|
||||
gradient: const LinearGradient(colors: [Colors.black, Colors.grey]),
|
||||
shadowColor: Colors.black38,
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
_buildCardWithTitle(
|
||||
context: context,
|
||||
title: "歌曲列表",
|
||||
icon: Icons.music_note_outlined,
|
||||
targetPage: const MusicPage(),
|
||||
gradient: const LinearGradient(colors: [Color(0xFFff9a9e), Color(0xFFfecfef)]),
|
||||
shadowColor: const Color(0xFFff9a9e).withOpacity(0.6),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
_buildCardWithTitle(
|
||||
context: context,
|
||||
title: "成绩管理",
|
||||
icon: Icons.score,
|
||||
targetIndex: 1,
|
||||
gradient: const LinearGradient(colors: [Color(0xFF84fab0), Color(0xFF8fd3f4)]),
|
||||
shadowColor: const Color(0xFF84fab0).withOpacity(0.6),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
_buildCardWithTitle(
|
||||
context: context,
|
||||
title: "娱乐功能",
|
||||
icon: Icons.kebab_dining_sharp,
|
||||
targetPage: const ScoreListPage(),
|
||||
gradient: const LinearGradient(colors: [Colors.lightBlueAccent, Colors.blueAccent]),
|
||||
shadowColor: Colors.lightBlue.withOpacity(0.6),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
_buildCardWithTitle(
|
||||
context: context,
|
||||
title: "评分列表",
|
||||
icon: Icons.star,
|
||||
targetPage: const ScoreListPage(),
|
||||
gradient: const LinearGradient(colors: [Colors.redAccent, Colors.pinkAccent]),
|
||||
shadowColor: Colors.red.withOpacity(0.6),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
// 右侧快捷按钮区域(你可以自由修改图标、文字、点击事件)
|
||||
|
||||
Widget _buildQuickActionButtons(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
"快捷操作",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const Text("快捷操作", style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 15),
|
||||
// 按钮网格
|
||||
GridView.count(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
crossAxisCount: 2, // 一行 2 个按钮
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
childAspectRatio: 1.0,
|
||||
children: [
|
||||
_quickActionItem(
|
||||
icon: Icons.download,
|
||||
label: "更新成绩",
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.lightBlueAccent.withAlpha(10), Colors.pinkAccent.withOpacity(0.1)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
color: Colors.pinkAccent.shade100,
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const BindAccountPage()),
|
||||
);
|
||||
},
|
||||
gradient: LinearGradient(colors: [Colors.lightBlueAccent.withAlpha(10), Colors.pinkAccent.withOpacity(0.1)]),
|
||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => const BindAccountPage())),
|
||||
),
|
||||
_quickActionItem(
|
||||
icon: Icons.stars_outlined,
|
||||
label: "ADX",
|
||||
color: Colors.white,
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.blueAccent, Colors.pinkAccent.shade100],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.topRight,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.blueAccent.withOpacity(0.3),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(2, 4),
|
||||
),
|
||||
],
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => AdxDownloadGridPage(),
|
||||
),
|
||||
);
|
||||
},
|
||||
gradient: LinearGradient(colors: [Colors.blueAccent, Colors.pinkAccent.shade100]),
|
||||
boxShadow: [BoxShadow(color: Colors.blueAccent.withOpacity(0.3), blurRadius: 8, offset: const Offset(2, 4))],
|
||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => AdxDownloadGridPage())),
|
||||
),
|
||||
|
||||
// 橙色渐变
|
||||
_quickActionItem(
|
||||
icon: Icons.generating_tokens,
|
||||
label: "ReiSasol",
|
||||
color: Colors.white,
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.orangeAccent, Colors.pink],
|
||||
begin: Alignment.center,
|
||||
end: Alignment.bottomLeft,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.orange.withOpacity(0.3),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(2, 4),
|
||||
),
|
||||
],
|
||||
gradient: const LinearGradient(colors: [Colors.orangeAccent, Colors.pink]),
|
||||
onTap: () async {
|
||||
// 你的固定分享链接
|
||||
const url = "https://bot.q.qq.com/s/c2mloqdgv?id=102172520";
|
||||
const title = "ReiSasol";
|
||||
|
||||
// QQ 分享 Scheme
|
||||
final qqScheme = 'mqq://im/chat?chat_type=wpa&url=${Uri.encodeComponent(url)}&title=${Uri.encodeComponent(title)}';
|
||||
final uri = Uri.parse(qqScheme);
|
||||
|
||||
try {
|
||||
if (await canLaunchUrl(uri)) {
|
||||
await launchUrl(uri);
|
||||
} else {
|
||||
// 未安装QQ → 用浏览器打开链接
|
||||
await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);
|
||||
}
|
||||
} catch (e) {
|
||||
// 兜底打开
|
||||
await launchUrl(Uri.parse(url));
|
||||
}
|
||||
if (await canLaunchUrl(Uri.parse(url))) await launchUrl(Uri.parse(url));
|
||||
},
|
||||
),
|
||||
_quickActionItem(
|
||||
icon: Icons.link,
|
||||
label: "友站",
|
||||
color: Colors.white,
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.grey[600]!, Colors.grey[400]!],
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.2),
|
||||
blurRadius: 6,
|
||||
offset: const Offset(1, 2),
|
||||
),
|
||||
],
|
||||
gradient: LinearGradient(colors: [Colors.grey[600]!, Colors.grey[400]!]),
|
||||
onTap: () {},
|
||||
),
|
||||
],
|
||||
@@ -324,16 +269,12 @@ class HomePage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// 修改后的组件方法
|
||||
Widget _quickActionItem({
|
||||
required IconData icon,
|
||||
required String label,
|
||||
required Color color,
|
||||
required VoidCallback onTap,
|
||||
// 新增:渐变背景(可选)
|
||||
Gradient? gradient,
|
||||
// 新增:阴影(可选)
|
||||
List<BoxShadow>? boxShadow,
|
||||
}) {
|
||||
return InkWell(
|
||||
@@ -341,31 +282,24 @@ class HomePage extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
// 优先级:渐变 > 纯色背景
|
||||
color: gradient == null ? Colors.black.withOpacity(0.1) : null,
|
||||
gradient: gradient,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: boxShadow,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), // 优化内边距
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon, color: color, size: 28),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: color,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Text(label, style: TextStyle(fontSize: 13, color: color, fontWeight: FontWeight.w500)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCardWithTitle({
|
||||
required BuildContext context,
|
||||
required String title,
|
||||
@@ -383,28 +317,13 @@ class HomePage extends StatelessWidget {
|
||||
if (targetIndex != null && onSwitchTab != null) {
|
||||
onSwitchTab!(targetIndex);
|
||||
} else if (targetPage != null) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => targetPage),
|
||||
);
|
||||
Navigator.push(context, MaterialPageRoute(builder: (context) => targetPage));
|
||||
}
|
||||
},
|
||||
child: _buildCustomCardBody(
|
||||
gradient: gradient,
|
||||
shadowColor: shadowColor,
|
||||
icon: icon,
|
||||
),
|
||||
child: _buildCustomCardBody(gradient: gradient, shadowColor: shadowColor, icon: icon),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Text(title, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600, letterSpacing: 0.5)),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -420,27 +339,13 @@ class HomePage extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
gradient: gradient,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: shadowColor,
|
||||
blurRadius: 15,
|
||||
spreadRadius: 3,
|
||||
offset: const Offset(4, 6),
|
||||
),
|
||||
],
|
||||
boxShadow: [BoxShadow(color: shadowColor, blurRadius: 15, spreadRadius: 3, offset: Offset(4,6))],
|
||||
),
|
||||
child: Center(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.25),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
size: 36,
|
||||
color: Colors.white,
|
||||
),
|
||||
decoration: BoxDecoration(color: Colors.white.withOpacity(0.25), shape: BoxShape.circle),
|
||||
child: Icon(icon, size: 36, color: Colors.white),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../model/song_model.dart';
|
||||
@@ -10,6 +11,7 @@ import 'package:dio/dio.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import '../../tool/cacheImage.dart';
|
||||
import '../../widgets/glowBlobConfig.dart';
|
||||
|
||||
class ScorePage extends StatefulWidget {
|
||||
const ScorePage({Key? key}) : super(key: key);
|
||||
@@ -422,13 +424,45 @@ class _ScorePageState extends State<ScorePage> with SingleTickerProviderStateMix
|
||||
IconButton(icon: const Icon(Icons.refresh), onPressed: () => _loadData(isInitialLoad: false))
|
||||
],
|
||||
),
|
||||
body: Column(
|
||||
body: Stack(
|
||||
children: [
|
||||
_buildDataSourceSelector(),
|
||||
_buildFilterBar(),
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: _buildBody(),
|
||||
LiquidGlowBackground(
|
||||
blurSigma: 60, // 模糊程度
|
||||
duration: const Duration(seconds: 10), // 动画周期
|
||||
blobs: [
|
||||
GlowBlobConfig(
|
||||
color: Colors.blueAccent.withOpacity(0.5),
|
||||
size: 150,
|
||||
begin: const Alignment(-0.8, -0.4),
|
||||
end: const Alignment(-0.2, 0.2), // 移动到中央偏左
|
||||
),
|
||||
GlowBlobConfig(
|
||||
color: Colors.pinkAccent.withOpacity(0.4),
|
||||
size: 100,
|
||||
begin: const Alignment(-0.8, 0.9),
|
||||
end: const Alignment(0.3, 0.5),
|
||||
),
|
||||
GlowBlobConfig(
|
||||
color: Colors.white.withOpacity(0.3),
|
||||
size: 200,
|
||||
begin: const Alignment(2.0, -1.4), // 从正下方溢出处
|
||||
end: const Alignment(0.0, -0.5), // 向上浮动
|
||||
),
|
||||
],
|
||||
),
|
||||
// 2. 主内容层
|
||||
SafeArea(
|
||||
bottom: false,
|
||||
child: Column(
|
||||
children: [
|
||||
_buildDataSourceSelector(),
|
||||
_buildFilterBar(),
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: _buildBody(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -488,6 +522,7 @@ class _ScorePageState extends State<ScorePage> with SingleTickerProviderStateMix
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButtonFormField<String>(
|
||||
value: safeValue, // <--- 这里用安全值,修复报错
|
||||
isExpanded: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: isSegaMode ? "选择卡片" : "选择账号",
|
||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
|
||||
@@ -826,13 +861,6 @@ class _ScorePageState extends State<ScorePage> with SingleTickerProviderStateMix
|
||||
},
|
||||
child: const Text("取消"),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
onConfirm(tempSelected);
|
||||
Navigator.pop(dialogContext);
|
||||
},
|
||||
child: const Text("确定"),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
onConfirm([]);
|
||||
@@ -840,6 +868,14 @@ class _ScorePageState extends State<ScorePage> with SingleTickerProviderStateMix
|
||||
},
|
||||
child: const Text("重置", style: TextStyle(color: Colors.red)),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
onConfirm(tempSelected);
|
||||
Navigator.pop(dialogContext);
|
||||
},
|
||||
child: const Text("确定"),
|
||||
),
|
||||
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -1341,6 +1377,7 @@ class _ScorePageState extends State<ScorePage> with SingleTickerProviderStateMix
|
||||
}
|
||||
return Colors.black;
|
||||
}
|
||||
|
||||
Widget _buildScoreInfo(Map<String, dynamic> score, SongModel song) {
|
||||
final dxScore = score['deluxscoreMax'] ?? 0;
|
||||
final playCount = score['playCount'] ?? 0;
|
||||
@@ -1352,14 +1389,14 @@ class _ScorePageState extends State<ScorePage> with SingleTickerProviderStateMix
|
||||
int syncStatus = score['syncStatus'] ?? 0;
|
||||
|
||||
int totalNotes = 0;
|
||||
if ((type == 'dx' && song.dx != null) || (type == 'sd' && song.sd != null)) {
|
||||
if (song.dx != null || song.sd != null) {
|
||||
final levelKey = level.toString();
|
||||
final levelData = type == 'dx' ? song.dx![levelKey] : song.sd![levelKey];
|
||||
if (levelData != null && levelData['notes'] != null) {
|
||||
totalNotes = levelData['notes']['total'] ?? 0;
|
||||
if (score['musicId'] > 10000) {
|
||||
totalNotes = song.dx![levelKey]['notes']['total'] ?? 0;
|
||||
} else {
|
||||
totalNotes = song.sd![levelKey]['notes']['total'] ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
final allDx = totalNotes * 3;
|
||||
final perc = allDx > 0 ? dxScore / allDx : 0.0;
|
||||
|
||||
@@ -1382,53 +1419,45 @@ class _ScorePageState extends State<ScorePage> with SingleTickerProviderStateMix
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
// 🔴 核心修复:用 Wrap 自动换行,代替会溢出的 Row
|
||||
child: Wrap(
|
||||
spacing: 10, // 元素横向间距
|
||||
runSpacing: 6, // 换行后纵向间距
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
alignment: WrapAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.score_rounded, size: 14, color: Colors.blueGrey),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
"DX: $dxScore / $allDx",
|
||||
style: const TextStyle(fontSize: 13, color: Colors.blueGrey, fontWeight: FontWeight.w500),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
// 左侧信息组
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.score_rounded, size: 14, color: Colors.blueGrey),
|
||||
Text(
|
||||
"DX: $dxScore / $allDx",
|
||||
style: const TextStyle(fontSize: 13, color: Colors.blueGrey, fontWeight: FontWeight.w500),
|
||||
),
|
||||
|
||||
const Icon(Icons.play_arrow_rounded, size: 14, color: Colors.grey),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
"$playCount 次",
|
||||
style: const TextStyle(fontSize: 13, color: Colors.grey),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
const Icon(Icons.play_arrow_rounded, size: 14, color: Colors.grey),
|
||||
Text(
|
||||
"$playCount 次",
|
||||
style: const TextStyle(fontSize: 13, color: Colors.grey),
|
||||
),
|
||||
|
||||
const Icon(Icons.star_rate_rounded, size: 14, color: Colors.amber),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
"Rating: $rating",
|
||||
style: const TextStyle(fontSize: 13,fontWeight: FontWeight.w500),
|
||||
),
|
||||
const Icon(Icons.star_rate_rounded, size: 14, color: Colors.amber),
|
||||
Text(
|
||||
"Rating: $rating",
|
||||
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500),
|
||||
),
|
||||
|
||||
const SizedBox(width: 8),
|
||||
|
||||
if (comboIconPath != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4),
|
||||
child: Image.asset(comboIconPath, width: 30, height: 30),
|
||||
),
|
||||
|
||||
if (syncIconPath != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4),
|
||||
child: Image.asset(syncIconPath, width: 30, height: 30),
|
||||
),
|
||||
],
|
||||
),
|
||||
// 图标
|
||||
if (comboIconPath != null)
|
||||
Image.asset(comboIconPath, width: 26, height: 26),
|
||||
if (syncIconPath != null)
|
||||
Image.asset(syncIconPath, width: 26, height: 26),
|
||||
],
|
||||
),
|
||||
|
||||
// 右侧星级(自动换到下一行)
|
||||
if (perc >= 0.85) _dxStarIcon(perc),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -282,33 +282,85 @@ class _BindAccountPageState extends State<BindAccountPage> {
|
||||
|
||||
if (_selectedImageFile != null) const SizedBox(height: 15),
|
||||
|
||||
// 按钮组
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: _isProcessing ? null : _pickImageAndScan,
|
||||
icon: const Icon(Icons.image_search),
|
||||
label: const Text("识别截图"),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blueAccent,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Colors.purpleAccent, Colors.deepOrange],
|
||||
begin: Alignment.topLeft, // 改成你要的
|
||||
end: Alignment.bottomRight, // 改成你要的
|
||||
),
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.pink.withOpacity(0.4),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: _isProcessing ? null : _pickImageAndScan,
|
||||
icon: const Icon(Icons.image_search, size: 20),
|
||||
label: const Text("识别截图", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500)),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: _isProcessing ? null : _handleBind,
|
||||
icon: _isProcessing
|
||||
? const SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white))
|
||||
: const Icon(Icons.login),
|
||||
label: Text(_isProcessing ? "处理中" : "绑定/刷新"),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
// 只改这里:渐变方向 → 参考你的写法
|
||||
gradient: const LinearGradient(
|
||||
colors: [Colors.white10, Colors.black],
|
||||
begin: Alignment.topLeft, // 改成你要的
|
||||
end: Alignment.bottomRight, // 改成你要的
|
||||
),
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.white.withOpacity(0.4),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: _isProcessing ? null : _handleBind,
|
||||
icon: _isProcessing
|
||||
? const SizedBox(
|
||||
width: 18,
|
||||
height: 18,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: const Icon(Icons.login, size: 20),
|
||||
label: Text(
|
||||
_isProcessing ? "处理中" : "绑定/刷新",
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w500),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -97,7 +97,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||
),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.all(24),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24),
|
||||
child: SingleChildScrollView(
|
||||
// 关键修复2:让滚动视图正常工作
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
@@ -111,7 +111,8 @@ class _LoginPageState extends State<LoginPage> {
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 400),
|
||||
child: Card(
|
||||
elevation: 8, shadowColor: _pinkColor.withOpacity(0.3),
|
||||
elevation: 8,
|
||||
shadowColor: _pinkColor.withOpacity(0.3),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
|
||||
@@ -9,6 +9,7 @@ import '../../model/user_model.dart';
|
||||
import '../../providers/user_provider.dart';
|
||||
import '../../service/sega_service.dart';
|
||||
import '../../tool/cacheImage.dart';
|
||||
import '../../widgets/glowBlobConfig.dart';
|
||||
import 'login_page.dart';
|
||||
|
||||
class UserPage extends StatefulWidget {
|
||||
@@ -590,63 +591,96 @@ class _UserPageState extends State<UserPage> {
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 20),
|
||||
child: Center(
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 900),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildProfileHeader(context, userProvider, user),
|
||||
const SizedBox(height: 24),
|
||||
floatingActionButton: _buildFloatingBackButton(),
|
||||
body: Stack(
|
||||
children: [
|
||||
// 在 Stack 的底层调用
|
||||
LiquidGlowBackground(
|
||||
blurSigma: 60, // 模糊程度
|
||||
duration: const Duration(seconds: 10), // 动画周期
|
||||
blobs: [
|
||||
GlowBlobConfig(
|
||||
color: Colors.deepPurpleAccent.withOpacity(0.5),
|
||||
size: 250,
|
||||
begin: const Alignment(-0.8, -0.4), // 从左下
|
||||
end: const Alignment(-0.2, 0.2), // 移动到中央偏左
|
||||
),
|
||||
GlowBlobConfig(
|
||||
color: Colors.pinkAccent.withOpacity(0.4),
|
||||
size: 100,
|
||||
begin: const Alignment(-0.8, 0.9),
|
||||
end: const Alignment(0.3, 0.5),
|
||||
),
|
||||
GlowBlobConfig(
|
||||
color: Colors.white.withOpacity(0.3),
|
||||
size: 200,
|
||||
begin: const Alignment(2.0, -0.4), // 从正下方溢出处
|
||||
end: const Alignment(0.0, -0.5), // 向上浮动
|
||||
),
|
||||
],
|
||||
),
|
||||
// 2. 主内容层
|
||||
SafeArea(
|
||||
bottom:false ,
|
||||
child:SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 20),
|
||||
child: Center(
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 900),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildProfileHeader(context, userProvider, user),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
if (user.userCards != null && user.userCards!.isNotEmpty)
|
||||
_buildUserCardSlider(userProvider, user),
|
||||
const SizedBox(height: 24),
|
||||
if (user.userCards != null && user.userCards!.isNotEmpty)
|
||||
_buildUserCardSlider(userProvider, user),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
_buildSectionCard([
|
||||
_buildItem("用户ID", user.id.toString()),
|
||||
_buildEditableItem("用户名", _nameController),
|
||||
_buildEditableItem("邮箱", _emailController),
|
||||
_buildEditableSexItem(),
|
||||
_buildEditableItem("个性签名", _bioController),
|
||||
_buildItem("积分", user.points.toString()),
|
||||
_buildItem("B50方案", user.useB50Type.toString()),
|
||||
_buildCopyableItem(context, "API Key", user.apiKey),
|
||||
_buildCopyableItem(context, "绑定 API Key", user.apiBindKey),
|
||||
_buildItem("UserID", "****${user.userId.toString().substring(4)}"),
|
||||
_buildItem("上次登录", _formatLastLoginTime(user.lastLoginTime)),
|
||||
]),
|
||||
const SizedBox(height: 20),
|
||||
_buildSectionCard([
|
||||
_buildItem("用户ID", user.id.toString()),
|
||||
_buildEditableItem("用户名", _nameController),
|
||||
_buildEditableItem("邮箱", _emailController),
|
||||
_buildEditableSexItem(),
|
||||
_buildEditableItem("个性签名", _bioController),
|
||||
_buildItem("积分", user.points.toString()),
|
||||
_buildItem("B50方案", user.useB50Type.toString()),
|
||||
_buildCopyableItem(context, "API Key", user.apiKey),
|
||||
_buildCopyableItem(context, "绑定 API Key", user.apiBindKey),
|
||||
_buildItem("UserID", "****${user.userId.toString().substring(4)}"),
|
||||
_buildItem("上次登录", _formatLastLoginTime(user.lastLoginTime)),
|
||||
]),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
_buildScoreCheckerCard(user),
|
||||
const SizedBox(height: 20),
|
||||
_buildScoreCheckerCard(user),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
_buildSectionCard([
|
||||
_buildSwitchItem("禁止被推荐", _isDisagreeRecommend, (v) {
|
||||
setState(() => _isDisagreeRecommend = v);
|
||||
}),
|
||||
_buildSwitchItem("禁止加好友", _isDisagreeFriend, (v) {
|
||||
setState(() => _isDisagreeFriend = v);
|
||||
}),
|
||||
]),
|
||||
const SizedBox(height: 20),
|
||||
_buildSectionCard([
|
||||
_buildSwitchItem("禁止被推荐", _isDisagreeRecommend, (v) {
|
||||
setState(() => _isDisagreeRecommend = v);
|
||||
}),
|
||||
_buildSwitchItem("禁止加好友", _isDisagreeFriend, (v) {
|
||||
setState(() => _isDisagreeFriend = v);
|
||||
}),
|
||||
]),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
_buildSegaCard(user),
|
||||
const SizedBox(height: 20),
|
||||
_buildRadarChartSection(),
|
||||
const SizedBox(height: 20),
|
||||
_buildSegaCard(user),
|
||||
const SizedBox(height: 20),
|
||||
_buildRadarChartSection(),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
_buildSaveButton(userProvider),
|
||||
const SizedBox(height: 12),
|
||||
_buildLogoutButton(context, userProvider),
|
||||
const SizedBox(height: 100),
|
||||
],
|
||||
_buildSaveButton(userProvider),
|
||||
const SizedBox(height: 12),
|
||||
_buildLogoutButton(context, userProvider),
|
||||
const SizedBox(height: 100),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
floatingActionButton: _buildFloatingBackButton(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -898,10 +932,13 @@ class _UserPageState extends State<UserPage> {
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Text("国服用户 - $name"),
|
||||
const Spacer(),
|
||||
// 移除按钮(仿照sega移除)
|
||||
_buildSmallButton("移除", Colors.red, () => _removeGuoFuAccount(name, user)),
|
||||
],
|
||||
),
|
||||
);
|
||||
})
|
||||
}).toList(),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -1253,6 +1290,7 @@ class _UserPageState extends State<UserPage> {
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
// 服务器标签
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
@@ -1265,27 +1303,18 @@ class _UserPageState extends State<UserPage> {
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
|
||||
// ID 文本(自动占剩余空间)
|
||||
Expanded(child: Text(card.segaId ?? "")),
|
||||
const SizedBox(width: 6),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(foregroundColor: Colors.red),
|
||||
onPressed: () => _removeSegaCard(card, user),
|
||||
child: const Text("移除", style: TextStyle(fontSize: 12)),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
TextButton(
|
||||
onPressed: () => _verifyBoundSega(card),
|
||||
child: const Text("验证", style: TextStyle(fontSize: 12)),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
TextButton(
|
||||
onPressed: () => _refreshBoundSegaScore(card),
|
||||
child: const Text("刷新成绩", style: TextStyle(fontSize: 12)),
|
||||
),
|
||||
|
||||
// 三个紧凑按钮
|
||||
_buildSmallButton("移除", Colors.red, () => _removeSegaCard(card, user)),
|
||||
_buildSmallButton("验证", null, () => _verifyBoundSega(card)),
|
||||
_buildSmallButton("刷新成绩", null, () => _refreshBoundSegaScore(card)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
}).toList(),
|
||||
|
||||
if (user.segaCards == null || user.segaCards!.isEmpty)
|
||||
const Padding(
|
||||
@@ -1307,7 +1336,21 @@ class _UserPageState extends State<UserPage> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSmallButton(String text, Color? color, VoidCallback onTap) {
|
||||
return TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: color,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
minimumSize: Size.zero,
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
onPressed: onTap,
|
||||
child: Text(
|
||||
text,
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
);
|
||||
}
|
||||
Widget _webCard({required Widget child}) {
|
||||
return Builder(
|
||||
builder: (context) {
|
||||
@@ -1554,7 +1597,123 @@ class _UserPageState extends State<UserPage> {
|
||||
},
|
||||
);
|
||||
}
|
||||
// 移除 国服账号(仿照移除Sega)
|
||||
Future<void> _removeGuoFuAccount(String name, UserModel user) async {
|
||||
final confirm = await showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: const Text("确认移除"),
|
||||
content: Text("确定要删除国服账号 $name 吗?"),
|
||||
actions: [
|
||||
TextButton(onPressed: () => Navigator.pop(ctx), child: const Text("取消")),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx, true),
|
||||
style: TextButton.styleFrom(foregroundColor: Colors.red),
|
||||
child: const Text("删除"),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
if (confirm != true) return;
|
||||
|
||||
final provider = Provider.of<UserProvider>(context, listen: false);
|
||||
|
||||
// 复制并删除指定name的国服账号
|
||||
Map<String, int> newMap = Map.from(user.userName2userId ?? {});
|
||||
newMap.remove(name);
|
||||
|
||||
// 完全沿用你原来的 UserModel 构造(一模一样)
|
||||
UserModel updatedUser = UserModel(
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
userId: user.userId,
|
||||
teamId: user.teamId,
|
||||
email: user.email,
|
||||
password: user.password,
|
||||
twoFactorKey: user.twoFactorKey,
|
||||
apiKey: user.apiKey,
|
||||
apiBindKey: user.apiBindKey,
|
||||
protectRole: user.protectRole,
|
||||
risks: user.risks,
|
||||
mcName: user.mcName,
|
||||
userName2userId: newMap,
|
||||
lxKey: user.lxKey,
|
||||
dfUsername: user.dfUsername,
|
||||
dfPassword: user.dfPassword,
|
||||
nuoId: user.nuoId,
|
||||
botId: user.botId,
|
||||
spasolBotId: user.spasolBotId,
|
||||
githubId: user.githubId,
|
||||
rating: user.rating,
|
||||
ratingMax: user.ratingMax,
|
||||
iconId: user.iconId,
|
||||
plateId: user.plateId,
|
||||
plateIds: user.plateIds,
|
||||
frameId: user.frameId,
|
||||
charaSlots: user.charaSlots,
|
||||
qiandaoDay: user.qiandaoDay,
|
||||
inviter: user.inviter,
|
||||
successLogoutTime: user.successLogoutTime,
|
||||
lastLoginTime: user.lastLoginTime,
|
||||
friendIds: user.friendIds,
|
||||
bio: user.bio,
|
||||
friendBio: user.friendBio,
|
||||
sex: user.sex,
|
||||
isDisagreeRecommend: user.isDisagreeRecommend,
|
||||
isDisagreeFriend: user.isDisagreeFriend,
|
||||
points: user.points,
|
||||
planPoints: user.planPoints,
|
||||
cardIds: user.cardIds,
|
||||
userCards: user.userCards,
|
||||
tags: user.tags,
|
||||
useBeta: user.useBeta,
|
||||
useNuo: user.useNuo,
|
||||
useServer: user.useServer,
|
||||
useB50Type: user.useB50Type,
|
||||
userHot: user.userHot,
|
||||
chatInGroupNumbers: user.chatInGroupNumbers,
|
||||
sc: user.sc,
|
||||
id2pcNuo: user.id2pcNuo,
|
||||
mai2links: user.mai2links,
|
||||
key2KeychipEn: user.key2KeychipEn,
|
||||
key2key2KeychipEn: user.key2key2KeychipEn,
|
||||
mai2link: user.mai2link,
|
||||
userRegion: user.userRegion,
|
||||
rinUsernameOrEmail: user.rinUsernameOrEmail,
|
||||
rinPassword: user.rinPassword,
|
||||
rinChusanUser: user.rinChusanUser,
|
||||
segaCards: user.segaCards,
|
||||
placeList: user.placeList,
|
||||
lastKeyChip: user.lastKeyChip,
|
||||
token: user.token,
|
||||
timesRegionData: user.timesRegionData,
|
||||
yearTotal: user.yearTotal,
|
||||
yearTotalComment: user.yearTotalComment,
|
||||
userCollCardMap: user.userCollCardMap,
|
||||
collName2musicIds: user.collName2musicIds,
|
||||
ai: user.ai,
|
||||
pkScore: user.pkScore,
|
||||
pkScoreStr: user.pkScoreStr,
|
||||
pkScoreReality: user.pkScoreReality,
|
||||
pkUserId: user.pkUserId,
|
||||
limitPkTimestamp: user.limitPkTimestamp,
|
||||
hasAcceptPk: user.hasAcceptPk,
|
||||
pkPlayNum: user.pkPlayNum,
|
||||
pkWin: user.pkWin,
|
||||
userData: user.userData,
|
||||
banState: user.banState,
|
||||
);
|
||||
|
||||
provider.updateUser(updatedUser);
|
||||
await provider.saveUserInfo();
|
||||
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text("✅ 已移除国服账号:$name")),
|
||||
);
|
||||
}
|
||||
}
|
||||
Widget _buildBenefitItem({
|
||||
required IconData icon,
|
||||
required String title,
|
||||
|
||||
113
lib/widgets/glowBlobConfig.dart
Normal file
113
lib/widgets/glowBlobConfig.dart
Normal file
@@ -0,0 +1,113 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 球体配置类:控制颜色、大小、以及运动轨迹
|
||||
class GlowBlobConfig {
|
||||
final Color color;
|
||||
final double size;
|
||||
final Alignment begin;
|
||||
final Alignment end;
|
||||
|
||||
GlowBlobConfig({
|
||||
required this.color,
|
||||
required this.size,
|
||||
required this.begin,
|
||||
required this.end,
|
||||
});
|
||||
}
|
||||
|
||||
class LiquidGlowBackground extends StatefulWidget {
|
||||
// 支持传入配置列表
|
||||
final List<GlowBlobConfig> blobs;
|
||||
final Duration duration;
|
||||
final double blurSigma;
|
||||
|
||||
const LiquidGlowBackground({
|
||||
super.key,
|
||||
required this.blobs,
|
||||
this.duration = const Duration(seconds: 8),
|
||||
this.blurSigma = 50.0,
|
||||
});
|
||||
|
||||
@override
|
||||
State<LiquidGlowBackground> createState() => _LiquidGlowBackgroundState();
|
||||
}
|
||||
|
||||
class _LiquidGlowBackgroundState extends State<LiquidGlowBackground>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: widget.duration,
|
||||
)..repeat(reverse: true); // 设置为 reverse 让往返运动更丝滑
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
animation: _controller,
|
||||
builder: (context, child) {
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
// 根据传入的配置动态生成球体
|
||||
...widget.blobs.map((config) {
|
||||
// 使用 AnimationController 在 begin 和 end 之间插值
|
||||
final currentAlignment = Alignment.lerp(
|
||||
config.begin,
|
||||
config.end,
|
||||
_controller.value,
|
||||
)!;
|
||||
|
||||
return _buildBlob(
|
||||
color: config.color,
|
||||
size: config.size,
|
||||
alignment: currentAlignment,
|
||||
);
|
||||
}),
|
||||
|
||||
// 核心模糊效果层
|
||||
Positioned.fill(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(
|
||||
sigmaX: widget.blurSigma,
|
||||
sigmaY: widget.blurSigma,
|
||||
),
|
||||
child: Container(color: Colors.transparent),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBlob({
|
||||
required Color color,
|
||||
required double size,
|
||||
required Alignment alignment,
|
||||
}) {
|
||||
return Align(
|
||||
alignment: alignment,
|
||||
child: Container(
|
||||
width: size,
|
||||
height: size,
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
shape: BoxShape.circle,
|
||||
backgroundBlendMode: BlendMode.screen, // 让光影融合更自然
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,18 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <open_file_linux/open_file_linux_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) open_file_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "OpenFileLinuxPlugin");
|
||||
open_file_linux_plugin_register_with_registrar(open_file_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||
}
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_linux
|
||||
open_file_linux
|
||||
url_launcher_linux
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
jni
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
|
||||
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
|
||||
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
|
||||
347C8783FFA8594D3475C1B1 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8403A1BE4D0285716060FA7E /* Pods_RunnerTests.framework */; };
|
||||
D001A0C52A7A968BD1BBDC89 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D349F9576E7496D04E1998B2 /* Pods_Runner.framework */; };
|
||||
A46D509B6933DAAB43E6E6F7 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E27D01287AB6E5C77DFC866 /* Pods_RunnerTests.framework */; };
|
||||
E94F9D77408D51D8E7A96F7F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C71C09486046B2CB4E18A7F0 /* Pods_Runner.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -62,8 +62,8 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
061A6DA9B784560E62EA378E /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
1E3EDE577A6C1F411A56772B /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
20DBCB375C39D0CE7B7EA565 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
2A72486B11A7ED6C5CD16A56 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
|
||||
@@ -80,14 +80,14 @@
|
||||
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
|
||||
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
|
||||
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
|
||||
716AF5A705D0555D88DF2B29 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
4E27D01287AB6E5C77DFC866 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
|
||||
8403A1BE4D0285716060FA7E /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
925906409C141F8E699BDA54 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9AC33D131F9E1EA9EB03F15A /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
C52A2A0CB2BACFFF5FF7072B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
D349F9576E7496D04E1998B2 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C71C09486046B2CB4E18A7F0 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DB8CB3EA8EFE4F5FF1BCD246 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
DE3E8B33E5B8E6A8CCC794A6 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
E2C1479E5196488C1819A4D1 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
F4DD2D7757E5812FE234C99F /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -95,7 +95,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
347C8783FFA8594D3475C1B1 /* Pods_RunnerTests.framework in Frameworks */,
|
||||
A46D509B6933DAAB43E6E6F7 /* Pods_RunnerTests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -103,27 +103,13 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D001A0C52A7A968BD1BBDC89 /* Pods_Runner.framework in Frameworks */,
|
||||
E94F9D77408D51D8E7A96F7F /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
10C14F25FB53CAE6F47361B9 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C52A2A0CB2BACFFF5FF7072B /* Pods-Runner.debug.xcconfig */,
|
||||
9AC33D131F9E1EA9EB03F15A /* Pods-Runner.release.xcconfig */,
|
||||
925906409C141F8E699BDA54 /* Pods-Runner.profile.xcconfig */,
|
||||
061A6DA9B784560E62EA378E /* Pods-RunnerTests.debug.xcconfig */,
|
||||
1E3EDE577A6C1F411A56772B /* Pods-RunnerTests.release.xcconfig */,
|
||||
716AF5A705D0555D88DF2B29 /* Pods-RunnerTests.profile.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
331C80D6294CF71000263BE5 /* RunnerTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -150,8 +136,8 @@
|
||||
33CEB47122A05771004F2AC0 /* Flutter */,
|
||||
331C80D6294CF71000263BE5 /* RunnerTests */,
|
||||
33CC10EE2044A3C60003C045 /* Products */,
|
||||
D73912EC22F37F3D000D13A0 /* Frameworks */,
|
||||
10C14F25FB53CAE6F47361B9 /* Pods */,
|
||||
CE01DD500A025813DDDBCC38 /* Pods */,
|
||||
828A2A90CCA6BA035658AE38 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -199,15 +185,29 @@
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
|
||||
828A2A90CCA6BA035658AE38 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D349F9576E7496D04E1998B2 /* Pods_Runner.framework */,
|
||||
8403A1BE4D0285716060FA7E /* Pods_RunnerTests.framework */,
|
||||
C71C09486046B2CB4E18A7F0 /* Pods_Runner.framework */,
|
||||
4E27D01287AB6E5C77DFC866 /* Pods_RunnerTests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CE01DD500A025813DDDBCC38 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
20DBCB375C39D0CE7B7EA565 /* Pods-Runner.debug.xcconfig */,
|
||||
DB8CB3EA8EFE4F5FF1BCD246 /* Pods-Runner.release.xcconfig */,
|
||||
E2C1479E5196488C1819A4D1 /* Pods-Runner.profile.xcconfig */,
|
||||
2A72486B11A7ED6C5CD16A56 /* Pods-RunnerTests.debug.xcconfig */,
|
||||
DE3E8B33E5B8E6A8CCC794A6 /* Pods-RunnerTests.release.xcconfig */,
|
||||
F4DD2D7757E5812FE234C99F /* Pods-RunnerTests.profile.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -215,7 +215,7 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||
buildPhases = (
|
||||
2C72CB55051DF188C184CCE5 /* [CP] Check Pods Manifest.lock */,
|
||||
096B41B0DEC40EB80A110691 /* [CP] Check Pods Manifest.lock */,
|
||||
331C80D1294CF70F00263BE5 /* Sources */,
|
||||
331C80D2294CF70F00263BE5 /* Frameworks */,
|
||||
331C80D3294CF70F00263BE5 /* Resources */,
|
||||
@@ -234,13 +234,13 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
D60F7A1773BBDE533CA61546 /* [CP] Check Pods Manifest.lock */,
|
||||
B7B705D7127D0C90AD8D9500 /* [CP] Check Pods Manifest.lock */,
|
||||
33CC10E92044A3C60003C045 /* Sources */,
|
||||
33CC10EA2044A3C60003C045 /* Frameworks */,
|
||||
33CC10EB2044A3C60003C045 /* Resources */,
|
||||
33CC110E2044A8840003C045 /* Bundle Framework */,
|
||||
3399D490228B24CF009A79C7 /* ShellScript */,
|
||||
38C831F56EAB5041148AF6D2 /* [CP] Embed Pods Frameworks */,
|
||||
370D7045E7238027D5055B59 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -323,7 +323,7 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
2C72CB55051DF188C184CCE5 /* [CP] Check Pods Manifest.lock */ = {
|
||||
096B41B0DEC40EB80A110691 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -383,7 +383,7 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
|
||||
};
|
||||
38C831F56EAB5041148AF6D2 /* [CP] Embed Pods Frameworks */ = {
|
||||
370D7045E7238027D5055B59 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -400,7 +400,7 @@
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
D60F7A1773BBDE533CA61546 /* [CP] Check Pods Manifest.lock */ = {
|
||||
B7B705D7127D0C90AD8D9500 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -473,7 +473,7 @@
|
||||
/* Begin XCBuildConfiguration section */
|
||||
331C80DB294CF71000263BE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 061A6DA9B784560E62EA378E /* Pods-RunnerTests.debug.xcconfig */;
|
||||
baseConfigurationReference = 2A72486B11A7ED6C5CD16A56 /* Pods-RunnerTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
@@ -488,7 +488,7 @@
|
||||
};
|
||||
331C80DC294CF71000263BE5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 1E3EDE577A6C1F411A56772B /* Pods-RunnerTests.release.xcconfig */;
|
||||
baseConfigurationReference = DE3E8B33E5B8E6A8CCC794A6 /* Pods-RunnerTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
@@ -503,7 +503,7 @@
|
||||
};
|
||||
331C80DD294CF71000263BE5 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 716AF5A705D0555D88DF2B29 /* Pods-RunnerTests.profile.xcconfig */;
|
||||
baseConfigurationReference = F4DD2D7757E5812FE234C99F /* Pods-RunnerTests.profile.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
|
||||
76
pubspec.lock
76
pubspec.lock
@@ -2,7 +2,7 @@
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
archive:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: archive
|
||||
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
|
||||
@@ -57,6 +57,22 @@ packages:
|
||||
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: checked_yaml
|
||||
sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f"
|
||||
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
cli_util:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cli_util
|
||||
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
|
||||
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
||||
source: hosted
|
||||
version: "0.4.2"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -98,7 +114,7 @@ packages:
|
||||
source: hosted
|
||||
version: "0.3.5+2"
|
||||
crypto:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: crypto
|
||||
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
|
||||
@@ -130,7 +146,7 @@ packages:
|
||||
source: hosted
|
||||
version: "0.7.12"
|
||||
dio:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dio
|
||||
sha256: aff32c08f92787a557dd5c0145ac91536481831a01b4648136373cddb0e64f8c
|
||||
@@ -146,7 +162,7 @@ packages:
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
encrypt:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: encrypt
|
||||
sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
|
||||
@@ -226,7 +242,7 @@ packages:
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
fl_chart:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fl_chart
|
||||
sha256: d0f0d49112f2f4b192481c16d05b6418bd7820e021e265a3c22db98acf7ed7fb
|
||||
@@ -238,8 +254,16 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_launcher_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_launcher_icons
|
||||
sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
|
||||
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
||||
source: hosted
|
||||
version: "0.13.1"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
|
||||
@@ -247,7 +271,7 @@ packages:
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
flutter_map:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_map
|
||||
sha256: "87cc8349b8fa5dccda5af50018c7374b6645334a0d680931c1fe11bce88fa5bb"
|
||||
@@ -281,7 +305,7 @@ packages:
|
||||
source: hosted
|
||||
version: "0.1.1"
|
||||
geocoding:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: geocoding
|
||||
sha256: "606be036287842d779d7ec4e2f6c9435fc29bbbd3c6da6589710f981d8852895"
|
||||
@@ -313,7 +337,7 @@ packages:
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
geolocator:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: geolocator
|
||||
sha256: "79939537046c9025be47ec645f35c8090ecadb6fe98eba146a0d25e8c1357516"
|
||||
@@ -369,7 +393,7 @@ packages:
|
||||
source: hosted
|
||||
version: "0.2.5"
|
||||
glass_liquid_navbar:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: glass_liquid_navbar
|
||||
sha256: "782fa0d0c112ad6c1341b286cd59b802d86b6f4b5383aaafe3b0cd7180d266dd"
|
||||
@@ -401,7 +425,7 @@ packages:
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
html:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: html
|
||||
sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602"
|
||||
@@ -425,7 +449,7 @@ packages:
|
||||
source: hosted
|
||||
version: "4.1.2"
|
||||
image:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image
|
||||
sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d
|
||||
@@ -433,7 +457,7 @@ packages:
|
||||
source: hosted
|
||||
version: "4.3.0"
|
||||
image_picker:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image_picker
|
||||
sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320"
|
||||
@@ -528,8 +552,16 @@ packages:
|
||||
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: json_annotation
|
||||
sha256: cb09e7dac6210041fad964ed7fbee004f14258b4eca4040f72d1234062ace4c8
|
||||
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
||||
source: hosted
|
||||
version: "4.11.0"
|
||||
latlong2:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: latlong2
|
||||
sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe"
|
||||
@@ -657,7 +689,7 @@ packages:
|
||||
source: hosted
|
||||
version: "9.3.0"
|
||||
open_file:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: open_file
|
||||
sha256: b22decdae85b459eac24aeece48f33845c6f16d278a9c63d75c5355345ca236b
|
||||
@@ -825,7 +857,7 @@ packages:
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
pointycastle:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: pointycastle
|
||||
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
|
||||
@@ -849,7 +881,7 @@ packages:
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
provider:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: provider
|
||||
sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272"
|
||||
@@ -865,7 +897,7 @@ packages:
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
share_plus:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: share_plus
|
||||
sha256: "3ef39599b00059db0990ca2e30fca0a29d8b37aae924d60063f8e0184cf20900"
|
||||
@@ -881,7 +913,7 @@ packages:
|
||||
source: hosted
|
||||
version: "3.4.0"
|
||||
shared_preferences:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf
|
||||
@@ -1006,7 +1038,7 @@ packages:
|
||||
source: hosted
|
||||
version: "0.3.1"
|
||||
url_launcher:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8
|
||||
@@ -1102,7 +1134,7 @@ packages:
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
webview_flutter:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: webview_flutter
|
||||
sha256: a3da219916aba44947d3a5478b1927876a09781174b5a2b67fa5be0555154bf9
|
||||
@@ -1174,7 +1206,7 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
zxing2:
|
||||
dependency: "direct dev"
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: zxing2
|
||||
sha256: "2677c49a3b9ca9457cb1d294fd4bd5041cac6aab8cdb07b216ba4e98945c684f"
|
||||
|
||||
28
pubspec.yaml
28
pubspec.yaml
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 1.0.0+1
|
||||
version: 1.0.0+2
|
||||
|
||||
environment:
|
||||
sdk: ^3.11.3
|
||||
@@ -30,14 +30,10 @@ environment:
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
flutter_launcher_icons: ^0.13.1
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.8
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
glass_liquid_navbar: ^0.2.0
|
||||
flutter_map: ^6.1.0 # 地图组件
|
||||
latlong2: ^0.9.0 # flutter_map 依赖的坐标库
|
||||
@@ -61,6 +57,10 @@ dev_dependencies:
|
||||
image_picker: ^1.0.4
|
||||
zxing2: ^0.2.3 # 新增:用于二维码识别
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
@@ -103,3 +103,19 @@ flutter:
|
||||
#
|
||||
# For details regarding fonts from package dependencies,
|
||||
# see https://flutter.dev/to/font-from-package
|
||||
|
||||
flutter_launcher_icons:
|
||||
android: true # 为 Android 生成图标
|
||||
ios: true # 为 iOS 生成图标
|
||||
image_path: "images/icon/icon.png" # 你的源图标路径(建议 1024x1024 PNG)
|
||||
|
||||
# 可选:为 Android 自适应图标(Android 8.0+)设置背景色或前景图
|
||||
# adaptive_icon_background: "#ffffff"
|
||||
# adaptive_icon_foreground: "assets/icon/foreground.png"
|
||||
|
||||
# 可选:为 Web 平台设置
|
||||
web:
|
||||
generate: true
|
||||
image_path: "assets/icon/icon.png"
|
||||
background_color: "#hexcode"
|
||||
theme_color: "#hexcode"
|
||||
|
||||
@@ -6,6 +6,18 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <geolocator_windows/geolocator_windows.h>
|
||||
#include <share_plus/share_plus_windows_plugin_c_api.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
GeolocatorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("GeolocatorWindows"));
|
||||
SharePlusWindowsPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||
}
|
||||
|
||||
@@ -3,9 +3,14 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_windows
|
||||
geolocator_windows
|
||||
share_plus
|
||||
url_launcher_windows
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
jni
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
||||
Reference in New Issue
Block a user