| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- import 'package:cached_network_image/cached_network_image.dart';
- import 'package:easy_refresh/easy_refresh.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:flutter_riverpod/flutter_riverpod.dart';
- import 'package:flutter_screenutil/flutter_screenutil.dart';
- import 'package:go_router/go_router.dart';
- import 'package:news_app/constant/size_res.dart';
- import 'package:news_app/ui/topic/topic_item_widget.dart';
- import 'package:news_app/widget/load_image.dart';
- import 'package:shimmer/shimmer.dart';
- import '../../constant/color_res.dart';
- import '../../constant/config.dart';
- import '../../gen/assets.gen.dart';
- import '../../model/topic_item_model.dart';
- import '../../provider/topic_list_provider.dart';
- import '../../provider/topic_provider.dart';
- import '../../widget/list_animation_layout.dart';
- import '../../widget/my_txt.dart';
- import '../search/search_bar_widget.dart';
- /// @author: bo.zeng
- /// @email: cnhbwds@gmail.com
- /// @date: 2025 2025/4/9 16:00
- /// @description:
- class MainTopicPage extends ConsumerStatefulWidget {
- const MainTopicPage({super.key});
- @override
- ConsumerState<MainTopicPage> createState() => _MainTopicPageState();
- }
- final topicProvider = NotifierProvider<TopicProvider, TopicData>(
- () => TopicProvider(),
- );
- final topicListProvider = NotifierProvider<TopicListProvider, TopicItemModel>(
- () => TopicListProvider(),
- );
- class _MainTopicPageState extends ConsumerState<MainTopicPage>
- with AutomaticKeepAliveClientMixin {
- int _page = 1;
- int _currentTotal = 0;
- @override
- void initState() {
- super.initState();
- ref.read(topicProvider.notifier).fetchTopicHot();
- ref.read(topicProvider.notifier).fetchRankHot();
- ref.read(topicListProvider.notifier).fetchList(page: _page, tid: "");
- eventBus.on<String>().listen((event) {
- if (event == "topicCall") {
- _page = 1;
- ref.read(topicListProvider.notifier).fetchList(page: _page, tid: "");
- }
- });
- }
- void longTapAction(String contentId) {}
- @override
- Widget build(BuildContext context) {
- super.build(context);
- final hotData = ref.watch(topicProvider.select((p) => p.topicHotList));
- final rankData = ref.watch(topicProvider.select((p) => p.topicRankList));
- final itemData = ref.watch(topicListProvider);
- ref.listen(topicListProvider.select((p) => p.records), (previous, next) {
- _currentTotal = next?.length ?? 0;
- });
- return Scaffold(
- appBar: AppBar(
- elevation: 0,
- // 移除阴影
- scrolledUnderElevation: 0,
- // 禁用滚动时的阴影变化
- backgroundColor: color5F59F7,
- centerTitle: true,
- title: Row(
- spacing: 10.w,
- children: [
- Image.asset(Assets.images.logo.path, width: 70.w),
- Expanded(child: SearchBarWidget(tabIndex: 3)),
- ],
- ),
- systemOverlayStyle: SystemUiOverlayStyle(
- statusBarColor: color5F59F7,
- statusBarIconBrightness: Brightness.light, // 状态栏图标颜色
- ),
- ),
- body: EasyRefresh.builder(
- onRefresh: () async {
- _page = 1;
- await Future.wait([
- ref.read(topicProvider.notifier).fetchTopicHot(),
- ref.read(topicProvider.notifier).fetchRankHot(),
- ref
- .read(topicListProvider.notifier)
- .fetchList(page: _page, tid: ""),
- ]);
- return IndicatorResult.success;
- },
- onLoad: () async {
- // 重新读取最新的 itemData
- final newItemData = ref.read(topicListProvider);
- int total = newItemData.total ?? 0;
- if (_currentTotal >= total) {
- return IndicatorResult.noMore;
- } else {
- _page += 1;
- await ref
- .read(topicListProvider.notifier)
- .fetchList(page: _page, tid: "");
- return IndicatorResult.success;
- }
- },
- childBuilder: (context, physics) {
- return Stack(
- children: [
- Positioned(
- child: Container(
- height: 100.h,
- decoration: BoxDecoration(
- gradient: LinearGradient(
- colors: [color5F59F7, color6592FD, Colors.white],
- begin: Alignment.topCenter,
- end: Alignment.bottomCenter,
- ),
- ),
- ),
- ),
- CustomScrollView(
- slivers: [
- if (hotData.isNotEmpty)
- SliverPadding(
- padding: EdgeInsets.symmetric(
- vertical: horizontalPadding,
- horizontal: horizontalPadding,
- ),
- sliver: SliverToBoxAdapter(
- child: Row(
- spacing: 5.w,
- children: [
- Icon(
- Icons.fire_hydrant_alt_rounded,
- size: 20,
- color: Colors.white,
- ),
- myTxt(
- text: "热门话题",
- color: Colors.white,
- fontWeight: FontWeight.bold,
- fontSize: 18.sp,
- ),
- ],
- ),
- ),
- ),
- SliverPadding(
- padding: EdgeInsets.symmetric(
- horizontal: horizontalPadding,
- ),
- sliver: SliverToBoxAdapter(
- child: Builder(
- builder: (context) {
- if (hotData.isNotEmpty) {
- return Row(
- spacing: horizontalPadding,
- children: List<Widget>.generate(hotData.length, (
- index,
- ) {
- return Expanded(
- child: Stack(
- alignment: Alignment.bottomLeft,
- children: [
- AspectRatio(
- aspectRatio: 16 / 9,
- child: ClipRRect(
- borderRadius: BorderRadius.circular(
- 8.r,
- ),
- child: CachedNetworkImage(
- fit: BoxFit.cover,
- imageUrl:
- hotData[index].image ?? "",
- ),
- ),
- ),
- Positioned(
- bottom: 5.h,
- left: 5.h,
- right: 5.h,
- child: myTxt(
- text: hotData[index].title ?? "",
- fontSize: 14.sp,
- color: Colors.white,
- maxLines: 2, // 限制文本的最大行数
- ),
- ),
- ],
- ),
- );
- }),
- );
- } else {
- return const SizedBox.shrink();
- }
- },
- ),
- ),
- ),
- SliverPadding(
- padding: EdgeInsets.symmetric(
- vertical: horizontalPadding,
- horizontal: horizontalPadding,
- ),
- sliver: SliverToBoxAdapter(
- child: Row(
- spacing: 5.w,
- children: [
- // Image.asset(Assets.images.fire.path, width: 13.w),
- LoadAssetImage('topic_fire', width: 13.w),
- myTxt(
- text: "精选话题",
- color: Colors.black,
- fontWeight: FontWeight.bold,
- fontSize: 18.sp,
- ),
- ],
- ),
- ),
- ),
- SliverToBoxAdapter(
- child: Container(
- margin: EdgeInsets.symmetric(
- horizontal: horizontalPadding,
- ),
- padding: EdgeInsets.all(8.w),
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(8.r),
- color: Colors.white,
- ),
- child: Builder(
- builder: (context) {
- return Column(
- spacing: 8.h,
- children: List<Widget>.generate(rankData.length, (
- index,
- ) {
- return GestureDetector(
- onTap: () {
- context.push(
- "/topic/list",
- extra: rankData[index].contentId,
- );
- },
- child: Row(
- spacing: 5.w,
- children: [
- SizedBox(width: 1.w),
- myTxt(
- text: "${index + 1}",
- fontWeight: FontWeight.w900,
- color:
- index <= 3
- ? Colors.red
- : Colors.black,
- fontSize: 15.sp,
- ),
- Flexible(
- child: myTxt(
- text: rankData[index].content ?? "",
- color: Colors.black,
- fontSize: 15.sp,
- maxLines: 1,
- ),
- ),
- ],
- ),
- );
- }),
- );
- },
- ),
- ),
- ),
- (itemData.records ?? []).isEmpty
- ? SliverList.separated(
- separatorBuilder: (context, index) {
- return Container(height: 10.h);
- },
- itemBuilder: (context, index) {
- return Shimmer.fromColors(
- baseColor: Color(0xffe5e5e5),
- highlightColor: Color(0xfff5f5f5),
- child: AnimationItem(),
- );
- },
- itemCount: 20,
- )
- : SliverList(
- delegate: SliverChildBuilderDelegate((context, index) {
- return GestureDetector(
- onTap: () {
- context.push(
- "/topic/detail",
- extra: itemData.records?[index].contentId,
- );
- },
- child: Padding(
- padding: EdgeInsets.only(
- left: horizontalPadding,
- right: horizontalPadding,
- top: horizontalPadding,
- ),
- child: TopicItemWidget(
- longTapAction,
- item: itemData.records?[index],
- ),
- ),
- );
- }, childCount: itemData.records?.length ?? 0),
- ),
- ],
- physics: physics,
- ),
- ],
- );
- },
- ),
- );
- }
- @override
- bool get wantKeepAlive => true;
- }
|