538 lines
16 KiB
Dart
538 lines
16 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:permission_handler/permission_handler.dart';
|
||
import 'package:shared_preferences/shared_preferences.dart';
|
||
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
|
||
import '../../components/CustomAlertDialog.dart';
|
||
import '../center/centerPage.dart';
|
||
import '../home/homePage.dart';
|
||
import '../mine/setting/privacy_policy.dart';
|
||
import '../mine/setting/user_manual.dart';
|
||
import '../publish/publish.dart';
|
||
import '../message/message.dart';
|
||
import '../mine/mine.dart';
|
||
import 'package:flutter/gestures.dart';
|
||
|
||
// Tabs组件抽离
|
||
class Tabs extends StatefulWidget {
|
||
final int initialIndex; //接收参数
|
||
const Tabs({super.key, this.initialIndex = 0});
|
||
|
||
@override
|
||
State<Tabs> createState() => _TabsState();
|
||
}
|
||
|
||
class _TabsState extends State<Tabs> {
|
||
int _currentIndex = 0;
|
||
AssetEntity? selectedAsset;
|
||
int _unreadMessageCount = 0;
|
||
|
||
// 需要登录验证的页面索引
|
||
final Set<int> _authRequiredIndices = {1, 2, 3, 4}; // 除了首页(0)外都需要登录
|
||
|
||
// 添加一个key来标识CenterPage
|
||
final GlobalKey<CenterPageState> centerPageKey = GlobalKey<CenterPageState>();
|
||
|
||
Future<bool> _checkLoginStatus() async {
|
||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||
final isLoggedIn = prefs.getBool('isLoggedIn') ?? false;
|
||
|
||
|
||
|
||
|
||
|
||
|
||
final token = prefs.getString('token');
|
||
return isLoggedIn && token != null;
|
||
}
|
||
|
||
// 添加检查实名认证状态的方法
|
||
Future<bool> _checkRealNameStatus() async {
|
||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||
return prefs.getBool('isRealNameAuth') ?? false;
|
||
}
|
||
|
||
// 显示实名认证提示对话框
|
||
void _showRealNameDialog() {
|
||
showDialog(
|
||
context: context,
|
||
barrierDismissible: false,
|
||
builder: (BuildContext context) {
|
||
return CustomAlertDialog(
|
||
title: '实名认证提示',
|
||
content: '为了保护您的合法权益,请先进行实名认证',
|
||
confirmText: '去实名',
|
||
cancelText: '取消',
|
||
onConfirm: () {
|
||
Navigator.of(context).pop();
|
||
Navigator.pushNamed(context, '/realName');
|
||
},
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
|
||
|
||
// 添加一个新方法来显示用户协议弹窗
|
||
Future<bool> _showAgreementDialog() async {
|
||
bool? result = await showDialog<bool>(
|
||
context: context,
|
||
barrierDismissible: false,
|
||
builder: (BuildContext context) {
|
||
return CustomAlertDialog(
|
||
title: '温馨提示',
|
||
content: '',
|
||
contentWidget: RichText(
|
||
textAlign: TextAlign.center,
|
||
text: TextSpan(
|
||
style: const TextStyle(color: Colors.white54, fontSize: 14),
|
||
children: [
|
||
const TextSpan(text: '如您同意并接受'),
|
||
TextSpan(
|
||
text: '《用户协议》',
|
||
style: const TextStyle(color: Color(0xFF7cd3ba)),
|
||
recognizer: TapGestureRecognizer()
|
||
..onTap = () {
|
||
// 先关闭当前对话框
|
||
Navigator.of(context).pop(false);
|
||
Navigator.push(
|
||
context,
|
||
MaterialPageRoute(builder: (context) => const UserManualPage()),
|
||
);
|
||
|
||
},
|
||
),
|
||
const TextSpan(text: '和'),
|
||
TextSpan(
|
||
text: '《隐私政策》',
|
||
style: const TextStyle(color: Color(0xFF7cd3ba)),
|
||
recognizer: TapGestureRecognizer()
|
||
..onTap = () {
|
||
// 先关闭当前对话框
|
||
Navigator.of(context).pop(false);
|
||
// 跳转到隐私政策页面
|
||
Navigator.push(
|
||
context,
|
||
MaterialPageRoute(builder: (context) => const PrivacyPolicyPage()),
|
||
);
|
||
|
||
},
|
||
),
|
||
const TextSpan(text: '全部条款后,可使用完整功能'),
|
||
],
|
||
),
|
||
),
|
||
onConfirm: () {
|
||
Navigator.of(context).pop(true); // 用户同意
|
||
},
|
||
onCancel: () {
|
||
Navigator.of(context).pop(false); // 用户不同意
|
||
},
|
||
confirmText: '同意并继续',
|
||
cancelText: '不同意',
|
||
);
|
||
},
|
||
);
|
||
return result ?? false;
|
||
}
|
||
|
||
Future<void> _handleCenterTap() async {
|
||
// 同时请求相机和相册权限
|
||
final statuses = await [
|
||
Permission.camera,
|
||
Permission.photos, // iOS相册权限
|
||
Permission.storage, // Android存储权限
|
||
].request();
|
||
|
||
// 检查所有权限是否已授予
|
||
final allGranted = statuses[Permission.camera]?.isGranted == true &&
|
||
(statuses[Permission.photos]?.isGranted == true ||
|
||
statuses[Permission.storage]?.isGranted == true);
|
||
|
||
if (!allGranted) {
|
||
if (mounted) {
|
||
showDialog(
|
||
context: context,
|
||
builder: (context) => CustomAlertDialog(
|
||
title: '需要权限授权',
|
||
content: '请允许访问相机和相册权限以继续操作',
|
||
confirmText: '去设置',
|
||
onConfirm: () => openAppSettings(),
|
||
cancelText: '取消',
|
||
),
|
||
);
|
||
}
|
||
return;
|
||
}
|
||
bool isLoggedIn = await _checkLoginStatus();
|
||
|
||
if (!isLoggedIn) {
|
||
if (mounted) {
|
||
// 先显示协议弹窗
|
||
bool agreed = await _showAgreementDialog();
|
||
|
||
if (!agreed) {
|
||
// 用户不同意,跳转到首页
|
||
setState(() {
|
||
_currentIndex = 0;
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 用户同意,跳转到登录页
|
||
final result = await Navigator.pushNamed(context, '/login');
|
||
if (result == true) {
|
||
// 检查实名认证状态
|
||
bool isRealNameAuth = await _checkRealNameStatus();
|
||
if (!isRealNameAuth) {
|
||
if (mounted) {
|
||
_showRealNameDialog();
|
||
}
|
||
return;
|
||
}
|
||
// 已登录且已实名认证,直接打开相册选择器
|
||
await _openAssetPicker();
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 已登录,检查实名认证状态
|
||
bool isRealNameAuth = await _checkRealNameStatus();
|
||
if (!isRealNameAuth) {
|
||
if (mounted) {
|
||
_showRealNameDialog();
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 已登录且已实名认证,直接打开相册选择器
|
||
await _openAssetPicker();
|
||
}
|
||
// Future<void> _handleCenterTap() async {
|
||
// bool isLoggedIn = await _checkLoginStatus();
|
||
|
||
// if (!isLoggedIn) {
|
||
// if (mounted) {
|
||
// final result = await Navigator.pushNamed(context, '/login');
|
||
// if (result == true) {
|
||
// // 检查实名认证状态
|
||
// bool isRealNameAuth = await _checkRealNameStatus();
|
||
// if (!isRealNameAuth) {
|
||
// if (mounted) {
|
||
// _showRealNameDialog();
|
||
// }
|
||
// return;
|
||
// }
|
||
// // 已登录且已实名认证,先设置当前索引为2(CenterPage)
|
||
// setState(() {
|
||
// _currentIndex = 2;
|
||
// });
|
||
// await _openAssetPicker(); // 打开相册选择器
|
||
// }
|
||
// }
|
||
// return;
|
||
// }
|
||
|
||
// // 已登录,检查实名认证状态
|
||
// bool isRealNameAuth = await _checkRealNameStatus();
|
||
// if (!isRealNameAuth) {
|
||
// if (mounted) {
|
||
// _showRealNameDialog();
|
||
// }
|
||
// return;
|
||
// }
|
||
|
||
// // 已登录且已实名认证,先设置当前索引为2(CenterPage)
|
||
// setState(() {
|
||
// _currentIndex = 2;
|
||
// });
|
||
// await _openAssetPicker(); // 打开相册选择器
|
||
// }
|
||
|
||
// 修改现有的 _handleTabChange 方法
|
||
Future<void> _handleTabChange(int index) async {
|
||
if (_authRequiredIndices.contains(index)) {
|
||
bool isLoggedIn = await _checkLoginStatus();
|
||
|
||
if (!isLoggedIn) {
|
||
if (mounted) {
|
||
// 先显示协议弹窗
|
||
bool agreed = await _showAgreementDialog();
|
||
|
||
if (!agreed) {
|
||
// 用户不同意,保持在首页
|
||
setState(() {
|
||
_currentIndex = 0;
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 用户同意,跳转到登录页
|
||
final result = await Navigator.pushNamed(context, '/login');
|
||
if (result == true && mounted) {
|
||
// 如果是发布页面(index == 1),需要检查实名认证
|
||
if (index == 1) {
|
||
bool isRealNameAuth = await _checkRealNameStatus();
|
||
if (!isRealNameAuth) {
|
||
_showRealNameDialog();
|
||
return;
|
||
}
|
||
}
|
||
setState(() {
|
||
_currentIndex = index;
|
||
});
|
||
}
|
||
return;
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 已登录,如果是发布页面需要检查实名认证
|
||
if (index == 1) {
|
||
bool isRealNameAuth = await _checkRealNameStatus();
|
||
if (!isRealNameAuth) {
|
||
if (mounted) {
|
||
_showRealNameDialog();
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
setState(() {
|
||
_currentIndex = index;
|
||
});
|
||
}
|
||
|
||
// 将页面列表改为getter方法,动态创建页面实例
|
||
List<Widget> get _pages => [
|
||
const HomePage(),
|
||
const PublishPage(),
|
||
CenterPage(
|
||
key: centerPageKey,
|
||
selectedAsset: selectedAsset,
|
||
), // 将selectedAsset传递给CenterPage
|
||
const MessagePage(),
|
||
const MinePage(),
|
||
];
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_currentIndex = widget.initialIndex;
|
||
_loadUnreadMessageCount();
|
||
|
||
// 添加监听器以定期更新未读消息数
|
||
_startMessageCountTimer();
|
||
|
||
// 延迟执行以确保页面已完全加载
|
||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
final arguments = ModalRoute.of(context)?.settings.arguments as Map<String, dynamic>?;
|
||
|
||
// 检查是否有打开相册选择器的标记
|
||
if (arguments != null && arguments['openAssetPicker'] == true) {
|
||
// 先设置当前索引为2(确保显示CenterPage),再打开相册选择器
|
||
setState(() {
|
||
_currentIndex = 2;
|
||
});
|
||
_openAssetPicker(); // 自动打开相册选择器
|
||
}
|
||
|
||
// 原有的showMessage处理逻辑
|
||
if (arguments != null && arguments['showMessage'] != null) {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(
|
||
content: Text(
|
||
arguments['showMessage'],
|
||
style: const TextStyle(color: Colors.white),
|
||
textAlign: TextAlign.center,
|
||
),
|
||
backgroundColor: const Color(0xFF1A1A29),
|
||
behavior: SnackBarBehavior.floating,
|
||
margin: EdgeInsets.only(
|
||
bottom: MediaQuery.of(context).size.height - 100,
|
||
left: 20,
|
||
right: 20,
|
||
),
|
||
),
|
||
);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 加载未读消息数
|
||
Future<void> _loadUnreadMessageCount() async {
|
||
final prefs = await SharedPreferences.getInstance();
|
||
if (mounted) {
|
||
setState(() {
|
||
_unreadMessageCount = prefs.getInt('unreadMessageCount') ?? 0;
|
||
});
|
||
}
|
||
}
|
||
|
||
// 定期更新未读消息数
|
||
void _startMessageCountTimer() {
|
||
Future.delayed(const Duration(seconds: 5), () {
|
||
if (mounted) {
|
||
_loadUnreadMessageCount();
|
||
_startMessageCountTimer();
|
||
}
|
||
});
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
super.dispose();
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
resizeToAvoidBottomInset: false,
|
||
body: _pages[_currentIndex],
|
||
bottomNavigationBar: Container(
|
||
height: 60,
|
||
color: const Color(0xff0C0C16),
|
||
child: Stack(
|
||
children: [
|
||
// 背景图片
|
||
Positioned(
|
||
left: 0,
|
||
right: 0,
|
||
bottom: 0,
|
||
child: Container(
|
||
margin: const EdgeInsets.symmetric(
|
||
vertical: 5,
|
||
horizontal: 8,
|
||
),
|
||
padding: const EdgeInsets.all(5),
|
||
height: 50,
|
||
decoration: const BoxDecoration(
|
||
image: DecorationImage(
|
||
image: AssetImage('images/bg.png'),
|
||
fit: BoxFit.fill,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
// 导航栏
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||
children: [
|
||
_buildNavItem(0, "images/homePage.png", "images/homePage_active.png", "MR"),
|
||
_buildNavItem(1, "images/recommed.png", "images/recommend_active.png", "发布"),
|
||
// 中间按钮
|
||
Container(
|
||
width: 60,
|
||
height: 60,
|
||
alignment: Alignment.center,
|
||
child: GestureDetector(
|
||
onTap: _handleCenterTap,
|
||
onLongPress: _handleCenterTap,
|
||
child: Container(
|
||
width: 36,
|
||
height: 36,
|
||
decoration: const BoxDecoration(
|
||
shape: BoxShape.circle,
|
||
gradient: LinearGradient(
|
||
colors: [Color(0xff80DAA4), Color(0xff79DDED)],
|
||
begin: Alignment.centerLeft,
|
||
end: Alignment.centerRight,
|
||
),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Color(0x40000000),
|
||
blurRadius: 4,
|
||
offset: Offset(0, 2),
|
||
),
|
||
],
|
||
),
|
||
child: const Icon(
|
||
Icons.add,
|
||
color: Colors.white,
|
||
size: 22,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
_buildNavItem(3, "images/car.png", "images/car_active.png", "消息"),
|
||
_buildNavItem(4, "images/mine.png", "images/mine_active.png", "我的"),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildNavItem(int index, String icon, String activeIcon, String label) {
|
||
final bool isSelected = _currentIndex == index;
|
||
return GestureDetector(
|
||
onTap: () => _handleTabChange(index),
|
||
behavior: HitTestBehavior.opaque,
|
||
child: Container(
|
||
width: 60,
|
||
height: 60,
|
||
child: Column(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Image.asset(
|
||
isSelected ? activeIcon : icon,
|
||
width: 20,
|
||
height: 20,
|
||
),
|
||
const SizedBox(height: 4),
|
||
Text(
|
||
label,
|
||
style: TextStyle(
|
||
fontSize: 10,
|
||
color: isSelected ? const Color(0xff79DDED) : Colors.white,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Future<void> _openAssetPicker() async {
|
||
final List<AssetEntity>? result = await AssetPicker.pickAssets(
|
||
context,
|
||
pickerConfig: const AssetPickerConfig(
|
||
maxAssets: 1,
|
||
requestType: RequestType.image, // 限制只能选择图片
|
||
themeColor: Color(0xff7CDBC8), // 设置主题色
|
||
textDelegate: AssetPickerTextDelegate(), // 使用中文本地化
|
||
specialItemPosition: SpecialItemPosition.none, // 移除特殊项
|
||
specialItemBuilder: null,
|
||
shouldRevertGrid: false,
|
||
gridCount: 4,
|
||
pathThumbnailSize: ThumbnailSize.square(80),
|
||
),
|
||
);
|
||
|
||
if (result != null && result.isNotEmpty && mounted) {
|
||
// 先更新资源
|
||
setState(() {
|
||
selectedAsset = result.first;
|
||
});
|
||
|
||
// 选择完图片后直接切换到CenterPage
|
||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
if (mounted) {
|
||
setState(() {
|
||
_currentIndex = 2;
|
||
});
|
||
// 延迟更新CenterPage的状态
|
||
Future.microtask(() {
|
||
if (centerPageKey.currentState != null) {
|
||
centerPageKey.currentState!.updateSelectedAsset(selectedAsset);
|
||
}
|
||
});
|
||
}
|
||
});
|
||
}
|
||
}
|
||
}
|