import 'dart:ui'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:sport/bean/forum.dart'; import 'package:sport/bean/post.dart'; import 'package:sport/pages/social/post_detail_page.dart'; import 'package:sport/pages/social/post_page.dart'; import 'package:sport/pages/social/post_widget.dart'; import 'package:sport/pages/social/search_page.dart'; import 'package:sport/provider/lib/provider_widget.dart'; import 'package:sport/provider/lib/view_state_lifecycle.dart'; import 'package:sport/provider/social_detail_model.dart'; import 'package:sport/router/navigator_util.dart'; import 'package:sport/services/api/resp.dart'; import 'package:sport/services/userid.dart'; import 'package:sport/widgets/appbar.dart'; import 'package:sport/widgets/error.dart'; import 'package:sport/widgets/loading.dart'; import 'package:sport/widgets/misc.dart'; import 'package:sport/widgets/persistent_header.dart'; import 'package:sport/widgets/space.dart'; class SocialDetailPage extends StatefulWidget { final Forum forum; final int index; SocialDetailPage(this.forum, {this.index = 0}); @override State createState() => _PageState(); } class _PageState extends ViewStateLifecycle with TickerProviderStateMixin, UserId { late ScrollController _controller; late TabController _tabController; double _expandedHeight = 0; int _brightness = 0; final List _tabs = ['热门', '关注', '最新', '精华', '我的']; Future>? _getPostListByOfficial; @override SocialDetailModel createModel() => SocialDetailModel.forum(widget.index, widget.forum.forumId); @override void initState() { super.initState(); _getPostListByOfficial = model.api.getPostListByOfficial(forumId: widget.forum.forumId, limit: 3); _tabController = TabController(length: _tabs.length, initialIndex: widget.index, vsync: this) ..addListener(() { if (_tabController.index.toDouble() == _tabController.animation?.value) { model.swtichTab(_tabController.index); _controller.animateTo(0, duration: Duration(milliseconds: 100), curve: Curves.ease); } }); _controller = ScrollController() ..addListener(() { if (_controller.position.pixels >= _expandedHeight - 35) { if (_brightness == 0) { setState(() { _brightness = 1; }); } } else { if (_brightness == 1) { setState(() { _brightness = 0; }); } } }); } @override void dispose() { super.dispose(); _controller.dispose(); _tabController.dispose(); PaintingBinding.instance?.imageCache?.clear(); } Widget _buildHeaderWidget() { return Stack( fit: StackFit.expand, children: [ Positioned( left: MediaQuery.of(context).size.width / 2, bottom: 0, top: 0, right: -MediaQuery.of(context).size.width / 2, child: ImageFiltered(imageFilter: ImageFilter.blur(sigmaX: 200.0, sigmaY: 50.0), child: CachedNetworkImage( imageUrl: "${widget.forum.cover}", fit: BoxFit.cover, width: double.infinity, height: MediaQuery.of(context).size.width * 154.0 / 375 + MediaQuery.of(context).padding.top, ),), ), Align( alignment: Alignment.center, child: Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.fromLTRB(12.0, 50, 12.0, 0), child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ CircleAvatar( radius: 24, backgroundColor: Colors.white, child: CircleAvatar( radius: 21, backgroundImage: CachedNetworkImageProvider("${widget.forum.cover}"), ) ), Space( width: 12, ), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "${widget.forum.name}", style: Theme.of(context).textTheme.headline1, ), Space( width: 40, ), Padding( padding: const EdgeInsets.only(top: 4.0), child: Row( mainAxisSize: MainAxisSize.min, children: [ Image.asset("lib/assets/img/tab_bbs_normal.png", height: 14.0,), Padding( padding: const EdgeInsets.only(left: 5.0), child: Text( "${widget.forum.subjectCount}", style: Theme.of(context).textTheme.bodyText1!, ), ), ],), ), // Row( // children: [ // Image.asset("lib/assets/img/bbs_icon_reportnumber.png"), // Space( // width: 4, // ), // Text( // "帖子数:${widget.forum.subjectCount}", // style: Theme.of(context).textTheme.subtitle2!.copyWith(color: Colors.white), // ), // ], // ), ], ), ], ), ), ], ), ), Positioned( left: 0, right: 0, bottom: -1, child: Container( height: 10, decoration: BoxDecoration(borderRadius: BorderRadius.vertical(top: Radius.circular(10)), color: Colors.white), ), ), ]); } Color getColor(String? tag) { if (tag == "榜单" || tag == "公告") return Theme.of(context).accentColor; else if (tag == "置顶") { return const Color(0xff5498FF); } return const Color(0xff00DC42); } Widget _buildHeaderListWidget() { return Container( decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(10))), child: FutureBuilder>( future: _getPostListByOfficial, builder: (BuildContext context, AsyncSnapshot> snapshot) { if (snapshot.connectionState == ConnectionState.done && snapshot.data?.pageResult?.results?.isNotEmpty == true) { return Column(children: [ Space( height: 5, ), Column( children: (snapshot.data?.pageResult.results ?? []) .map((e) => InkWell( onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) { return PostDetailPage(e, false, snapshot.data?.pageResult?.results ?? []); })); }, child: Row( children: [ Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(2)), border: Border.all( color: getColor(e.tags?.first), width: .5, )), padding: EdgeInsets.symmetric(horizontal: 2), margin: EdgeInsets.fromLTRB(12.0, 5, 6, 5), child: Text( "${e.tags?.first}", strutStyle: fixedLine, style: Theme.of(context).textTheme.subtitle2!.copyWith(color: getColor(e.tags?.first)), )), Expanded( child: Text("${e.title?.isNotEmpty == true ? e.title : e.content}", maxLines: 1, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.subtitle1!), ) ], ))) .toList(), ), Space( height: 5, ), Divider() ]); } return Container(); }, ), ); } @override Widget build(BuildContext context) { _expandedHeight = MediaQuery.of(context).size.width * 154.0 / 375; return Scaffold( backgroundColor: Colors.white, body: Stack( children: [ ProviderWidget( model: model, onModelReady: (model) => model.initData(), builder: (_, model, __) { return EasyRefresh.builder( controller: model.refreshController, enableControlFinishRefresh: true, enableControlFinishLoad: true, onRefresh: () => model.refresh(), onLoad: model.isIdle ? () => model.loadMore() : null, header: buildClassicalHeader(), footer: buildClassicalFooter(), builder: (context, physics, header, footer) { return CustomScrollView( controller: _controller, physics: physics, slivers: [ SliverAppBar( expandedHeight: _expandedHeight, pinned: true, elevation: 0, iconTheme: IconThemeData(color: Colors.black), brightness: _brightness == 0 ? Brightness.dark : Brightness.light, title: _brightness == 0 ? Text("") : Text( "${widget.forum.name}", style: titleStyle, ), backgroundColor: Colors.white, flexibleSpace: FlexibleSpaceBar( collapseMode: CollapseMode.pin, background: _buildHeaderWidget(), ), leading: IconButton( icon: Image.asset("lib/assets/img/topbar_return.png"), onPressed: () { Navigator.of(context).pop(); }, ), actions: [ IconButton(onPressed: ()=>Navigator.push(context, new MaterialPageRoute(builder: (context) => SearchPage())), icon: Icon(Icons.search)) ], ), if(header != null)header, SliverToBoxAdapter( child: _buildHeaderListWidget(), ), SliverPersistentHeader( delegate: PersistentHeader( min: 34, max: 34, child: Container( color: Colors.white, padding: EdgeInsets.only(bottom: 5), child: TabBar( isScrollable: true, indicatorPadding: EdgeInsets.symmetric(horizontal: 8), indicatorWeight: 3, controller: _tabController, tabs: _tabs.map((e) => Tab(text: e)).toList(), ), )), pinned: true, ), if (model.isBusy) SliverToBoxAdapter( child: RequestLoadingWidget(), ), if (model.isEmpty) SliverFillRemaining( child: Center( child: RequestErrorWidget( null, msg: "暂无帖子~", assets: RequestErrorWidget.ASSETS_NO_INVITATION, ), ), ), if (model.isIdle) SliverList( delegate: SliverChildBuilderDelegate( (context, index) { Post post = model.list[index]; return PostWidget(post, model, selfId == post.userId); }, childCount: model.list.length, ), ), if (model.isIdle && model.list.isNotEmpty) SliverToBoxAdapter( child: Center( child: Padding( padding: const EdgeInsets.all(32.0), child: Text("没有更多数据了"), )), ), ], ); }); }, ), Positioned( right: 12.0, bottom: 12.0, child: GestureDetector( onTap: () async { var result = await NavigatorUtil.goPage( context, (context) => PostPage( widget.forum.forumId!, forum: widget.forum, )); if(result == true) { try { int index = _tabController.index.toInt(); if (_tabs[index] == "最新") { model.refresh(); } else { _tabController.animateTo(_tabs.indexOf("最新"), duration: Duration(milliseconds: 100), curve: Curves.ease); _controller.animateTo(0, duration: Duration(milliseconds: 100), curve: Curves.ease); } } catch (e) { print(e); } } }, child: Image.asset("lib/assets/img/bbs_icon_edit.png"))) ], )); } }