together_mobile/lib/screens/contact/contact_screen.dart

325 lines
11 KiB
Dart

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 '/common/constants.dart';
import '/models/apply_list_model.dart';
import '/models/contact_model.dart';
import '/models/user_model.dart';
import '/request/server.dart';
import '/screens/contact/components/friend_group.dart';
import '/screens/contact/components/friend_tile.dart';
import '/screens/contact/components/group_chat_tile.dart';
class ContactScreen extends StatefulWidget with GetItStatefulWidgetMixin {
ContactScreen({super.key});
@override
State<ContactScreen> createState() => _ContactScreenState();
}
class _ContactScreenState extends State<ContactScreen> with GetItStateMixin {
final Map<String, bool> _shows = {
'friendGroups': true,
'allFriends': false,
'groupChats': false
};
@override
Widget build(BuildContext context) {
// Seems like `watchOnly` cannot watch collecion type.
int friendCount = watchOnly(
(Contact contact) => contact.friendCount,
);
int applyCount = watchOnly(
(ApplyList applyList) => applyList.count,
);
int groupChatCount = watchOnly(
(Contact contact) => contact.groupChatCount,
);
// 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<String>('bottom-sliver-list');
return Scaffold(
appBar: AppBar(
leading: Container(
margin: const EdgeInsets.only(left: 8),
child: CircleAvatar(
backgroundImage: CachedNetworkImageProvider(
'$userAvatarsUrl/${get<UserProfile>().avatar}',
),
),
),
title: const Text('通讯录'),
centerTitle: true,
actions: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.search),
splashRadius: 20,
),
IconButton(
onPressed: () {
context.pushNamed('SearchNewContact');
},
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(
[
// apply list
TextButton(
onPressed: () async {
context.pushNamed('ApplyList');
},
style: TextButton.styleFrom(
iconColor: Theme.of(context).textTheme.bodyLarge?.color,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
badges.Badge(
showBadge: applyCount > 0,
badgeStyle: const badges.BadgeStyle(
badgeColor: kErrorColor,
elevation: 12,
),
badgeContent: Text(
applyCount.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.pushNamed<int>('ManageGroup');
},
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']!) {
String groupName = get<Contact>().friendGroups[index];
return FriendGroup(
key: ValueKey(groupName),
groupName: groupName,
);
} else if (_shows['allFriends']!) {
String friendId =
get<Contact>().friends.keys.toList()[index];
// print(friends);
return FriendTile(
key: ValueKey(
friendId,
),
friendId: friendId,
);
} else {
String groupChatId =
get<Contact>().groupChats.keys.toList()[index];
return GroupChatTile(
key: ValueKey(groupChatId),
groupChatId: groupChatId,
);
}
},
childCount: _shows['friendGroups']!
? get<Contact>().friendGroups.length
: _shows['allFriends']!
? friendCount
: groupChatCount,
),
),
],
),
),
);
}
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<String, bool> 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;
}
}