import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:badges/badges.dart' as badges; import 'package:cached_network_image/cached_network_image.dart'; import 'package:get_it_mixin/get_it_mixin.dart'; import 'package:together_mobile/common/constants.dart'; import 'package:together_mobile/models/apply_list_model.dart'; import 'package:together_mobile/models/contact_model.dart'; import 'package:together_mobile/models/user_model.dart'; import 'package:together_mobile/request/server.dart'; import 'package:together_mobile/screens/contact/components/friend_group.dart'; import 'package:together_mobile/screens/contact/components/friend_tile.dart'; import 'package:together_mobile/screens/contact/components/group_chat_tile.dart'; class ContactScreen extends StatefulWidget with GetItStatefulWidgetMixin { ContactScreen({super.key}); @override State createState() => _ContactScreenState(); } class _ContactScreenState extends State with GetItStateMixin { final Map _shows = { 'friendGroups': true, 'allFriends': false, 'groupChats': false }; @override Widget build(BuildContext context) { Map friends = watchOnly( (Contact contact) => contact.friends, ); List friendGroups = watchOnly( (Contact contact) => contact.friendGroups, ); // Create a localkey, use to generate the custom scroll view, // or there will be a error: "Duplicate GlobalKey detected in widget tree." // But when I wrap custom scroll view into the RefrashIndicator, the key isn't needed any more // const Key customScrollKey = ValueKey('bottom-sliver-list'); return Scaffold( appBar: AppBar( leading: Container( margin: const EdgeInsets.only(left: 8), child: get().avatar.isEmpty ? const CircleAvatar( backgroundImage: AssetImage('assets/images/user_2.png'), ) : CircleAvatar( backgroundImage: CachedNetworkImageProvider( '$avatarsUrl/${get().avatar}', ), ), ), title: const Text('通讯录'), centerTitle: true, actions: [ IconButton( onPressed: () {}, icon: const Icon(Icons.search), splashRadius: 20, ), IconButton( onPressed: () { context.push('/contact/add'); }, icon: const Icon(Icons.person_add_alt_1), splashRadius: 20, ), ], ), body: RefreshIndicator( onRefresh: () async { await Future.delayed(const Duration(seconds: 2)); }, child: CustomScrollView( physics: const BouncingScrollPhysics(), // key: customScrollKey, slivers: [ SliverFixedExtentList( delegate: SliverChildListDelegate( [ TextButton( onPressed: () async { // await getApplicantInfo(get().applicantIds); context.push('/contact/apply_list'); }, style: TextButton.styleFrom( iconColor: Theme.of(context).textTheme.bodyLarge?.color, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ badges.Badge( showBadge: get().count > 0, badgeStyle: const badges.BadgeStyle( badgeColor: kErrorColor, elevation: 12, ), badgeContent: Text( get().count.toString(), style: TextStyle( fontSize: 11, color: Theme.of(context).colorScheme.inversePrimary, ), ), badgeAnimation: const badges.BadgeAnimation.scale(), position: badges.BadgePosition.topEnd(top: -12, end: -15), child: Text( '添加申请', style: TextStyle( fontSize: 16, color: Theme.of(context).textTheme.bodyLarge?.color, ), ), ), const Icon( Icons.keyboard_arrow_right, size: 30, ), ], ), ), TextButton( onPressed: () async { context.push('/contact/friend_group'); }, style: TextButton.styleFrom( iconColor: Theme.of(context).textTheme.bodyLarge?.color, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '分组管理', style: TextStyle( fontSize: 16, color: Theme.of(context).textTheme.bodyLarge?.color, ), ), const Icon( Icons.keyboard_arrow_right, size: 30, ), ], ), ), ], ), itemExtent: 50.0, ), SliverPersistentHeader( delegate: _MySliverPersistentHeader(_shows, _change, _refresh), pinned: true, ), SliverList( delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { if (_shows['friendGroups']!) { return FriendGroup( key: ValueKey(friendGroups[index]), groupName: friendGroups[index], ); } else if (_shows['allFriends']!) { return FriendTile( key: ValueKey( friends.keys.toList()[index], ), friendId: friends.keys.toList()[index], ); } else { return GroupChatTile(); } }, childCount: _shows['friendGroups']! ? get().friendGroups.length : _shows['allFriends']! ? get().friends.length : get().groupChats.length, ), ), ], ), ), ); } void _change(String which) { switch (which) { case 'friendGroups': setState(() { _shows['friendGroups'] = true; _shows['allFriends'] = false; _shows['groupChats'] = false; }); break; case 'allFriends': setState(() { _shows['friendGroups'] = false; _shows['allFriends'] = true; _shows['groupChats'] = false; }); break; case 'groupChats': setState(() { _shows['friendGroups'] = false; _shows['allFriends'] = false; _shows['groupChats'] = true; }); break; } } void _refresh() { setState(() {}); } } class _MySliverPersistentHeader extends SliverPersistentHeaderDelegate { const _MySliverPersistentHeader(this.shows, this.change, this.refresh); final Map shows; final Function(String) change; final VoidCallback refresh; @override double get minExtent => 50; @override double get maxExtent => 50; @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent, ) { return Container( height: 50, color: Theme.of(context).colorScheme.background, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ InkWell( onTap: () { change('friendGroups'); }, child: Container( margin: const EdgeInsets.only(left: 10), padding: const EdgeInsets.all(4), decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), color: shows['friendGroups']! ? kSecondaryColor.withOpacity(0.15) : Theme.of(context).brightness == Brightness.light ? null : Theme.of(context).colorScheme.background, ), child: const Text('分组'), ), ), InkWell( onTap: () { change('allFriends'); }, child: Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), color: shows['allFriends']! ? kSecondaryColor.withOpacity(0.15) : Theme.of(context).brightness == Brightness.light ? null : Theme.of(context).colorScheme.background, ), child: const Text('全部好友'), ), ), InkWell( onTap: () { change('groupChats'); }, child: Container( margin: const EdgeInsets.only(right: 10), padding: const EdgeInsets.all(4), decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), color: shows['groupChats']! ? kSecondaryColor.withOpacity(0.15) : Theme.of(context).brightness == Brightness.light ? null : Theme.of(context).colorScheme.background, ), child: const Text('群聊'), ), ), ], ), ); } @override bool shouldRebuild(covariant _MySliverPersistentHeader oldDelegate) { return true; } }