460 lines
14 KiB
Dart
460 lines
14 KiB
Dart
import 'dart:math';
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||
import 'package:provider/provider.dart';
|
||
import 'package:shared_preferences/shared_preferences.dart';
|
||
|
||
import '../../apis/app.dart';
|
||
import '../../components/appbar.dart';
|
||
import '../../components/cached_image.dart';
|
||
import '../../providers/auth_provider.dart';
|
||
|
||
class MorePage extends StatefulWidget {
|
||
const MorePage({super.key});
|
||
|
||
@override
|
||
State<MorePage> createState() => _MorePageState();
|
||
}
|
||
|
||
// WidgetsBindingObserver mixin 来监听页面生命周期。
|
||
class _MorePageState extends State<MorePage> with WidgetsBindingObserver {
|
||
// Map来存储每个item的固定高度
|
||
final Map<String, double> _itemHeights = {};
|
||
List _waterFallList = [];
|
||
List<dynamic> _workList = [];
|
||
int countNum = 0;
|
||
int _currentPage = 1;
|
||
String? _userId;
|
||
bool _liked = false;
|
||
int _likesCount = 0;
|
||
|
||
bool _isLoading = false;
|
||
final ScrollController _scrollController = ScrollController();
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
var randomNum = Random();
|
||
for (var i = 0; i < 20; i++) {
|
||
_waterFallList.add(230 + 28 * randomNum.nextDouble());
|
||
}
|
||
print(_waterFallList);
|
||
WidgetsBinding.instance.addObserver(this);
|
||
_fetchWorks();
|
||
// 滚动监听
|
||
_scrollController.addListener(_onScroll);
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
WidgetsBinding.instance.removeObserver(this);
|
||
super.dispose();
|
||
}
|
||
|
||
@override
|
||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||
if (state == AppLifecycleState.resumed) {
|
||
_fetchWorks();
|
||
}
|
||
}
|
||
|
||
//页面重新获得焦点时刷新数据
|
||
Future<void> _onPageResume() async {
|
||
if (mounted) {
|
||
await _fetchWorks();
|
||
}
|
||
}
|
||
|
||
void _onScroll() {
|
||
if (_scrollController.position.pixels ==
|
||
_scrollController.position.maxScrollExtent) {
|
||
_loadMore();
|
||
}
|
||
}
|
||
|
||
Future<void> _loadMore() async {
|
||
// 检查是否正在加载和是否还有更多数据
|
||
if (!_isLoading && _workList.length < countNum) {
|
||
await _fetchWorks(page: _currentPage + 1);
|
||
}
|
||
}
|
||
|
||
Future<void> _fetchWorks({int page = 1}) async {
|
||
if (_isLoading) return;
|
||
|
||
setState(() {
|
||
_isLoading = true;
|
||
});
|
||
|
||
try {
|
||
// 使用 AuthProvider 获取登录状态
|
||
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
||
// 先加载token,确保登录状态是最新的
|
||
await authProvider.loadTokenFromPrefs();
|
||
final bool isLoggedIn = authProvider.isLoggedIn;
|
||
|
||
final works = await userApi.getMoreWork(
|
||
page: page,
|
||
pageSize: 10,
|
||
requiresToken: isLoggedIn,
|
||
);
|
||
|
||
if (works['code'] == 200) {
|
||
if (mounted) {
|
||
// 获取作品列表后,遍历获取每个作者的关注状态
|
||
final List newWorkList = List.from(works['rows']);
|
||
print("newWorkList----------,${newWorkList}");
|
||
if (isLoggedIn) {
|
||
for (var work in newWorkList) {
|
||
try {
|
||
final userResponse = await userApi.getOtherPublish(work['userId'].toString());
|
||
if (userResponse['code'] == 200) {
|
||
work['isFollow'] = userResponse['data']['isFollow'];
|
||
// print("##############################userResponse['data'],${userResponse['data']}");
|
||
}
|
||
} catch (e) {
|
||
print('获取用户${work['userId']}的关注状态失败: $e');
|
||
}
|
||
}
|
||
}
|
||
|
||
setState(() {
|
||
if (page == 1) {
|
||
_workList = newWorkList;
|
||
} else {
|
||
_workList.addAll(newWorkList);
|
||
}
|
||
|
||
countNum = works['total'];
|
||
_currentPage = page;
|
||
});
|
||
|
||
// 确保最新点赞状态同步到本地存储
|
||
if (isLoggedIn) {
|
||
_syncLikedWorksToPrefs();
|
||
}
|
||
}
|
||
}
|
||
} catch (e) {
|
||
if (mounted) {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(content: Text('加载失败,请稍后重试')),
|
||
);
|
||
}
|
||
} finally {
|
||
if (mounted) {
|
||
setState(() {
|
||
_isLoading = false;
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
// 同步点赞状态到本地存储
|
||
Future<void> _syncLikedWorksToPrefs() async {
|
||
try {
|
||
final prefs = await SharedPreferences.getInstance();
|
||
final likedWorkIds = _workList
|
||
.where((work) => work['isAddLike']?.toString() == '1')
|
||
.map((work) => work['workId'].toString())
|
||
.toList();
|
||
|
||
await prefs.setStringList('likedWorks', likedWorkIds);
|
||
} catch (e) {
|
||
print('同步点赞状态失败: $e');
|
||
}
|
||
}
|
||
|
||
Future<void> _navigateToDetail(Map<String, dynamic> work) async {
|
||
if (!mounted) return;
|
||
|
||
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
||
|
||
if (!authProvider.isLoggedIn) {
|
||
await Navigator.pushNamed(context, '/login');
|
||
return;
|
||
}
|
||
|
||
final result = await Navigator.pushNamed(
|
||
context,
|
||
"/infoDetail",
|
||
arguments: {
|
||
'workId': work['workId'],
|
||
'isLiked': work['isAddLike'],
|
||
'likeCount': work['receiveRockets'],
|
||
},
|
||
);
|
||
|
||
if (result != null && result is Map<String, dynamic>) {
|
||
setState(() {
|
||
final index = _workList.indexWhere((item) => item['workId'] == work['workId']);
|
||
if (index != -1) {
|
||
_workList[index]['isAddLike'] = result['isLiked'];
|
||
_workList[index]['receiveRockets'] = result['likeCount'];
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
Future<void> _handleAvatarTap(Map<String, dynamic> work) async {
|
||
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
||
final currentUserId = authProvider.userId;
|
||
|
||
if (currentUserId.toString() == work['userId'].toString()) {
|
||
Navigator.pushNamed(
|
||
context,
|
||
'/tabs',
|
||
arguments: {'initialIndex': 4},
|
||
);
|
||
} else {
|
||
final result = await Navigator.pushNamed(
|
||
context,
|
||
'/otherMine',
|
||
arguments: {
|
||
...work, // 展开所有现有属性
|
||
'userId': work['userId'],
|
||
'nickName': work['nickName'] ?? '未知用户',
|
||
'avatar': work['avatar'] ?? '',
|
||
'isFollow': work['isFollow'] ?? '0',
|
||
'workAddress': work['workAddress'] ?? '',
|
||
'workName': work['workName'] ?? '',
|
||
'receiveRockets': work['receiveRockets'] ?? 0,
|
||
'isAddLike': work['isAddLike'] ?? '0',
|
||
},
|
||
);
|
||
|
||
if (result != null && result is Map<String, dynamic>) {
|
||
setState(() {
|
||
// 更新列表中对应项的关注状态
|
||
final index = _workList.indexWhere(
|
||
(item) => item['userId'] == result['userId']);
|
||
if (index != -1) {
|
||
_workList[index]['isFollow'] = result['isFollowed'] ? "1" : "0";
|
||
}
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
Future<void> _handleLikeInMore(Map<String, dynamic> work) async {
|
||
if (!mounted) return;
|
||
|
||
try {
|
||
final response = work['isAddLike'].toString() == "1"
|
||
? await userApi.getCancelLikeWork(work['workId'])
|
||
: await userApi.getLikeWork(work['workId']);
|
||
|
||
if (!mounted) return;
|
||
|
||
if (response['code'] == 200) {
|
||
setState(() {
|
||
work['isAddLike'] = work['isAddLike'].toString() == "1" ? "0" : "1";
|
||
work['receiveRockets'] = work['isAddLike'].toString() == "1"
|
||
? work['receiveRockets'] + 1
|
||
: work['receiveRockets'] - 1;
|
||
});
|
||
|
||
// 更新SharedPreferences中的点赞状态
|
||
await _syncLikedWorksToPrefs();
|
||
} else {
|
||
if (!mounted) return;
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(
|
||
content: Text(response['msg'] ?? '操作失败'),
|
||
backgroundColor: Colors.red,
|
||
),
|
||
);
|
||
}
|
||
} catch (e) {
|
||
if (!mounted) return;
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(
|
||
content: Text('网络错误,请稍后重试'),
|
||
backgroundColor: Colors.red,
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
resizeToAvoidBottomInset: false,
|
||
appBar: const CustomAppBar(title: ''),
|
||
backgroundColor: Colors.black,
|
||
body: RefreshIndicator(
|
||
onRefresh: () => _fetchWorks(page: 1),
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(10),
|
||
child: ListView(
|
||
controller: _scrollController,
|
||
children: [
|
||
MasonryGridView.count(
|
||
shrinkWrap: true,
|
||
physics: const NeverScrollableScrollPhysics(),
|
||
crossAxisCount: 2,
|
||
itemCount: _workList.length,
|
||
itemBuilder: (BuildContext context, int index) {
|
||
return picCard(_workList[index]);
|
||
},
|
||
mainAxisSpacing: 10,
|
||
crossAxisSpacing: 10,
|
||
),
|
||
if (_workList.isNotEmpty)
|
||
Container(
|
||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||
alignment: Alignment.center,
|
||
child: _workList.length < countNum
|
||
? const SizedBox(
|
||
width: 24,
|
||
height: 24,
|
||
child: CircularProgressIndicator(
|
||
strokeWidth: 2.0,
|
||
color: Colors.white,
|
||
),
|
||
)
|
||
: const Text(
|
||
'已经到底啦',
|
||
style: TextStyle(
|
||
color: Colors.grey,
|
||
fontSize: 14,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget picCard(Map<String, dynamic> work) {
|
||
// 使用workId作为key来获取或生成固定高度
|
||
final double itemHeight = _itemHeights.putIfAbsent(
|
||
work['workId'].toString(),
|
||
() => 230 + Random().nextDouble() * 28,
|
||
);
|
||
String isLiked = work['isAddLike'].toString();
|
||
return GestureDetector(
|
||
onTap: () => _navigateToDetail(work),
|
||
child: Container(
|
||
height: itemHeight,
|
||
child: Stack(
|
||
children: [
|
||
CachedImage(
|
||
imageUrl: work['workAddress'],
|
||
width: double.infinity,
|
||
height: double.infinity,
|
||
fit: BoxFit.cover,
|
||
borderRadius: BorderRadius.circular(10),
|
||
),
|
||
Positioned(
|
||
left: 5,
|
||
top: 5,
|
||
child: GestureDetector(
|
||
onTap: () => _handleAvatarTap(work),
|
||
child: Row(
|
||
children: [
|
||
Container(
|
||
width: 24,
|
||
height: 24,
|
||
decoration: BoxDecoration(
|
||
shape: BoxShape.circle,
|
||
color: const Color(0xFF2C2C2C),
|
||
),
|
||
child: ClipOval(
|
||
child: work['avatar'] != null && work['avatar'].toString().isNotEmpty
|
||
? CachedImage(
|
||
imageUrl: work['avatar'],
|
||
width: 24,
|
||
height: 24,
|
||
fit: BoxFit.cover,
|
||
)
|
||
: const Center(
|
||
child: Icon(
|
||
Icons.person,
|
||
color: Colors.white54,
|
||
size: 12,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(width: 5),
|
||
Text(
|
||
work['nickName'],
|
||
style: const TextStyle(color: Colors.white, fontSize: 12),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
// 渐变背景
|
||
Positioned(
|
||
bottom: 0,
|
||
left: 0,
|
||
right: 0,
|
||
child: Container(
|
||
height: 80,
|
||
decoration: BoxDecoration(
|
||
gradient: LinearGradient(
|
||
begin: Alignment.topCenter,
|
||
end: Alignment.bottomCenter,
|
||
colors: [
|
||
Colors.transparent,
|
||
Colors.black.withOpacity(0.8),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
// 作品信息和点赞按钮
|
||
Positioned(
|
||
left: 5,
|
||
bottom: 8,
|
||
right: 5,
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
Expanded(
|
||
child: Text(
|
||
work['workName'],
|
||
style:
|
||
const TextStyle(color: Colors.white, fontSize: 14),
|
||
overflow: TextOverflow.ellipsis,
|
||
maxLines: 1,
|
||
),
|
||
),
|
||
Row(
|
||
children: [
|
||
GestureDetector(
|
||
onTap: () => _handleLikeInMore(work),
|
||
child: Image.asset(
|
||
'images/upvote.png',
|
||
width: 18,
|
||
height: 18,
|
||
fit: BoxFit.contain,
|
||
color: work['isAddLike'].toString() == "1"
|
||
? const Color(0xffEE7371)
|
||
: const Color(0xffC1C1C1),
|
||
),
|
||
),
|
||
const SizedBox(width: 5),
|
||
Text(
|
||
work['receiveRockets'].toString(),
|
||
style: TextStyle(
|
||
color: work['isAddLike'].toString() == "1"
|
||
? const Color(0xffEE7371)
|
||
: Colors.white,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
));
|
||
}
|
||
}
|