马良AI写作初始化仓库

This commit is contained in:
邓滨杰
2025-09-10 00:07:52 +08:00
parent 3c06bb1a03
commit 39c0f8840f
1309 changed files with 318528 additions and 0 deletions

View File

@@ -0,0 +1,346 @@
import 'package:flutter/material.dart';
import 'package:ainoval/utils/web_theme.dart';
class AppSidebar extends StatefulWidget {
final bool isExpanded;
final Function(bool)? onExpandedChanged;
final Function(String)? onNavigate; // 添加导航回调
final String? currentRoute; // 可选的当前路由高亮
final bool isAuthed; // 是否已登录
final VoidCallback? onRequireAuth; // 触发登录
const AppSidebar({
Key? key,
this.isExpanded = true,
this.onExpandedChanged,
this.onNavigate,
this.currentRoute,
this.isAuthed = true,
this.onRequireAuth,
}) : super(key: key);
@override
State<AppSidebar> createState() => _AppSidebarState();
}
class _AppSidebarState extends State<AppSidebar> with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _widthAnimation;
bool _isExpanded = true;
@override
void initState() {
super.initState();
_isExpanded = widget.isExpanded;
_animationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_widthAnimation = Tween<double>(
begin: 60,
end: 240,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
));
if (_isExpanded) {
_animationController.value = 1.0;
}
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
void _toggleSidebar() {
setState(() {
_isExpanded = !_isExpanded;
if (_isExpanded) {
_animationController.forward();
} else {
_animationController.reverse();
}
widget.onExpandedChanged?.call(_isExpanded);
});
}
@override
Widget build(BuildContext context) {
final isDark = WebTheme.isDarkMode(context);
return AnimatedBuilder(
animation: _widthAnimation,
builder: (context, child) {
return Container(
width: _widthAnimation.value,
height: double.infinity,
decoration: BoxDecoration(
color: isDark ? WebTheme.darkGrey100 : WebTheme.grey50,
border: Border(
right: BorderSide(
color: WebTheme.getBorderColor(context),
width: 1,
),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
Container(
height: 60,
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: WebTheme.getBorderColor(context),
width: 1,
),
),
),
child: Row(
children: [
Icon(
Icons.menu_book,
size: 24,
color: WebTheme.getPrimaryColor(context),
),
if (_isExpanded) ...[
const SizedBox(width: 12),
Expanded(
child: Text(
'AI小说创作',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: WebTheme.getTextColor(context),
),
overflow: TextOverflow.ellipsis,
),
),
],
],
),
),
// Navigation Items
Expanded(
child: ListView(
padding: const EdgeInsets.symmetric(vertical: 8),
children: [
_buildNavItem(
context,
icon: Icons.home,
label: '首页',
isSelected: widget.currentRoute == 'home',
onTap: () => widget.onNavigate?.call('home'),
),
_buildNavItem(
context,
icon: Icons.settings_applications,
label: '我的设定',
isSelected: widget.currentRoute == 'settings',
onTap: () {
if (!widget.isAuthed) {
widget.onRequireAuth?.call();
return;
}
widget.onNavigate?.call('settings');
},
),
_buildNavItem(
context,
icon: Icons.book,
label: '我的小说',
isSelected: widget.currentRoute == 'novels',
onTap: () {
if (!widget.isAuthed) {
widget.onRequireAuth?.call();
return;
}
widget.onNavigate?.call('novels');
},
),
// _buildNavItem(
// context,
// icon: Icons.edit,
// label: '创作中心',
// onTap: () {
// if (!widget.isAuthed) {
// widget.onRequireAuth?.call();
// return;
// }
// },
// ),
// _buildNavItem(
// context,
// icon: Icons.auto_awesome,
// label: 'AI助手',
// onTap: () {
// if (!widget.isAuthed) {
// widget.onRequireAuth?.call();
// return;
// }
// },
// ),
// _buildNavItem(
// context,
// icon: Icons.group,
// label: '社区',
// onTap: () {
// if (!widget.isAuthed) {
// widget.onRequireAuth?.call();
// return;
// }
// },
// ),
_buildNavItem(
context,
icon: Icons.analytics,
label: '数据分析',
isSelected: widget.currentRoute == 'analytics',
onTap: () {
if (!widget.isAuthed) {
widget.onRequireAuth?.call();
return;
}
widget.onNavigate?.call('analytics');
},
),
_buildNavItem(
context,
icon: Icons.workspace_premium,
label: '我的订阅',
isSelected: widget.currentRoute == 'my_subscription',
onTap: () {
if (!widget.isAuthed) {
widget.onRequireAuth?.call();
return;
}
widget.onNavigate?.call('my_subscription');
},
),
const Divider(height: 32),
_buildNavItem(
context,
icon: Icons.settings,
label: '设置',
onTap: () {
if (!widget.isAuthed) {
widget.onRequireAuth?.call();
return;
}
widget.onNavigate?.call('account_settings');
},
),
_buildNavItem(
context,
icon: Icons.help_outline,
label: '帮助',
onTap: () {
if (!widget.isAuthed) {
widget.onRequireAuth?.call();
return;
}
},
),
],
),
),
// Toggle Button
Container(
height: 48,
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: WebTheme.getBorderColor(context),
width: 1,
),
),
),
child: InkWell(
onTap: _toggleSidebar,
child: Center(
child: Icon(
_isExpanded ? Icons.chevron_left : Icons.chevron_right,
size: 20,
color: WebTheme.getSecondaryTextColor(context),
),
),
),
),
],
),
);
},
);
}
Widget _buildNavItem(
BuildContext context, {
required IconData icon,
required String label,
bool isSelected = false,
VoidCallback? onTap,
}) {
final isDark = WebTheme.isDarkMode(context);
return Container(
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
child: Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(8),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(8),
child: Container(
padding: EdgeInsets.symmetric(
horizontal: _isExpanded ? 16 : 12,
vertical: 12,
),
decoration: BoxDecoration(
color: isSelected
? (isDark ? WebTheme.darkGrey200 : WebTheme.grey200)
: Colors.transparent,
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Icon(
icon,
size: 20,
color: isSelected
? WebTheme.getPrimaryColor(context)
: WebTheme.getSecondaryTextColor(context),
),
if (_isExpanded) ...[
const SizedBox(width: 12),
Expanded(
child: Text(
label,
style: TextStyle(
fontSize: 14,
fontWeight: isSelected ? FontWeight.w500 : FontWeight.w400,
color: isSelected
? WebTheme.getTextColor(context)
: WebTheme.getSecondaryTextColor(context),
),
overflow: TextOverflow.ellipsis,
),
),
// 游客模式在展开时显示小提示“需登录”
// 访客提示徽标已移除,保持简洁
],
],
),
),
),
),
);
}
}