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

575 lines
16 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 '../../apis/app.dart';
import 'package:flutter/material.dart';
import '../../components/CustomAlertDialog.dart';
import '../../components/emptyState.dart';
// 创建数据模型
class FollowData {
final int userId;
final String nickName;
final String avatar;
final String? detail;
final DateTime createTime;
final String followStatus;
FollowData({
required this.userId,
required this.nickName,
required this.avatar,
this.detail,
required this.createTime,
required this.followStatus,
});
factory FollowData.fromJson(Map<String, dynamic> json) {
return FollowData(
userId: json['userId'] ?? 0,
nickName: json['nickName'] ?? '',
avatar: json['avatar'] ?? '',
detail: json['detail'],
createTime: json['createTime'] != null
? DateTime.parse(json['createTime'])
: DateTime.now(),
followStatus: json['followStatus'] ?? '0',
);
}
}
class LikePage extends StatefulWidget {
final Map<String, int> initialTabIndex;
const LikePage({super.key, required this.initialTabIndex});
@override
State<LikePage> createState() => _LikePageState();
}
class _LikePageState extends State<LikePage> with SingleTickerProviderStateMixin {
List<FollowData> followList = [];
List<FollowData> fansList = [];
// 为关注列表和粉丝列表分别添加总数计数
int followTotalCount = 0;
int fansTotalCount = 0;
late TabController _tabController;
bool isLoading = false;
int currentPage = 1;
int totalCount = 0;
final ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
_tabController = TabController(
length: 2,
vsync: this,
initialIndex: widget.initialTabIndex["initialTabIndex"] ?? 0, // 设置初始索引
);
_tabController.addListener(_onTabChanged);
_scrollController.addListener(_onScroll);
_initializeData();
}
void _initializeData() {
// 使用 widget.initialTabIndex 来决定加载哪个列表
if (widget.initialTabIndex["initialTabIndex"] == 1) {
getMyFans();
} else {
getMyFollow();
}
}
@override
void dispose() {
_scrollController.dispose();
_tabController.dispose();
super.dispose();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_tabController.index = widget.initialTabIndex["initialTabIndex"] ?? 0;
}
void _onScroll() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_loadMore();
}
}
Future<void> _loadMore() async {
if (isLoading) return;
final currentList = _tabController.index == 0 ? followList : fansList;
final totalItems = _tabController.index == 0 ? followTotalCount : fansTotalCount;
if (currentList.length >= totalItems) return;
if (_tabController.index == 0) {
await getMyFollow(page: currentPage + 1);
} else {
await getMyFans(page: currentPage + 1);
}
}
void _onTabChanged() {
if (_tabController.indexIsChanging) {
setState(() {
currentPage = 1;
});
if (_tabController.index == 0) {
getMyFollow(page: 1);
} else {
getMyFans(page: 1);
}
}
}
// 添加刷新列表的方法
void refreshList() {
setState(() {
if (_tabController.index == 0) {
followList = [];
} else {
fansList = [];
}
currentPage = 1;
});
if (_tabController.index == 0) {
getMyFollow(page: 1);
} else {
getMyFans(page: 1);
}
}
Future<void> getMyFans({int page = 1}) async {
if (isLoading) return;
setState(() => isLoading = true);
try {
final result = await userApi.getMyFans(
page: page,
pageSize: 10,
);
if (result['code'] == 200) {
final List<dynamic> data = result['rows'];
setState(() {
if (page == 1) {
fansList = data.map((item) => FollowData.fromJson(item)).toList();
} else {
fansList.addAll(data.map((item) => FollowData.fromJson(item)).toList());
}
fansTotalCount = result['total']; // 更新粉丝总数
currentPage = page;
});
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('获取粉丝列表失败')),
);
}
} finally {
if (mounted) {
setState(() => isLoading = false);
}
}
}
Future<void> getMyFollow({int page = 1}) async {
if (isLoading) return;
setState(() => isLoading = true);
try {
final result = await userApi.getMyFollow(
page: page,
pageSize: 10,
);
if (result['code'] == 200) {
final List<dynamic> data = result['rows'];
setState(() {
if (page == 1) {
followList = data.map((item) => FollowData.fromJson(item)).toList();
} else {
followList.addAll(data.map((item) => FollowData.fromJson(item)).toList());
}
followTotalCount = result['total']; // 更新关注总数
currentPage = page;
});
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('获取关注列表失败')),
);
}
} finally {
if (mounted) {
setState(() => isLoading = false);
}
}
}
@override
Widget build(BuildContext context) {
return DefaultTabController(
initialIndex: widget.initialTabIndex["initialTabIndex"] ?? 0,
length: 2,
child: Scaffold(
appBar: AppBar(
leading: Padding(
padding: const EdgeInsets.all(8.0),
child: IconButton(
icon: Image.asset(
'images/arraw.png',
width: 11,
height:22,
fit: BoxFit.cover,
),
onPressed: () => Navigator.pop(context),
),
),
title: Center( // 将TabBar居中
child: SizedBox(
width: 316, // 设置一个合适的宽度
child: TabBar(
controller: _tabController,
tabs: const [
Tab(text: '关注'),
Tab(text: '欢迎度'),
],
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(
width: 2.0,
color: Color(0xFF80DAA4),
),
insets: EdgeInsets.symmetric(horizontal: 30.0),
),
labelColor: Colors.white,
unselectedLabelColor: Colors.grey,
),
),
),
// 添加一个空的actions保持标题居中
actions: [
const SizedBox(width: 48), // 与leading宽度相同
],
),
body: Container(
decoration: const BoxDecoration(color: Color(0xff0C0C16)),
child: RefreshIndicator(
onRefresh: () async {
refreshList();
},
child: TabBarView(
controller: _tabController,
children: [
LikeTab(
followList: followList,
scrollController: _scrollController,
isLoading: isLoading,
totalCount: followTotalCount,
onRefreshNeeded: refreshList,
isFollowTab: true,
),
LikeTab(
followList: fansList,
scrollController: _scrollController,
isLoading: isLoading,
totalCount: fansTotalCount,
onRefreshNeeded: refreshList,
isFollowTab: false,
),
],
),
),
),
),
);
}
}
class LikeTab extends StatelessWidget {
final List<FollowData> followList;
final ScrollController scrollController;
final bool isLoading;
final int totalCount;
final VoidCallback onRefreshNeeded;
final bool isFollowTab;
const LikeTab({
super.key,
required this.followList,
required this.scrollController,
required this.isLoading,
required this.totalCount,
required this.onRefreshNeeded,
required this.isFollowTab,
});
@override
Widget build(BuildContext context) {
// 如果列表为空,直接显示占满屏幕的空状态
if (followList.isEmpty) {
return Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/mine_bg.png'),
fit: BoxFit.cover,
),
),
child: const Center(
child: EmptyState(message: '暂无数据'),
),
);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 10),
child: Text(
isFollowTab ? '我的关注($totalCount' : '我的欢迎度($totalCount',
style: const TextStyle(fontSize: 12, color: Colors.white),
textAlign: TextAlign.left,
),
),
Expanded(
child: ListView.builder(
controller: scrollController,
padding: const EdgeInsets.symmetric(horizontal: 20), // 统一左边距
itemCount: followList.length + 1,
itemBuilder: (context, index) {
if (index == followList.length) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 16),
alignment: Alignment.center,
child: followList.isEmpty
? const EmptyState(message: '暂无数据')
: followList.length < totalCount
? const SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
strokeWidth: 2.0,
color: Colors.white,
),
)
: const Text(
'已经到底啦',
style: TextStyle(
color: Colors.grey,
fontSize: 14,
),
),
);
}
final item = followList[index];
return Padding(
padding: const EdgeInsets.symmetric(vertical: 18),
child: FollowItem(
userId: item.userId,
nickName: item.nickName,
detail: item.detail ?? '',
followStatus: item.followStatus,
avatar: item.avatar,
isFollowTab: isFollowTab,
onFollowStatusChanged: onRefreshNeeded,
),
);
},
),
),
],
);
}
}
class FollowItem extends StatefulWidget {
final String avatar;
final String nickName;
final String detail;
final String followStatus;
final int userId;
final bool isFollowTab;
final VoidCallback? onFollowStatusChanged;
const FollowItem({
super.key,
required this.avatar,
required this.nickName,
required this.detail,
required this.followStatus,
required this.userId,
required this.isFollowTab,
this.onFollowStatusChanged,
});
@override
State<FollowItem> createState() => _FollowItemState();
}
class _FollowItemState extends State<FollowItem> {
late String _currentStatus;
// bool _isLoading = false;
@override
void initState() {
super.initState();
_currentStatus = widget.followStatus;
}
String _getButtonText() {
if (widget.isFollowTab) {
return '已关注';
}
return _currentStatus == '1' ? '互相关注' : '回关';
}
Color _getButtonTextColor() {
if (widget.isFollowTab) {
return const Color(0xff6D717A);
}
return _currentStatus == '1'
? const Color(0xff6D717A)
: const Color(0xffFF4B4B); // 修改为红色
}
Future<void> _handleFollowAction() async {
// if (_isLoading) return;
// setState(() => _isLoading = true);
try {
if (widget.isFollowTab || _currentStatus == '1') {
// 显示取消关注确认框
final bool? shouldUnfollow = await showDialog<bool>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return CustomAlertDialog(
title: '确认不再关注?',
content: '',
onConfirm: () {
Navigator.of(context).pop(true);
},
confirmText: '确定',
cancelText: '取消',
);
},
);
if (shouldUnfollow == true) {
final result = await userApi.cancelFollow(widget.userId);
debugPrint('取消关注响应数据: $result');
if (result['code'] == 200) {
setState(() => _currentStatus = '0');
widget.onFollowStatusChanged?.call();
if (widget.isFollowTab) {
return;
}
}
}
} else {
debugPrint('点击回关按钮');
// 直接关注
final result = await userApi.addFollow(widget.userId);
debugPrint('回关响应数据: $result');
if (result['code'] == 200) {
setState(() => _currentStatus = '1');
if (widget.isFollowTab) {
widget.onFollowStatusChanged?.call();
}
}
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('操作失败: ${e.toString()}')),
);
}
}
}
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
GestureDetector(
onTap: () {
Navigator.pushNamed(
context,
'/otherMine',
arguments: {
'userId': widget.userId,
'avatar': widget.avatar,
'nickName': widget.nickName,
'isFollow': widget.followStatus,
},
);
},
child: CircleAvatar(
backgroundImage: NetworkImage(widget.avatar),
radius: 24,
),
),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.nickName,
style: const TextStyle(fontSize: 16, color: Colors.white),
),
const SizedBox(height: 5),
SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
child: Text(
widget.detail,
style: const TextStyle(fontSize: 12, color: Colors.grey),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
],
),
],
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.transparent,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius:const BorderRadius.all(Radius.circular(50)),
side: BorderSide(
// 根据状态动态设置边框颜色
color: widget.isFollowTab || _currentStatus == '1'
? const Color(0xff464952)
: const Color(0xffFF4B4B),
width: 1.5,
),
),
minimumSize: const Size(70, 26),
padding: const EdgeInsets.all(0),
),
onPressed: _handleFollowAction,
child: Text(
_getButtonText(),
style: TextStyle(
color: _getButtonTextColor(),
fontSize: 12,
),
),
),
],
);
}
}