import 'package:azlistview/azlistview.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart' as extended; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart' hide NestedScrollView; import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:sport/bean/login.dart'; import 'package:sport/bean/post_user.dart'; import 'package:sport/bean/user_friend.dart'; import 'package:sport/bean/user_info.dart'; import 'package:sport/pages/social/chat_page.dart'; import 'package:sport/pages/social/user_detail_page.dart'; import 'package:sport/pages/social/user_friend_add_page.dart'; import 'package:sport/provider/lib/provider_widget.dart'; import 'package:sport/provider/lib/view_state_lifecycle.dart'; import 'package:sport/provider/user_friend_model.dart'; import 'package:sport/router/navigator_util.dart'; import 'package:sport/utils/DateFormat.dart'; import 'package:sport/utils/toast.dart'; import 'package:sport/widgets/appbar.dart'; import 'package:sport/widgets/dialog/alert_dialog.dart'; import 'package:sport/widgets/dialog/request_dialog.dart'; import 'package:sport/widgets/error.dart'; import 'package:sport/widgets/image.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 UserFriendPage extends StatefulWidget { @override State createState() => _PageState(); } class _PageState extends State { PageController _controller; bool _refresh = false; int _page = 0; @override void initState() { super.initState(); } @override void dispose() { super.dispose(); _controller?.dispose(); } @override Widget build(BuildContext context) { final double tabHeader = 60; final double statusBarHeight = MediaQuery.of(context).padding.top; final double pinnedHeaderHeight = //statusBar height statusBarHeight + //pinned SliverAppBar height in header kToolbarHeight + tabHeader; return DefaultTabController( length: 3, child: Scaffold( backgroundColor: Colors.white, body: extended.NestedScrollView( pinnedHeaderSliverHeightBuilder: () { return pinnedHeaderHeight; }, innerScrollPositionKeyBuilder: () { TabController tabController = DefaultTabController.of(context); String index = 'Tab${tabController.index}'; return Key(index); }, headerSliverBuilder: (context, innerBoxIsScrolled) { return [ buildSliverAppBar(context, "好友列表", innerBoxIsScrolled: innerBoxIsScrolled, actions: [ IconButton( icon: Image.asset( "lib/assets/img/bbs_icon_addmore.png", width: 22.0, height: 22.0, ), // icon: Text( // "添加", // style: TextStyle(fontSize: 15, color: Theme.of(context).accentColor), // ), onPressed: () async { await NavigatorUtil.goPage( context, (context) => UserFriendAddPage()); setState(() { _refresh = true; }); await Future.delayed(Duration(seconds: 1)); setState(() { _refresh = false; }); }, ) ]), SliverPersistentHeader( delegate: PersistentHeader( min: tabHeader, max: tabHeader, child: Container( color: Colors.white, child: Column( children: [ Expanded( child: Center( child: Container( height: 35, child: TabBar( isScrollable: true, labelPadding: EdgeInsets.symmetric(horizontal: 32), indicatorWeight: 3, indicatorPadding: EdgeInsets.symmetric(horizontal: 6), tabs: [ Tab(text: '好友'), Tab(text: '我关注'), Tab(text: '关注我') ], onTap: (index) { _controller?.jumpToPage(index); }, ), ), ), ), ], ), )), pinned: true, ), ]; }, body: _refresh ? RequestLoadingWidget() : PageView.builder( controller: _controller = PageController(initialPage: _page) ..addListener(() { _page = _controller.page.toInt(); }), physics: NeverScrollableScrollPhysics(), itemCount: 3, itemBuilder: (_, index) => _PageDetailPage(index)), ), ), ); } } class _PageDetailPage extends StatefulWidget { final int type; _PageDetailPage(this.type); @override State createState() => _PageDetailState(type); } class _PageDetailState extends ViewStateLifecycle<_PageDetailPage, UserFriendModel> with ChangeNotifier { TextEditingController _controller; FocusNode _focusNode; ValueNotifier _searchValue = ValueNotifier(""); bool isSeach = false; _PageDetailState(int type); @override void initState() { super.initState(); _focusNode = FocusNode(); _controller = new TextEditingController(text: ''); // 监听 ... _controller.addListener(() { if (_controller.value.text != "") { if (widget.type == 0) { model.items = model.originItems .where( (element) => element.user.name.indexOf(_controller.text) > -1) .toList(); setState(() { isSeach = true; }); } else { model.list = model.originList .where((element) => element.name.indexOf(_controller.text) > -1) .toList(); } notifyListeners(); } else { if (widget.type == 0) { setState(() { isSeach = false; }); } model.items = model.originItems; model.list = model.originList; notifyListeners(); } }); } @override void dispose() { super.dispose(); _focusNode?.dispose(); _controller?.dispose(); } @override Widget build(BuildContext context) { return ProviderWidget( model: model, onModelReady: (model) => model.initData(), builder: (_, model, __) { return widget.type == 0 ? Column( children: [ _searchWidget(context), if (!isSeach) Space( height: 16.0, ), isSeach ? model.items.length > 0 ? Expanded( child: ListView.builder( padding: EdgeInsets.zero, itemBuilder: (context, index) => Column( children: [ ListTile( leading: InkWell( child: CircleAvatar( backgroundImage: userAvatarProvider(model.items[index].user.avatar), radius: 22, ), onTap: () { NavigatorUtil.goPage( context, (context) => UserDetailPage( PostUser.fromJson({ "id": "${model.items[index].user.uid}" }))); }, ), title: Text("${model.items[index].user.name}"), onTap: () { NavigatorUtil.goPage( context, (context) => ChatPage( UserInfo.fromJson(model .items[index].user .toJson()))); }, ), Divider() ], ), itemCount: model.items.length, ), ) : _searchNothings() : Expanded( child: AzListView( data: model.items, susItemHeight: 200, itemCount: model.items.length, indexBarData: model.tags.map((e) => "$e").toList(), itemBuilder: (BuildContext context, int index) { return ListTile( leading: InkWell( child: CircleAvatar( backgroundImage: userAvatarProvider(model.items[index].user.avatar), radius: 22, ), onTap: () { NavigatorUtil.goPage( context, (context) => UserDetailPage( PostUser.fromJson({ "id": "${model.items[index].user.uid}" }))); }, ), title: Text("${model.items[index].user.name}"), onTap: () { NavigatorUtil.goPage( context, (context) => ChatPage(UserInfo.fromJson( model.items[index].user.toJson()))); }, ); }, physics: BouncingScrollPhysics(), padding: EdgeInsets.zero, susItemBuilder: (BuildContext context, int index) { return Column( children: [ Container( // height: 40, width: MediaQuery.of(context).size.width, padding: EdgeInsets.only(left: 16.0), // color: Color(0xFFF3F4F5), alignment: Alignment.centerLeft, child: Text( '${model.items[index].getSuspensionTag()}', softWrap: false, style: TextStyle( fontSize: 14.0, color: Color(0xff9999999), ), ), ), Divider( indent: 12.0, endIndent: 12.0, ), ], ); }, indexBarOptions: IndexBarOptions( needRebuild: true, ignoreDragCancel: true, textStyle: TextStyle( color: Color(0xff999999), fontSize: 12.0), selectTextStyle: TextStyle( fontSize: 20, color: Theme.of(context).accentColor), // downTextStyle: TextStyle(fontSize: 12, color: Theme.of(context).accentColor), // selectItemDecoration: BoxDecoration(color: Colors.green), // downItemDecoration: // BoxDecoration(color: Colors.green), indexHintWidth: 33, indexHintHeight: 33, indexHintDecoration: BoxDecoration( image: DecorationImage( image: AssetImage( "lib/assets/img/friendlist_bg_letter.png"), fit: BoxFit.contain, ), ), indexHintTextStyle: TextStyle( fontSize: 18.0, color: Colors.white), indexHintAlignment: Alignment.centerRight, indexHintChildAlignment: Alignment(-0.25, 0.0), indexHintOffset: Offset(0, 0), ), ), ), ], ) : EasyRefresh.custom( firstRefresh: false, onRefresh: () => model.refresh(), onLoad: () => model.loadMore(), enableControlFinishRefresh: true, controller: model.refreshController, header: buildClassicalHeader(), footer: buildClassicalFooter(), slivers: [ SliverToBoxAdapter( child: _searchWidget(context), ), if (model.isBusy) SliverToBoxAdapter( child: RequestLoadingWidget(), ), if (model.list.length > 0) SliverList( delegate: SliverChildBuilderDelegate( (context, index) { return _buildItem(model.list[index]); }, childCount: model.list.length, ), ), if (model.list.length <= 0) SliverToBoxAdapter( child: _searchNothings(), ), if (model.isError) SliverToBoxAdapter( child: RequestErrorWidget( () { model.initData(); }, msg: widget.type == 0 ? "暂无好友~" : widget.type == 1 ? "暂无关注~" : "暂无关注我的~", assets: "emptypage-image-nomotion.png", ), ), ], ); }); } Widget _buildItem(UserFriend user) { var _padding = EdgeInsets.symmetric(horizontal: 4.0); Widget child; if (widget.type == 2) { child = Row( children: [ CircleAvatar( backgroundImage: userAvatarProvider(user?.socialInfo?.avatar), radius: 22, ), SizedBox( width: 8, ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "${user?.socialInfo?.name}", style: Theme.of(context) .textTheme .headline3 .copyWith(fontWeight: FontWeight.normal), ), SizedBox( height: 5, ), RichText( text: TextSpan( style: Theme.of(context).textTheme.subtitle2, children: [ TextSpan( text: '${DateFormat.formatCreateAt(user?.createdAt)}', style: Theme.of(context).textTheme.bodyText1, ), user.makeFrom == 'follow' ? TextSpan( text: '通过线上', style: Theme.of(context) .textTheme .bodyText1 .copyWith( color: Theme.of(context).accentColor), ) : TextSpan( text: '通过扫码', style: Theme.of(context) .textTheme .bodyText1 .copyWith( color: Theme.of(context).accentColor), ), TextSpan( text: "关注了你", style: Theme.of(context).textTheme.bodyText1, ) ]), ), // TextSpan( // "${DateFormat.formatCreateAt(user?.createdAt)}通过${user.makeFrom}关注了你", // // ), ], ), ), // if (user?.isFriends == "0") // user?.isIgnore == 0 // ? GestureDetector( // child: Container( // width: 64, // height: 30, // alignment: Alignment.center, // margin: _padding, // child: Text( // "关注", // strutStyle: fixedLine, // style: Theme.of(context).textTheme.bodyText2, // ), // decoration: BoxDecoration( // borderRadius: BorderRadius.circular(20), // border: Border.all( // color: Color(0xff999999), // width: .5, // ), // ), // ), // onTap: () async { // await request(context, () async { // var resp = await model.api // .userIgnoreFollow(uid: user?.socialInfo?.id) // .catchError((onError) {}); // if (resp?.code == 0) { // setState(() { // user.isIgnore = 1; // }); // } // }); // }, // ) // : Container( // width: 64, // height: 30, // margin: _padding, // alignment: Alignment.center, // child: Text( // "已忽略", // strutStyle: fixedLine, // style: Theme.of(context).textTheme.bodyText2, // ), // ), if (user?.isIgnore == 0) user.isFriends == "1" ? Container( width: 64, height: 30, // margin: _padding, alignment: Alignment.center, child: Text("已关注", strutStyle: fixedLine, style: Theme.of(context).textTheme.bodyText2), ) : GestureDetector( child: Container( width: 64, height: 30, margin: _padding, alignment: Alignment.center, child: Text( "关注", strutStyle: fixedLine, style: Theme.of(context) .textTheme .bodyText2 .copyWith(color: Theme.of(context).accentColor), ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), border: Border.all( color: Theme.of(context).accentColor, width: .5, ), ), ), onTap: () async { if (user.isFriends == "1") return; await request(context, () async { var resp = await model.api .userFollow(uid: user?.socialInfo?.id) .catchError((onError) {}); if (resp?.code == 0) { ToastUtil.show("关注成功"); setState(() { user.isFriends = "1"; }); } }); }, ) ], ); } else if (widget.type == 1) { child = Row( children: [ CircleAvatar( backgroundImage: userAvatarProvider(user?.socialInfo?.avatar), radius: 22, ), SizedBox( width: 8, ), Expanded( child: Text( "${user?.socialInfo?.name}", style: Theme.of(context) .textTheme .headline3 .copyWith(fontWeight: FontWeight.normal), ), ), GestureDetector( child: user.isFriends == "1" ? Row( children: [ Text("互关好友", style: TextStyle( fontSize: 14.0, color: Color(0xff999999))) ], ) : user.isFriends == "0" ? Text("已关注", style: TextStyle(fontSize: 14.0, color: Color(0xff999999))) : Container( width: 64, height: 30, margin: _padding, alignment: Alignment.center, child: Text( "关注", strutStyle: fixedLine, style: Theme.of(context) .textTheme .bodyText2 .copyWith(color: Theme.of(context).accentColor), ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), border: Border.all( color: Theme.of(context).accentColor, width: .5, ), ), ), // Container( // width: 82, // height: 30, // alignment: Alignment.center, // child: // decoration: BoxDecoration( // borderRadius: BorderRadius.circular(20), // border: Border.all( // color: Color(0xffDCDCDC), // width: .5, // ), // ), // ), onTap: () async { bool flag; if (user.isFriends == "1") { flag = await showDialog( context: context, builder: (context) => CustomAlertDialog( title: '是否取消关注,解除好友关系', ok: () { Navigator.of(context).pop(true); }, )); } else if (user.isFriends == "0") { flag = true; } if (flag == true) { await request(context, () async { var resp = await model.api .userUnFollow(uid: user?.socialInfo?.id) .catchError((onError) {}); setState(() { user.isFriends = "2"; // text = "233"; }); // if (resp?.code == 0) { // ToastUtil.show("取关成功"); // setState(() { // model.list?.remove(user); // if (model.list?.isEmpty == true) { // model.initData(); // } // }); // } }); } else if (flag == null) { await request(context, () async { var resp = await model.api .userFollow(uid: user?.socialInfo?.id) .catchError((onError) {}); if (resp?.code == 0) { ToastUtil.show("关注成功"); setState(() { user.isFriends = "0"; }); } }); } }, ) ], ); } else if (widget.type == 4) { // child = ListView.separated(itemBuilder: ()=>, itemCount: ); } // return Column( // children: [ // Padding( // padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 12.0), // child: InkWell( // onTap: () async { //// if(widget.type == 0) await NavigatorUtil.goPage(context, (context) => ChatPage(user?.socialInfo)); //// else // await NavigatorUtil.goPage( // context, // (context) => UserDetailPage( // PostUser( // id: "${user?.socialInfo?.id}", // name: user?.socialInfo?.name, // avatar: user?.socialInfo?.avatar), // userFriends: model.list)); // setState(() {}); // }, // child: child), // ), // Divider( // indent: 12.0, // height: 1, // endIndent: 12.0, // ) // ], // ); return Column( children: [ Padding( padding: const EdgeInsets.all(12.0), child: InkWell( onTap: () async { await NavigatorUtil.goPage( context, (context) => UserDetailPage( PostUser( id: "${user?.socialInfo?.id}", name: user?.socialInfo?.name, avatar: user?.socialInfo?.avatar), userFriends: model.list)); setState(() {}); }, child: child), ), Divider( height: 1, ) ], ); } Widget _searchWidget(BuildContext context) { return Container( margin: EdgeInsets.fromLTRB(12.0, 0, 12.0, 0), height: 35, // padding: EdgeInsets.symmetric(horizontal: 12.0), // padding: EdgeInsets.fromLTRB(12.0, 0, 12.0, 0), decoration: BoxDecoration( color: Color(0xffF1F1F1), shape: BoxShape.rectangle, borderRadius: BorderRadius.all(Radius.circular(50)), ), child: Row( children: [ SizedBox( width: 12.0, ), Image.asset("lib/assets/img/searchbar_icon_search.png"), SizedBox( width: 6, ), Expanded( child: TextField( controller: _controller, maxLines: 1, focusNode: _focusNode, strutStyle: StrutStyle(forceStrutHeight: true), decoration: InputDecoration( hintText: '输入账号/用户昵称', border: InputBorder.none, contentPadding: EdgeInsets.symmetric( vertical: 11.5, ), hintStyle: TextStyle( color: Color(0xff999999), ), ), onChanged: (value) { _searchValue.value = value; setState(() {}); }, onSubmitted: (value) { model.submitValue(value); // _searchModel.setKeyword(value); // Provider.of(context, listen: false).queryValue(value); }, style: TextStyle( color: Color(0xff333333), ), ), ), Visibility( visible: _searchValue.value?.isNotEmpty == true, child: GestureDetector( onTap: () { model.submitValue(null); _controller.clear(); }, child: Padding( padding: const EdgeInsets.all(8.0), child: Image.asset("lib/assets/img/searchbar_btn_no.png"), ), )) ], ), ); } Widget _searchNothings() { return Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.fromLTRB(0, 50, 0, 0), child: Image.asset("lib/assets/img/emptypage-image-nonetwork.png"), ), Padding( padding: const EdgeInsets.fromLTRB(0, 12, 0, 12), child: Text( "搜索无果", style: Theme.of(context).textTheme.bodyText2, ), ), SizedBox( height: 100, ) ], ); } @override UserFriendModel createModel() => UserFriendModel(widget.type); }