16 changed files with 716 additions and 146 deletions
Split View
Diff Options
-
309lib/controller/home/home_controller.dart
-
6lib/controller/setting/blacklist_controller.dart
-
18lib/model/home/check_black_data.dart
-
15lib/model/home/friend_footprint_info_data.dart
-
92lib/model/home/friend_footprint_list_data.dart
-
4lib/network/api_urls.dart
-
4lib/network/home_api.dart
-
36lib/network/home_api.g.dart
-
6lib/network/user_api.dart
-
33lib/network/user_api.g.dart
-
34lib/pages/home/content_card.dart
-
153lib/pages/home/friend_footprint_page.dart
-
120lib/pages/home/recommend_tab.dart
-
26lib/pages/mine/mine_page.dart
-
2lib/pages/mine/real_feedback_page.dart
-
4lib/pages/setting/blacklist_page.dart
@ -0,0 +1,18 @@ |
|||
class CheckBlackData { |
|||
bool? activeBlack; |
|||
bool? passiveBlack; |
|||
|
|||
CheckBlackData({this.activeBlack, this.passiveBlack}); |
|||
|
|||
CheckBlackData.fromJson(Map<String, dynamic> json) { |
|||
activeBlack = json['activeBlack']; |
|||
passiveBlack = json['passiveBlack']; |
|||
} |
|||
|
|||
Map<String, dynamic> toJson() { |
|||
final Map<String, dynamic> data = new Map<String, dynamic>(); |
|||
data['activeBlack'] = this.activeBlack; |
|||
data['passiveBlack'] = this.passiveBlack; |
|||
return data; |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
class FriendFootprintInfoData { |
|||
List<String>? profilePhotoList; |
|||
|
|||
FriendFootprintInfoData({this.profilePhotoList}); |
|||
|
|||
FriendFootprintInfoData.fromJson(Map<String, dynamic> json) { |
|||
profilePhotoList = json['profilePhotoList'].cast<String>(); |
|||
} |
|||
|
|||
Map<String, dynamic> toJson() { |
|||
final Map<String, dynamic> data = new Map<String, dynamic>(); |
|||
data['profilePhotoList'] = this.profilePhotoList; |
|||
return data; |
|||
} |
|||
} |
|||
@ -0,0 +1,92 @@ |
|||
class FriendFootprintListData { |
|||
List<Records>? records; |
|||
int? total; |
|||
int? size; |
|||
int? current; |
|||
int? pages; |
|||
|
|||
FriendFootprintListData( |
|||
{this.records, this.total, this.size, this.current, this.pages}); |
|||
|
|||
FriendFootprintListData.fromJson(Map<String, dynamic> json) { |
|||
if (json['records'] != null) { |
|||
records = <Records>[]; |
|||
json['records'].forEach((v) { |
|||
records!.add(new Records.fromJson(v)); |
|||
}); |
|||
} |
|||
total = json['total']; |
|||
size = json['size']; |
|||
current = json['current']; |
|||
pages = json['pages']; |
|||
} |
|||
|
|||
Map<String, dynamic> toJson() { |
|||
final Map<String, dynamic> data = new Map<String, dynamic>(); |
|||
if (this.records != null) { |
|||
data['records'] = this.records!.map((v) => v.toJson()).toList(); |
|||
} |
|||
data['total'] = this.total; |
|||
data['size'] = this.size; |
|||
data['current'] = this.current; |
|||
data['pages'] = this.pages; |
|||
return data; |
|||
} |
|||
} |
|||
|
|||
class Records { |
|||
String? channelId; |
|||
String? nickName; |
|||
String? profilePhoto; |
|||
int? genderCode; |
|||
String? birthYear; |
|||
String? birthDate; |
|||
int? age; |
|||
int? provinceCode; |
|||
String? provinceName; |
|||
int? cityCode; |
|||
String? cityName; |
|||
|
|||
Records( |
|||
{this.channelId, |
|||
this.nickName, |
|||
this.profilePhoto, |
|||
this.genderCode, |
|||
this.birthYear, |
|||
this.birthDate, |
|||
this.age, |
|||
this.provinceCode, |
|||
this.provinceName, |
|||
this.cityCode, |
|||
this.cityName}); |
|||
|
|||
Records.fromJson(Map<String, dynamic> json) { |
|||
channelId = json['channelId']; |
|||
nickName = json['nickName']; |
|||
profilePhoto = json['profilePhoto']; |
|||
genderCode = json['genderCode']; |
|||
birthYear = json['birthYear']; |
|||
birthDate = json['birthDate']; |
|||
age = json['age']; |
|||
provinceCode = json['provinceCode']; |
|||
provinceName = json['provinceName']; |
|||
cityCode = json['cityCode']; |
|||
cityName = json['cityName']; |
|||
} |
|||
|
|||
Map<String, dynamic> toJson() { |
|||
final Map<String, dynamic> data = new Map<String, dynamic>(); |
|||
data['channelId'] = this.channelId; |
|||
data['nickName'] = this.nickName; |
|||
data['profilePhoto'] = this.profilePhoto; |
|||
data['genderCode'] = this.genderCode; |
|||
data['birthYear'] = this.birthYear; |
|||
data['birthDate'] = this.birthDate; |
|||
data['age'] = this.age; |
|||
data['provinceCode'] = this.provinceCode; |
|||
data['provinceName'] = this.provinceName; |
|||
data['cityCode'] = this.cityCode; |
|||
data['cityName'] = this.cityName; |
|||
return data; |
|||
} |
|||
} |
|||
@ -0,0 +1,153 @@ |
|||
import 'package:dating_touchme_app/components/page_appbar.dart'; |
|||
import 'package:dating_touchme_app/controller/home/home_controller.dart'; |
|||
import 'package:dating_touchme_app/pages/home/content_card.dart'; |
|||
import 'package:easy_refresh/easy_refresh.dart'; |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:get/get.dart'; |
|||
|
|||
class FriendFootprintPage extends StatefulWidget { |
|||
const FriendFootprintPage({super.key}); |
|||
|
|||
@override |
|||
State<FriendFootprintPage> createState() => _FriendFootprintPageState(); |
|||
} |
|||
|
|||
class _FriendFootprintPageState extends State<FriendFootprintPage> { |
|||
final HomeController controller = Get.find<HomeController>(); |
|||
late final EasyRefreshController _refreshController; |
|||
|
|||
final ScrollController _scrollController = ScrollController(); |
|||
|
|||
@override |
|||
void initState() { |
|||
super.initState(); |
|||
_refreshController = EasyRefreshController(controlFinishRefresh: true, controlFinishLoad: true); |
|||
controller.loadFriendFootInitialData(); |
|||
|
|||
} |
|||
|
|||
@override |
|||
void dispose() { |
|||
_refreshController.dispose(); |
|||
super.dispose(); |
|||
} |
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return Scaffold( |
|||
appBar: PageAppbar(title: "好友足迹"), |
|||
body: Obx(() { |
|||
if (controller.recommendIsLoading.value && controller.recommendFeed.isEmpty) { |
|||
return Center( |
|||
child: Column( |
|||
mainAxisAlignment: MainAxisAlignment.center, |
|||
children: [ |
|||
CircularProgressIndicator(), |
|||
SizedBox(height: 16), |
|||
Text('加载数据中...'), |
|||
], |
|||
), |
|||
); |
|||
} |
|||
return EasyRefresh( |
|||
controller: _refreshController, |
|||
header: const ClassicHeader( |
|||
dragText: '下拉刷新', |
|||
armedText: '释放刷新', |
|||
readyText: '刷新中...', |
|||
processingText: '刷新中...', |
|||
processedText: '刷新完成', |
|||
failedText: '刷新失败', |
|||
noMoreText: '没有更多数据', |
|||
showMessage: false |
|||
), |
|||
footer: ClassicFooter( |
|||
dragText: '上拉加载', |
|||
armedText: '释放加载', |
|||
readyText: '加载中...', |
|||
processingText: '加载中...', |
|||
processedText: '加载完成', |
|||
failedText: '加载失败', |
|||
noMoreText: '没有更多数据', |
|||
showMessage: false |
|||
), |
|||
// 下拉刷新 |
|||
onRefresh: () async { |
|||
print('推荐列表下拉刷新被触发'); |
|||
try { |
|||
await controller.refreshFriendData(); |
|||
print( '推荐列表刷新完成, hasMore: $controller.recommendHasMore.value'); |
|||
_refreshController.finishRefresh(); |
|||
_refreshController.resetFooter(); |
|||
} catch (e) { |
|||
print('推荐列表刷新失败: $e'); |
|||
_refreshController.finishRefresh(IndicatorResult.fail); |
|||
} |
|||
}, |
|||
// 上拉加载更多 |
|||
onLoad: () async { |
|||
print('推荐列表上拉加载被触发, hasMore: $controller.recommendHasMore.value'); |
|||
try { |
|||
await controller.loadFriendFootMoreData(); |
|||
// 完成加载,根据是否有更多数据决定 |
|||
if (controller.friendHasMore.value) { |
|||
_refreshController.finishLoad(IndicatorResult.success); |
|||
print('推荐列表加载更多成功'); |
|||
} else { |
|||
_refreshController.finishLoad(IndicatorResult.noMore); |
|||
print('推荐列表没有更多数据了'); |
|||
} |
|||
} catch (e) { |
|||
print('推荐列表加载更多失败: $e'); |
|||
_refreshController.finishLoad(IndicatorResult.fail); |
|||
} |
|||
}, |
|||
child: ListView.separated( |
|||
controller: _scrollController, |
|||
// 关键:始终允许滚动,即使内容不足 |
|||
// 移除顶部 padding,让刷新指示器可以正确显示在 AppBar 下方 |
|||
padding: EdgeInsets.only(left: 12, right: 12), |
|||
itemBuilder: (context, index) { |
|||
// 空数据状态 |
|||
if (controller.friendFootFeed.isEmpty && index == 0) { |
|||
// 使用足够的高度确保可以滚动 |
|||
if (controller.friendIsLoading.value) { |
|||
return Center( |
|||
child: Column( |
|||
mainAxisAlignment: MainAxisAlignment.center, |
|||
children: [ |
|||
CircularProgressIndicator(), |
|||
SizedBox(height: 16), |
|||
Text('加载数据中...'), |
|||
], |
|||
), |
|||
); |
|||
} else { |
|||
return Center( |
|||
child: Column( |
|||
mainAxisAlignment: MainAxisAlignment.center, |
|||
children: [ |
|||
Text('暂无数据'), |
|||
], |
|||
), |
|||
); |
|||
} |
|||
} |
|||
// 数据项 |
|||
final item = controller.friendFootFeed[index]; |
|||
return ContentCard(item: item, isFoot: true,); |
|||
}, |
|||
separatorBuilder: (context, index) { |
|||
// 空状态或加载状态时不显示分隔符 |
|||
if (controller.friendFootFeed.isEmpty) { |
|||
return const SizedBox.shrink(); |
|||
} |
|||
return const SizedBox(height: 12); |
|||
}, |
|||
// 至少显示一个 item(用于显示加载或空状态) |
|||
itemCount: controller.friendFootFeed.isEmpty ? 1 : controller.friendFootFeed.length, |
|||
) |
|||
); |
|||
}), |
|||
); |
|||
} |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save