519 lines
16 KiB
Dart
519 lines
16 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import '../../../core/utils/responsive_utils.dart';
|
||
import '../../../shared/widgets/custom_app_bar.dart';
|
||
import '../../../shared/widgets/loading_widget.dart';
|
||
|
||
class AIRecommendationScreen extends ConsumerStatefulWidget {
|
||
const AIRecommendationScreen({super.key});
|
||
|
||
@override
|
||
ConsumerState<AIRecommendationScreen> createState() => _AIRecommendationScreenState();
|
||
}
|
||
|
||
class _AIRecommendationScreenState extends ConsumerState<AIRecommendationScreen> {
|
||
bool _isLoading = false;
|
||
List<RecommendationItem> _recommendations = [];
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_loadRecommendations();
|
||
}
|
||
|
||
Future<void> _loadRecommendations() async {
|
||
setState(() {
|
||
_isLoading = true;
|
||
});
|
||
|
||
// 模拟AI推荐数据加载
|
||
await Future.delayed(const Duration(milliseconds: 1000));
|
||
|
||
setState(() {
|
||
_recommendations = _generateRecommendations();
|
||
_isLoading = false;
|
||
});
|
||
}
|
||
|
||
List<RecommendationItem> _generateRecommendations() {
|
||
return [
|
||
RecommendationItem(
|
||
type: RecommendationType.vocabulary,
|
||
title: '商务英语词汇强化',
|
||
description: '基于您的学习历史,建议加强商务场景词汇学习',
|
||
priority: 'high',
|
||
estimatedTime: '15分钟',
|
||
icon: Icons.business_center,
|
||
color: Colors.blue,
|
||
action: '开始学习',
|
||
details: [
|
||
'包含50个高频商务词汇',
|
||
'涵盖会议、谈判、报告等场景',
|
||
'配有真实商务对话示例',
|
||
],
|
||
),
|
||
RecommendationItem(
|
||
type: RecommendationType.review,
|
||
title: '复习昨日学习内容',
|
||
description: '您有8个单词需要复习,趁热打铁效果更佳',
|
||
priority: 'high',
|
||
estimatedTime: '10分钟',
|
||
icon: Icons.refresh,
|
||
color: Colors.orange,
|
||
action: '立即复习',
|
||
details: [
|
||
'8个单词待复习',
|
||
'基于遗忘曲线算法推荐',
|
||
'巩固记忆效果显著',
|
||
],
|
||
),
|
||
RecommendationItem(
|
||
type: RecommendationType.test,
|
||
title: '词汇测试挑战',
|
||
description: '测试您的词汇掌握程度,发现薄弱环节',
|
||
priority: 'medium',
|
||
estimatedTime: '20分钟',
|
||
icon: Icons.quiz,
|
||
color: Colors.green,
|
||
action: '开始测试',
|
||
details: [
|
||
'30道精选测试题',
|
||
'多种题型组合',
|
||
'即时反馈和解析',
|
||
],
|
||
),
|
||
RecommendationItem(
|
||
type: RecommendationType.plan,
|
||
title: '制定本周学习计划',
|
||
description: '为您量身定制的学习计划,提高学习效率',
|
||
priority: 'medium',
|
||
estimatedTime: '5分钟',
|
||
icon: Icons.schedule,
|
||
color: Colors.purple,
|
||
action: '查看计划',
|
||
details: [
|
||
'个性化学习路径',
|
||
'合理安排学习时间',
|
||
'目标导向的学习方案',
|
||
],
|
||
),
|
||
RecommendationItem(
|
||
type: RecommendationType.weakness,
|
||
title: '语法薄弱点强化',
|
||
description: '针对您在时态方面的薄弱点进行专项训练',
|
||
priority: 'low',
|
||
estimatedTime: '25分钟',
|
||
icon: Icons.trending_up,
|
||
color: Colors.red,
|
||
action: '开始训练',
|
||
details: [
|
||
'时态专项练习',
|
||
'常见错误纠正',
|
||
'实用例句训练',
|
||
],
|
||
),
|
||
];
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final isMobile = ResponsiveUtils.isMobile(context);
|
||
|
||
return Scaffold(
|
||
appBar: CustomAppBar(
|
||
title: 'AI助手推荐',
|
||
),
|
||
body: _isLoading
|
||
? const LoadingWidget()
|
||
: _buildContent(context, isMobile),
|
||
);
|
||
}
|
||
|
||
Widget _buildContent(BuildContext context, bool isMobile) {
|
||
return RefreshIndicator(
|
||
onRefresh: _loadRecommendations,
|
||
child: SingleChildScrollView(
|
||
padding: EdgeInsets.all(isMobile ? 16.0 : 24.0),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
_buildHeader(context, isMobile),
|
||
const SizedBox(height: 24),
|
||
_buildRecommendationsList(context, isMobile),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildHeader(BuildContext context, bool isMobile) {
|
||
return Container(
|
||
padding: EdgeInsets.all(isMobile ? 20.0 : 24.0),
|
||
decoration: BoxDecoration(
|
||
gradient: LinearGradient(
|
||
colors: [Colors.purple.shade400, Colors.blue.shade500],
|
||
begin: Alignment.topLeft,
|
||
end: Alignment.bottomRight,
|
||
),
|
||
borderRadius: BorderRadius.circular(16),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Colors.purple.withOpacity(0.3),
|
||
blurRadius: 8,
|
||
offset: const Offset(0, 4),
|
||
),
|
||
],
|
||
),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Container(
|
||
padding: const EdgeInsets.all(12),
|
||
decoration: BoxDecoration(
|
||
color: Colors.white.withOpacity(0.2),
|
||
borderRadius: BorderRadius.circular(12),
|
||
),
|
||
child: Icon(
|
||
Icons.psychology,
|
||
color: Colors.white,
|
||
size: isMobile ? 28 : 32,
|
||
),
|
||
),
|
||
const SizedBox(width: 16),
|
||
Expanded(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
'AI智能推荐',
|
||
style: TextStyle(
|
||
color: Colors.white,
|
||
fontSize: isMobile ? 20 : 24,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
const SizedBox(height: 4),
|
||
Text(
|
||
'基于您的学习数据智能分析',
|
||
style: TextStyle(
|
||
color: Colors.white.withOpacity(0.9),
|
||
fontSize: isMobile ? 14 : 16,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 16),
|
||
Container(
|
||
padding: const EdgeInsets.all(12),
|
||
decoration: BoxDecoration(
|
||
color: Colors.white.withOpacity(0.1),
|
||
borderRadius: BorderRadius.circular(8),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
Icon(
|
||
Icons.lightbulb,
|
||
color: Colors.yellow.shade300,
|
||
size: 20,
|
||
),
|
||
const SizedBox(width: 8),
|
||
Expanded(
|
||
child: Text(
|
||
'今日为您推荐了 ${_recommendations.length} 项学习内容',
|
||
style: TextStyle(
|
||
color: Colors.white,
|
||
fontSize: isMobile ? 13 : 15,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildRecommendationsList(BuildContext context, bool isMobile) {
|
||
return Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
'推荐内容',
|
||
style: TextStyle(
|
||
fontSize: isMobile ? 18 : 20,
|
||
fontWeight: FontWeight.bold,
|
||
color: Colors.grey[800],
|
||
),
|
||
),
|
||
const SizedBox(height: 16),
|
||
ListView.separated(
|
||
shrinkWrap: true,
|
||
physics: const NeverScrollableScrollPhysics(),
|
||
itemCount: _recommendations.length,
|
||
separatorBuilder: (context, index) => const SizedBox(height: 16),
|
||
itemBuilder: (context, index) {
|
||
return _buildRecommendationCard(
|
||
context,
|
||
_recommendations[index],
|
||
isMobile,
|
||
);
|
||
},
|
||
),
|
||
],
|
||
);
|
||
}
|
||
|
||
Widget _buildRecommendationCard(
|
||
BuildContext context,
|
||
RecommendationItem item,
|
||
bool isMobile,
|
||
) {
|
||
return Card(
|
||
elevation: 3,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(16),
|
||
),
|
||
child: InkWell(
|
||
onTap: () => _handleRecommendationTap(item),
|
||
borderRadius: BorderRadius.circular(16),
|
||
child: Padding(
|
||
padding: EdgeInsets.all(isMobile ? 16.0 : 20.0),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Container(
|
||
padding: const EdgeInsets.all(12),
|
||
decoration: BoxDecoration(
|
||
color: item.color.withOpacity(0.1),
|
||
borderRadius: BorderRadius.circular(12),
|
||
),
|
||
child: Icon(
|
||
item.icon,
|
||
color: item.color,
|
||
size: isMobile ? 24 : 28,
|
||
),
|
||
),
|
||
const SizedBox(width: 16),
|
||
Expanded(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: Text(
|
||
item.title,
|
||
style: TextStyle(
|
||
fontSize: isMobile ? 16 : 18,
|
||
fontWeight: FontWeight.bold,
|
||
color: Colors.grey[800],
|
||
),
|
||
),
|
||
),
|
||
_buildPriorityBadge(item.priority),
|
||
],
|
||
),
|
||
const SizedBox(height: 4),
|
||
Row(
|
||
children: [
|
||
Icon(
|
||
Icons.access_time,
|
||
size: 16,
|
||
color: Colors.grey[600],
|
||
),
|
||
const SizedBox(width: 4),
|
||
Text(
|
||
item.estimatedTime,
|
||
style: TextStyle(
|
||
fontSize: 14,
|
||
color: Colors.grey[600],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 16),
|
||
Text(
|
||
item.description,
|
||
style: TextStyle(
|
||
fontSize: isMobile ? 14 : 16,
|
||
color: Colors.grey[700],
|
||
height: 1.4,
|
||
),
|
||
),
|
||
const SizedBox(height: 16),
|
||
ExpansionTile(
|
||
title: const Text(
|
||
'查看详情',
|
||
style: TextStyle(
|
||
fontSize: 14,
|
||
fontWeight: FontWeight.w500,
|
||
),
|
||
),
|
||
tilePadding: EdgeInsets.zero,
|
||
childrenPadding: const EdgeInsets.only(top: 8),
|
||
children: [
|
||
...item.details.map((detail) => Padding(
|
||
padding: const EdgeInsets.only(bottom: 4),
|
||
child: Row(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Container(
|
||
margin: const EdgeInsets.only(top: 6),
|
||
width: 4,
|
||
height: 4,
|
||
decoration: BoxDecoration(
|
||
color: item.color,
|
||
shape: BoxShape.circle,
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
Expanded(
|
||
child: Text(
|
||
detail,
|
||
style: TextStyle(
|
||
fontSize: 13,
|
||
color: Colors.grey[600],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
)),
|
||
],
|
||
),
|
||
const SizedBox(height: 16),
|
||
SizedBox(
|
||
width: double.infinity,
|
||
child: ElevatedButton(
|
||
onPressed: () => _handleRecommendationTap(item),
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: item.color,
|
||
foregroundColor: Colors.white,
|
||
padding: EdgeInsets.symmetric(
|
||
vertical: isMobile ? 12 : 16,
|
||
),
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(12),
|
||
),
|
||
),
|
||
child: Text(
|
||
item.action,
|
||
style: TextStyle(
|
||
fontSize: isMobile ? 14 : 16,
|
||
fontWeight: FontWeight.w600,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildPriorityBadge(String priority) {
|
||
Color color;
|
||
String text;
|
||
|
||
switch (priority) {
|
||
case 'high':
|
||
color = Colors.red;
|
||
text = '高优先级';
|
||
break;
|
||
case 'medium':
|
||
color = Colors.orange;
|
||
text = '中优先级';
|
||
break;
|
||
case 'low':
|
||
color = Colors.green;
|
||
text = '低优先级';
|
||
break;
|
||
default:
|
||
color = Colors.grey;
|
||
text = '普通';
|
||
}
|
||
|
||
return Container(
|
||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||
decoration: BoxDecoration(
|
||
color: color.withOpacity(0.1),
|
||
borderRadius: BorderRadius.circular(12),
|
||
border: Border.all(color: color, width: 1),
|
||
),
|
||
child: Text(
|
||
text,
|
||
style: TextStyle(
|
||
fontSize: 12,
|
||
color: color,
|
||
fontWeight: FontWeight.w500,
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
void _handleRecommendationTap(RecommendationItem item) {
|
||
switch (item.type) {
|
||
case RecommendationType.vocabulary:
|
||
Navigator.of(context).pushNamed('/vocabulary/daily-words');
|
||
break;
|
||
case RecommendationType.review:
|
||
Navigator.of(context).pushNamed('/vocabulary/review');
|
||
break;
|
||
case RecommendationType.test:
|
||
Navigator.of(context).pushNamed('/vocabulary/test');
|
||
break;
|
||
case RecommendationType.plan:
|
||
Navigator.of(context).pushNamed('/vocabulary/study-plan');
|
||
break;
|
||
case RecommendationType.weakness:
|
||
// 处理薄弱点强化
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
enum RecommendationType {
|
||
vocabulary,
|
||
review,
|
||
test,
|
||
plan,
|
||
weakness,
|
||
}
|
||
|
||
class RecommendationItem {
|
||
final RecommendationType type;
|
||
final String title;
|
||
final String description;
|
||
final String priority;
|
||
final String estimatedTime;
|
||
final IconData icon;
|
||
final Color color;
|
||
final String action;
|
||
final List<String> details;
|
||
|
||
const RecommendationItem({
|
||
required this.type,
|
||
required this.title,
|
||
required this.description,
|
||
required this.priority,
|
||
required this.estimatedTime,
|
||
required this.icon,
|
||
required this.color,
|
||
required this.action,
|
||
required this.details,
|
||
});
|
||
} |