ar_tourism_flutter_unity/lib/pages/mine/mine.dart
2025-05-14 17:04:13 +08:00

745 lines
29 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:share_plus/share_plus.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../apis/app.dart';
import '../../components/emptyState.dart';
import '../../components/workGrid.dart';
import 'authInfo.dart';
// 添加 WorkItem 类定义
class WorkItem {
final String imageUrl;
final String title;
final String count;
final int workId;
final bool showUpvote;
final String isAddLike; // 添加点赞状态字段
const WorkItem({
required this.imageUrl,
required this.title,
this.count = '0',
required this.workId,
this.showUpvote = true,
this.isAddLike = '0',
});
factory WorkItem.fromJson(Map<String, dynamic> json) {
return WorkItem(
imageUrl: json['workAddress']?.toString() ?? '',
title: json['workName']?.toString() ?? '',
count: json['receiveRockets']?.toString() ?? '0',
workId: json['workId'] ?? 0,
isAddLike: json['isAddLike']?.toString() ?? '0',
);
}
}
class MinePage extends StatefulWidget {
const MinePage({super.key});
@override
State<MinePage> createState() => _MinePageState();
}
class _MinePageState extends State<MinePage> {
late List<WorkItem> publishedWorks = [];
String storedPhone = '';
bool isLoading = true;
String? error;
Map<String, dynamic> userInfo = {
'avatar': null,
'nickName': '',
'signature': '',
};
@override
void initState() {
super.initState();
_loadUserData();
}
Future<void> _loadUserData() async {
try {
SharedPreferences prefs = await SharedPreferences.getInstance();
storedPhone = prefs.getString('phone') ?? '';
final result = await userApi.getSetting(storedPhone);
if (result['code'] == 200) {
if (mounted) {
setState(() {
userInfo = result;
isLoading = false;
});
getPublishedWorks();
}
}
} catch (e) {
if (mounted) {
setState(() {
error = '获取用户数据失败';
isLoading = false;
});
}
}
}
// 分享内容
void shareContent() {
final box = context.findRenderObject() as RenderBox;
String contentToShare = '这是我想分享的内容';
Share.share(
contentToShare,
subject: "分享主题",
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size,
);
}
// 获取我的发布作品
Future<void> getPublishedWorks() async {
try {
setState(() {
isLoading = true;
error = null;
});
final result = await userApi.getMyPublish();
if (result['code'] == 200) {
final List<dynamic> data = result['data'] ?? [];
// 直接使用服务器返回的点赞状态,而不是依赖本地存储
setState(() {
publishedWorks = data.map((item) {
return WorkItem(
workId: item['workId'] ?? '',
imageUrl: item['workAddress'] ?? '',
title: item['workName'] ?? '',
count: (item['receiveRockets'] ?? 0).toString(),
isAddLike: item['isAddLike']?.toString() ?? '0',
);
}).toList();
});
// 同步更新SharedPreferences中的点赞状态
_syncLikedWorksToPrefs();
} else {
setState(() {
error = result['msg'] ?? '未知错误';
});
}
} catch (e) {
setState(() {
error = '获取数据失败';
});
} finally {
setState(() {
isLoading = false;
});
}
}
// 同步点赞状态到本地存储
Future<void> _syncLikedWorksToPrefs() async {
try {
final prefs = await SharedPreferences.getInstance();
final likedWorkIds = publishedWorks
.where((work) => work.isAddLike == '1')
.map((work) => work.workId.toString())
.toList();
await prefs.setStringList('likedWorks', likedWorkIds);
} catch (e) {
print('同步点赞状态失败: $e');
}
}
String _truncateText(String text, int maxLength, int maxLines) {
if (text.isEmpty) return text;
final List<String> lines = [];
int startIndex = 0;
int currentLine = 0;
while (startIndex < text.length && currentLine < maxLines) {
int endIndex = startIndex + maxLength;
if (endIndex >= text.length) {
lines.add(text.substring(startIndex));
break;
}
lines.add(
'${text.substring(startIndex, endIndex)}${currentLine < maxLines - 1 ? '' : '...'}');
startIndex = endIndex;
currentLine++;
}
return lines.join('\n');
}
Future<void> handleLike(int index) async {
final workId = publishedWorks[index].workId;
final isLiked = publishedWorks[index].isAddLike == '1';
try {
final response = isLiked
? await userApi.getCancelLikeWork(workId)
: await userApi.getLikeWork(workId);
if (response['code'] == 200) {
// 更新当前页面状态
setState(() {
final updatedItems = List<WorkItem>.from(publishedWorks);
updatedItems[index] = WorkItem(
workId: publishedWorks[index].workId,
imageUrl: publishedWorks[index].imageUrl,
title: publishedWorks[index].title,
count: isLiked
? (int.parse(publishedWorks[index].count) - 1).toString()
: (int.parse(publishedWorks[index].count) + 1).toString(),
isAddLike: isLiked ? '0' : '1',
);
publishedWorks = updatedItems;
});
// 更新SharedPreferences中的点赞状态
await _syncLikedWorksToPrefs();
} else {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(response['msg'] ?? '操作失败'),
backgroundColor: Colors.red,
),
);
}
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('操作失败: $e'),
backgroundColor: Colors.red,
),
);
}
}
}
Widget _buildStatItem(
BuildContext context,
String label,
String count,
VoidCallback onTap,
) {
return GestureDetector(
onTap: onTap,
child: Column(
children: [
Text(
count,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(height: 4),
Text(
label,
style: const TextStyle(
fontSize: 12,
color: Color(0xffc1c1c1),
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
// if (isLoading) {
// return const Scaffold(
// body: Center(
// child: CircularProgressIndicator(),
// ),
// );
// }
// 如果未登录,返回空页面(防止闪现)
// if (!isLoggedIn) {
// return const SizedBox.shrink();
// }
return Scaffold(
body: Container(
width: double.infinity,
color: const Color(0xff0C0C16),
child: Stack(
children: [
Positioned(
top: 0,
left: 0,
child: GestureDetector(
onTap: () {
Navigator.pushNamed(
context,
"/change",
arguments: userInfo['background'],
);
},
child: Container(
width: MediaQuery.of(context).size.width,
height: 230,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
userInfo['background'] ?? 'images/detail_bg.png',
),
fit: BoxFit.fill,
),
),
child: Column(
children: [
Container(
padding: const EdgeInsets.only(top: 45, right: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
// IconButton(
// padding: EdgeInsets.zero,
// constraints: const BoxConstraints(),
// icon: Image.asset(
// 'images/share.png',
// width: 19,
// height: 19,
// fit: BoxFit.cover,
// ),
// onPressed: shareContent,
// ),
SizedBox(
height: 20,
)
],
),
),
Container(
padding: const EdgeInsets.only(left: 16, right: 16),
child: Column(
children: [
Row(
children: [
GestureDetector(
onTap: () {
Navigator.pushNamed(
context,
'/myInfo',
arguments: userInfo,
);
},
child: CircleAvatar(
radius: 42,
backgroundImage:
(userInfo['avatar'] == null ||
userInfo['avatar']
.toString()
.isEmpty)
? const AssetImage(
'images/default_avatar.png')
: NetworkImage(userInfo['avatar'])
as ImageProvider,
),
),
const SizedBox(width: 16.0),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
_truncateText(
userInfo['nickName'], 8, 3),
style: const TextStyle(
fontSize: 20,
color: Color(0xffffffff),
decoration: TextDecoration.none,
fontWeight: FontWeight.bold,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(width: 10),
TextButton(
onPressed: userInfo[
'authenticationStatus'] ==
'1'
? () {
// 跳转到认证信息页面
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
AuthInfoPage(),
),
);
}
: () {
Navigator.pushNamed(
context,
"/realName",
);
},
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(
userInfo['authenticationStatus'] ==
'1'
? const Color(0xff70DEED)
: const Color(0xff4E4E4E),
),
padding: MaterialStateProperty.all(
const EdgeInsets.symmetric(
vertical: 2,
horizontal: 8,
),
),
minimumSize:
MaterialStateProperty.all(
const Size(40, 10),
),
tapTargetSize: MaterialTapTargetSize
.shrinkWrap,
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(4),
),
),
),
child: Text(
userInfo['authenticationStatus'] ==
'1'
? '已认证'
: '实名认证',
style: const TextStyle(
color: Colors.black,
fontSize: 12,
),
),
),
],
),
const SizedBox(height: 10),
Text(
_truncateText(
userInfo['signature'] ?? '暂无个性签名',
15,
3),
style: const TextStyle(
color: Color(0xffE9E9E9),
fontSize: 12,
decoration: TextDecoration.none,
),
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
],
),
],
),
],
),
),
],
),
),
),
),
Positioned(
top: 170,
left: 0,
right: 0,
child: Container(
height: 60,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black.withOpacity(0),
Colors.black.withOpacity(1),
],
),
),
),
),
Positioned(
top: 145,
left: 0,
right: 0,
child: Container(
padding: const EdgeInsets.only(
top: 20, left: 115), // 修改左边距为16与用户名对齐
child: Row(
children: [
// 改为普通Row使用SizedBox控制间距
_buildStatItem(context, '关注', "${userInfo['following']}",
() {
Navigator.pushNamed(
context,
'/like',
arguments: {"initialTabIndex": 0},
);
}),
const SizedBox(width: 25), // 添加25px的间距
_buildStatItem(context, '欢迎度', "${userInfo['followed']}",
() {
Navigator.pushNamed(
context,
'/like',
arguments: {"initialTabIndex": 1},
);
}),
const SizedBox(width: 25), // 添加25px的间距
_buildStatItem(context, '喜爱', "${userInfo['popularity']}",
() {
Navigator.pushNamed(context, '/recevieLike');
}),
],
),
),
),
Positioned(
left: 0,
top: 230,
bottom: 0,
child: Container(
width: MediaQuery.of(context).size.width,
// decoration: const BoxDecoration(
// image: DecorationImage(
// image: AssetImage('images/mine_bg.png'),
// fit: BoxFit.fill,
// ),
// ),
color: const Color(0xff0C0C16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 固定不滚动的部分
Container(
color: const Color(0xff0C0C16), // 确保上部分背景色一致
child: Column(
children: [
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
GestureDetector(
onTap: () {
Navigator.pushNamed(context, '/history');
},
child: Column(
children: [
Image.asset(
'images/history.png',
width: 30,
height: 30,
),
const SizedBox(height: 4),
const Text(
'历史订单',
style: TextStyle(
fontSize: 12,
color: Colors.white,
),
),
],
),
),
GestureDetector(
onTap: () {
Navigator.pushNamed(context, '/works');
},
child: Column(
children: [
Image.asset(
'images/works.png',
width: 30,
height: 30,
),
const SizedBox(height: 4),
const Text(
'作品集',
style: TextStyle(
fontSize: 12,
color: Colors.white,
),
),
],
),
),
GestureDetector(
onTap: () {
Navigator.pushNamed(context, '/help');
},
child: Column(
children: [
Image.asset(
'images/help.png',
width: 30,
height: 30,
),
const SizedBox(height: 4),
const Text(
'帮助中心',
style: TextStyle(
fontSize: 12,
color: Colors.white,
),
),
],
),
),
GestureDetector(
onTap: () {
var userInfoWithPhone = {
...userInfo,
'phone': storedPhone
};
Navigator.pushNamed(
context,
'/setting',
arguments: userInfoWithPhone,
);
},
child: Column(
children: [
Image.asset(
'images/setting.png',
width: 30,
height: 30,
),
const SizedBox(height: 4),
const Text(
'设置中心',
style: TextStyle(
fontSize: 12,
color: Colors.white,
),
),
],
),
),
],
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Padding(
padding: EdgeInsets.only(left: 20),
child: Text(
"我的发布",
style: TextStyle(
color: Color(0xffffffff),
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
Padding(
padding: const EdgeInsets.only(right: 20),
child: GestureDetector(
onTap: () {
Navigator.pushNamed(context, '/drafts');
},
child: const Column(
children: [
Image(
image: AssetImage(
'images/save_drafts.png'),
width: 23,
height: 23,
),
SizedBox(height: 4),
Text(
'草稿箱',
style: TextStyle(
fontSize: 10,
color: Color(0xffc1c1c1),
),
)
],
),
),
),
],
),
],
),
),
// 可滚动的网格部分
Expanded(
child: Container(
color: const Color(0xff0C0C16), // 确保网格部分背景色一致
child: RefreshIndicator(
onRefresh: getPublishedWorks,
child: publishedWorks.isEmpty
? const EmptyState(
message: '暂无发布内容',
usePureBackground: true, // 指定使用纯色背景
)
: SingleChildScrollView(
physics:
const AlwaysScrollableScrollPhysics(),
child: WorkGridView(
items: publishedWorks,
onTap: (index) async {
final result = await Navigator.pushNamed(
context,
'/worksDetail',
arguments: {
'id': publishedWorks[index].workId,
'type': 'publish',
},
);
if (result != null &&
result is Map<String, dynamic>) {
setState(() {
final updatedItems =
List<WorkItem>.from(
publishedWorks);
updatedItems[index] = WorkItem(
workId:
publishedWorks[index].workId,
imageUrl:
publishedWorks[index].imageUrl,
title: publishedWorks[index].title,
count: result['receiveRockets']
.toString(),
isAddLike:
result['isAddLike'].toString(),
);
publishedWorks = updatedItems;
});
}
},
onLikeTap: handleLike,
),
),
),
),
),
],
),
),
),
],
),
),
);
}
}