217 lines
6.8 KiB
Dart
217 lines
6.8 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||
import 'package:cached_network_image/cached_network_image.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
import 'package:new_learn/core/api/class/api.dart';
|
||
import 'package:new_learn/core/api/class/model.dart';
|
||
import 'package:new_learn/core/utils/img_url.dart';
|
||
import 'package:new_learn/features/class/widgets/post_list_body.dart';
|
||
|
||
/// ============================================================
|
||
/// 【MyInteractPage】「我的互动」页 —— 对标 Vue pages/classPackage/myInteract/myInteract.vue
|
||
///
|
||
/// 一、入口:从「我的」页等进入。
|
||
/// 二、结构:NavBar("我的互动") + 3 颗胶囊 tab + 内容区
|
||
/// 「我的动态 / 我的点赞 / 我的留言」
|
||
/// 三、子列表用通用 PostListBody:
|
||
/// 动态 getUserClassPost(queryType=0);点赞 getMyLikePage;留言 getMyCommentPage。
|
||
/// 点赞页取消点赞时从列表移除该项(removeOnUnlike);其余保留。
|
||
/// 四、懒加载:默认建第一个 tab,切到再建(对标 renderedTabs)。
|
||
/// ============================================================
|
||
class MyInteractPage extends StatefulWidget {
|
||
const MyInteractPage({super.key});
|
||
|
||
@override
|
||
State<MyInteractPage> createState() => _MyInteractPageState();
|
||
}
|
||
|
||
class _MyInteractPageState extends State<MyInteractPage> {
|
||
static const List<String> _tabs = ['我的动态', '我的点赞', '我的留言'];
|
||
|
||
int _currentTab = 0;
|
||
final List<bool> _loadedTabs = [true, false, false];
|
||
|
||
void _switchTab(int index) {
|
||
if (_currentTab == index) return;
|
||
setState(() {
|
||
_loadedTabs[index] = true;
|
||
_currentTab = index;
|
||
});
|
||
}
|
||
|
||
void _openDetail(UserPostDto post) {
|
||
context.push('/class/my-update-detail', extra: post);
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
backgroundColor: const Color(0xFFF5F8FA),
|
||
extendBodyBehindAppBar: true,
|
||
appBar: AppBar(
|
||
backgroundColor: Colors.transparent,
|
||
surfaceTintColor: Colors.transparent,
|
||
elevation: 0,
|
||
title: const Text(
|
||
'我的互动',
|
||
style: TextStyle(
|
||
fontSize: 18,
|
||
fontWeight: FontWeight.w400,
|
||
color: Color(0xFF1D2B47),
|
||
),
|
||
),
|
||
centerTitle: true,
|
||
leading: IconButton(
|
||
icon: const Icon(Icons.arrow_back, color: Color(0xFF1D2B47)),
|
||
onPressed: () =>
|
||
context.canPop() ? context.pop() : context.go('/class'),
|
||
),
|
||
),
|
||
// 对齐 Vue .activity-box:背景图 + #F5F8FA 底色
|
||
// background-image: url(/StaticResource/2026-04-07/myInteract-bg.png)
|
||
// background-size: 100% 540rpx → height: 270.h + BoxFit.fitWidth
|
||
body: Stack(
|
||
children: [
|
||
Positioned(
|
||
top: 0,
|
||
left: 0,
|
||
right: 0,
|
||
child: SizedBox(
|
||
height: 270.h, // Vue 540rpx
|
||
child: CachedNetworkImage(
|
||
imageUrl: ImgUrl.build(
|
||
'/StaticResource/2026-04-07/myInteract-bg.png',
|
||
),
|
||
fit: BoxFit.fitWidth,
|
||
placeholder: (_, __) => const SizedBox.shrink(),
|
||
errorWidget: (_, __, ___) => const SizedBox.shrink(),
|
||
),
|
||
),
|
||
),
|
||
// 内容区:顶 padding = 系统状态栏 + AppBar 高度,对齐 Vue NavBar 后的起点
|
||
Padding(
|
||
padding: EdgeInsets.only(
|
||
top: MediaQuery.of(context).padding.top + kToolbarHeight,
|
||
),
|
||
child: Column(
|
||
children: [
|
||
_buildTabs(),
|
||
Expanded(
|
||
child: IndexedStack(
|
||
index: _currentTab,
|
||
children: [
|
||
if (_loadedTabs[0]) _UpdateTab(onTapPost: _openDetail),
|
||
if (_loadedTabs[1]) _LikeTab(onTapPost: _openDetail),
|
||
if (_loadedTabs[2]) _CommentTab(onTapPost: _openDetail),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildTabs() {
|
||
return Container(
|
||
width: double.infinity,
|
||
padding: EdgeInsets.fromLTRB(14.w, 12.h, 14.w, 22.h),
|
||
child: Row(
|
||
children: [
|
||
for (int i = 0; i < _tabs.length; i++) ...[
|
||
if (i > 0) SizedBox(width: 12.w),
|
||
_buildTabItem(i),
|
||
],
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildTabItem(int index) {
|
||
final active = _currentTab == index;
|
||
return GestureDetector(
|
||
onTap: () => _switchTab(index),
|
||
child: Container(
|
||
width: 84.w,
|
||
height: 37.h,
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(
|
||
color: active ? const Color(0xFF3D7DF5) : Colors.white,
|
||
borderRadius: BorderRadius.circular(20.r),
|
||
),
|
||
child: Text(
|
||
_tabs[index],
|
||
style: TextStyle(
|
||
fontSize: 15,
|
||
color: active ? Colors.white : const Color(0xFF687FAD),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
class _UpdateTab extends StatelessWidget {
|
||
const _UpdateTab({required this.onTapPost});
|
||
final ValueChanged<UserPostDto> onTapPost;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return PostListBody(
|
||
fetchPage:
|
||
({required pageIndex, required pageSize, required prevPageId}) =>
|
||
ClassApi.instance.getUserClassPost(
|
||
queryType: 0,
|
||
pageIndex: pageIndex,
|
||
pageSize: pageSize,
|
||
prevPageId: prevPageId,
|
||
),
|
||
emptyText: '暂无动态',
|
||
onTapPost: onTapPost,
|
||
);
|
||
}
|
||
}
|
||
|
||
class _LikeTab extends StatelessWidget {
|
||
const _LikeTab({required this.onTapPost});
|
||
final ValueChanged<UserPostDto> onTapPost;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return PostListBody(
|
||
fetchPage:
|
||
({required pageIndex, required pageSize, required prevPageId}) =>
|
||
ClassApi.instance.getMyLikePage(
|
||
pageIndex: pageIndex,
|
||
pageSize: pageSize,
|
||
prevPageId: prevPageId,
|
||
),
|
||
emptyText: '暂无点赞',
|
||
removeOnUnlike: true,
|
||
onTapPost: onTapPost,
|
||
);
|
||
}
|
||
}
|
||
|
||
class _CommentTab extends StatelessWidget {
|
||
const _CommentTab({required this.onTapPost});
|
||
final ValueChanged<UserPostDto> onTapPost;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return PostListBody(
|
||
fetchPage:
|
||
({required pageIndex, required pageSize, required prevPageId}) =>
|
||
ClassApi.instance.getMyCommentPage(
|
||
pageIndex: pageIndex,
|
||
pageSize: pageSize,
|
||
prevPageId: prevPageId,
|
||
),
|
||
emptyText: '暂无留言',
|
||
onTapPost: onTapPost,
|
||
);
|
||
}
|
||
}
|