import 'dart:async'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/skeleton/video_reply.dart'; import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/pages/dynamics/deatil/index.dart'; import 'package:pilipala/pages/dynamics/widgets/author_panel.dart'; import 'package:pilipala/pages/video/detail/reply/widgets/reply_item.dart'; import '../widgets/dynamic_panel.dart'; class DynamicDetailPage extends StatefulWidget { // const DynamicDetailPage({super.key}); const DynamicDetailPage({Key? key}) : super(key: key); @override State createState() => _DynamicDetailPageState(); } class _DynamicDetailPageState extends State { late DynamicDetailController? _dynamicDetailController; Future? _futureBuilderFuture; late StreamController titleStreamC; // appBar title final ScrollController scrollController = ScrollController(); bool _visibleTitle = false; String? action; @override void initState() { super.initState(); int oid = 0; int type = 0; if (Get.arguments['floor'] == 1) { oid = int.parse(Get.arguments['item'].basic!['comment_id_str']); type = Get.arguments['item'].basic!['comment_type']; } else { oid = Get.arguments['item'].modules.moduleDynamic.major.draw.id; type = 11; } action = Get.arguments.containsKey('action') ? Get.arguments['action'] : null; _dynamicDetailController = Get.put(DynamicDetailController(oid, type)); _futureBuilderFuture = _dynamicDetailController!.queryReplyList(); titleStreamC = StreamController(); scrollController.addListener(_listen); if (action == 'comment') { _visibleTitle = true; titleStreamC.add(true); } } void _listen() async { if (scrollController.position.pixels >= scrollController.position.maxScrollExtent - 300) { if (!_dynamicDetailController!.isLoadingMore) { _dynamicDetailController!.isLoadingMore = true; await _dynamicDetailController!.queryReplyList(reqType: 'onLoad'); } } if (scrollController.offset > 55 && !_visibleTitle) { _visibleTitle = true; titleStreamC.add(true); } else if (scrollController.offset <= 55 && _visibleTitle) { _visibleTitle = false; titleStreamC.add(false); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( elevation: 0, scrolledUnderElevation: 0, centerTitle: false, titleSpacing: 0, title: StreamBuilder( stream: titleStreamC.stream, initialData: false, builder: (context, AsyncSnapshot snapshot) { return AnimatedOpacity( opacity: snapshot.data ? 1 : 0, duration: const Duration(milliseconds: 300), child: author(_dynamicDetailController!.item, context), ); }, ), // actions: _detailModel != null ? appBarAction() : [], ), body: RefreshIndicator( onRefresh: () async { await _dynamicDetailController!.queryReplyList(); }, child: CustomScrollView( controller: scrollController, slivers: [ if (action != 'comment') SliverToBoxAdapter( child: DynamicPanel( item: _dynamicDetailController!.item, source: 'detail', ), ), SliverPersistentHeader( delegate: _MySliverPersistentHeaderDelegate( child: Container( decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, border: Border( top: BorderSide( width: 0.6, color: Theme.of(context).dividerColor.withOpacity(0.05), ), ), ), height: 45, padding: const EdgeInsets.only(left: 15, right: 12), child: Row( children: [ Obx( () => AnimatedSwitcher( duration: const Duration(milliseconds: 400), transitionBuilder: (Widget child, Animation animation) { return ScaleTransition( scale: animation, child: child); }, child: Text( '${_dynamicDetailController!.acount.value}', key: ValueKey( _dynamicDetailController!.acount.value), ), ), ), const Text('条回复'), const Spacer(), // TextButton.icon( // onPressed: () {}, // icon: const Icon( // Icons.subject_rounded, // size: 15, // ), // style: TextButton.styleFrom( // padding: const EdgeInsets.fromLTRB(12, 0, 12, 0), // foregroundColor: // Theme.of(context).colorScheme.outline, // ), // label: Text( // '按时间', // style: TextStyle( // fontSize: Theme.of(context) // .textTheme // .titleSmall! // .fontSize, // ), // ), // ), ], ), ), ), pinned: true, ), FutureBuilder( future: _futureBuilderFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { Map data = snapshot.data as Map; if (snapshot.data['status']) { // 请求成功 return Obx( () => SliverList( delegate: SliverChildBuilderDelegate( (context, index) { if (index == _dynamicDetailController!.replyList.length) { return Container( padding: EdgeInsets.only( bottom: MediaQuery.of(context).padding.bottom), height: MediaQuery.of(context).padding.bottom + 100, child: Center( child: Obx(() => Text( _dynamicDetailController!.noMore.value)), ), ); } else { return ReplyItem( replyItem: _dynamicDetailController! .replyList[index], showReplyRow: true, replyLevel: '1'); } }, childCount: _dynamicDetailController!.replyList.length + 1, ), ), ); } else { // 请求错误 return HttpError( errMsg: data['msg'], fn: () => setState(() {}), ); } } else { // 骨架屏 return SliverList( delegate: SliverChildBuilderDelegate((context, index) { return const VideoReplySkeleton(); }, childCount: 5), ); } }, ) ], ), ), ); } } class _MySliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate { final double _minExtent = 45; final double _maxExtent = 45; final Widget child; _MySliverPersistentHeaderDelegate({required this.child}); @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { //创建child子组件 //shrinkOffset:child偏移值minExtent~maxExtent //overlapsContent:SliverPersistentHeader覆盖其他子组件返回true,否则返回false return child; } //SliverPersistentHeader最大高度 @override double get maxExtent => _maxExtent; //SliverPersistentHeader最小高度 @override double get minExtent => _minExtent; @override bool shouldRebuild(covariant _MySliverPersistentHeaderDelegate oldDelegate) { return true; } }