import 'package:cached_network_image/cached_network_image.dart'; import 'package:chat/chat/group_chat_view.dart'; import 'package:chat/data/UserData.dart'; import 'package:chat/data/constants.dart'; import 'package:chat/generated/i18n.dart'; import 'package:chat/models/group_info_model.dart'; import 'package:chat/models/group_list_provider.dart'; import 'package:chat/utils/CustomUI.dart'; import 'package:chat/utils/MessageMgr.dart'; import 'package:chat/utils/conversation_table.dart'; import 'package:chat/utils/friend_list_mgr.dart'; import 'package:chat/utils/group_member_model.dart'; import 'package:chat/utils/msgHandler.dart'; import 'package:chat/utils/screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:oktoast/oktoast.dart'; import 'package:provider/provider.dart'; Widget _createAvatar(avatar) { return ClipRRect( borderRadius: BorderRadius.circular(6), child: CachedNetworkImage( imageUrl: avatar, width: Constants.ContactAvatarSize, height: Constants.ContactAvatarSize, )); } class FriendSelectItem extends StatefulWidget { final FriendModel friendModel; final String groupTitle; final bool isShowDivder; final bool isSingle; final bool isSelected; FriendSelectItem( {this.friendModel, this.groupTitle, this.isShowDivder = true, this.isSelected = false, this.isSingle = false}); @override _FriendSelectItemState createState() => _FriendSelectItemState(); } class _FriendSelectItemState extends State { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { var selectProvider = Provider.of(context); bool isSelect = selectProvider.isSelect(widget.friendModel); // print('是否选择 ${widget.friendModel.name} $isSelect'); var _avatarIcon = _createAvatar(widget.friendModel.avatar); Widget _button = Container( padding: const EdgeInsets.symmetric( vertical: MARGIN_VERTICAL, horizontal: 16.0), decoration: BoxDecoration(color: Colors.white), child: Row( children: [ widget.isSelected ? Container( width: 20, height: 20, decoration: BoxDecoration( color: Colors.grey[400], shape: BoxShape.circle, border: Border.all( color: const Color(0xFF707070), width: 0.2)), child: Icon(Icons.check, size: 15, color: Colors.white), ) : (isSelect ? Container( width: 20, height: 20, decoration: BoxDecoration( color: const Color(0xFF2685FA), shape: BoxShape.circle, border: Border.all( color: const Color(0xFF707070), width: 0.2)), child: Icon(Icons.check, size: 15, color: Colors.white), ) : Container( width: 20, height: 20, decoration: BoxDecoration( color: Colors.white, shape: BoxShape.circle, border: Border.all(color: const Color(0xFF707070))), )), SizedBox(width: 10), _avatarIcon, SizedBox(width: 10.0), Expanded( child: Container( child: Text( widget.friendModel.getTitle(), overflow: TextOverflow.ellipsis, )), ) ], ), ); //分组标签 Widget _itemBody; if (widget.groupTitle != null) { _itemBody = Column( children: [ Container( height: GROUP_TITLE_HEIGHT, padding: EdgeInsets.only(left: 16.0, right: 16.0), color: const Color(AppColors.ContactGroupTitleBgColor), alignment: Alignment.centerLeft, child: Text(widget.groupTitle, style: AppStyles.GroupTitleItemTextStyle), ), _button, ], ); } else { _itemBody = _button; } return InkWell( onTap: widget.isSelected ? null : () { if (widget.isSingle) { selectProvider.curSelectFriendList.clear(); if (isSelect) { selectProvider.removeFriend(widget.friendModel); } else { selectProvider.addFriend(widget.friendModel); MessageMgr().emit('jump_top'); } } else { if (isSelect) { selectProvider.removeFriend(widget.friendModel); } else { selectProvider.addFriend(widget.friendModel); MessageMgr().emit('jump_top'); } } }, child: Container( color: Colors.white, child: Column( children: [ _itemBody, widget.isShowDivder ? Container( height: 1, color: const Color(0xFFF3F3F3), margin: EdgeInsets.only( left: 26 + Constants.ContactAvatarSize), ) : Container() ], ))); } } class CreateGroupPage extends StatefulWidget { final int pageType; final List originalList; final int groupId; CreateGroupPage(this.pageType, this.originalList, this.groupId); @override _CreateGroupPageState createState() => _CreateGroupPageState(); } class _CreateGroupPageState extends State { String _currentLetter = ''; ScrollController _scrollController; ScrollController _headScrollCtrl = ScrollController(); TextEditingController _txtCtrl = new TextEditingController(); bool _hasdeleteIcon = false; bool isSingle = false; bool isCreating = false; List friendList = []; List searchList = []; Set originalUserIdSet = new Set(); GroupSelectProvider _groupSelectProvider = GroupSelectProvider(); final Map _letterPosMap = {INDEX_BAR_WORDS[0]: 0.0}; double _groupHeight(bool hasGroupTitle) { final _buttonHeight = MARGIN_VERTICAL * 2 + Constants.ContactAvatarSize + Constants.DividerWidth; if (hasGroupTitle) { return _buttonHeight + GROUP_TITLE_HEIGHT; } else { return _buttonHeight; } } @override void initState() { super.initState(); print('CreateGroupPage initState'); getFriendList(); isSingle = widget.pageType == GroupOperatingPageType.SelectGroupOwner; MessageMgr().on('jump_top', animateToTop); } @override void dispose() { MessageMgr().off('jump_top', animateToTop); super.dispose(); } animateToTop(data) { // _scrollController.animateTo( // 0.0, // curve: Curves.easeOut, // duration: const Duration(milliseconds: 300), // ); _headScrollCtrl.jumpTo(0); } getFriendList() async { for (var item in widget.originalList) { originalUserIdSet.add(item.memberId); } if (widget.pageType == GroupOperatingPageType.AddMember || widget.pageType == GroupOperatingPageType.CreateGroup) { friendList = await FriendListMgr().getFriendList(); setState(() {}); } if (widget.pageType == GroupOperatingPageType.DeleteMember || widget.pageType == GroupOperatingPageType.SelectGroupOwner) { for (var item in widget.originalList) { if (item.memberId != UserData().basicInfo.userId) { FriendModel friend = new FriendModel( friendId: item.memberId, avatar: item.avtar, name: item.nickName, refName: item.refName); friendList.add(friend); } } setState(() {}); } } Widget _createSearch() { return Container( alignment: Alignment.center, height: 45, child: TextField( keyboardAppearance: Brightness.light, keyboardType: TextInputType.text, textInputAction: TextInputAction.search, controller: _txtCtrl, maxLines: 1, style: TextStyle(textBaseline: TextBaseline.alphabetic, fontSize: 14.5), autofocus: false, inputFormatters: [ LengthLimitingTextInputFormatter(50), ], decoration: InputDecoration( contentPadding: EdgeInsets.symmetric(vertical: 14), hintText: I18n.of(context).search, hintStyle: TextStyle(fontSize: 14.5), prefixIcon: Consumer( builder: (context, counter, child) => Icon( IconData( 0xe664, fontFamily: Constants.IconFontFamily, ), color: const Color(0xFFA0A0A0), size: 18, )), filled: true, fillColor: Colors.transparent, border: InputBorder.none, ), onChanged: (str) async { setState(() { if (str.isEmpty) { _hasdeleteIcon = false; } else { _hasdeleteIcon = true; searchList = CustomUI() .getSearchResult(str, friendList == null ? [] : friendList); } }); }, onEditingComplete: () {}), ); } updateIndexPos(List friendList) { //计算用于 IndexBar 进行定位的关键通讯录列表项的位置 double _totalPos = 0.0; for (var i = 0; i < friendList.length; i++) { bool _hasGroupTitle = true; if (i > 0 && friendList[i].nameTag.compareTo(friendList[i - 1].nameTag) == 0) { _hasGroupTitle = false; } if (_hasGroupTitle) { _letterPosMap[friendList[i].nameTag] = _totalPos; } _totalPos += _groupHeight(_hasGroupTitle); } } String getLetter(BuildContext context, double tileHeight, Offset globalPos) { RenderBox _box = context.findRenderObject(); var local = _box.globalToLocal(globalPos); int index = (local.dy ~/ tileHeight).clamp(0, INDEX_BAR_WORDS.length - 1); return INDEX_BAR_WORDS[index]; } void _jumpToIndex(String letter) { if (_letterPosMap.isNotEmpty) { final _pos = _letterPosMap[letter]; if (_pos != null) { _scrollController.animateTo(_letterPosMap[letter], curve: Curves.easeInOut, duration: Duration(microseconds: 200)); } } } Widget _buildIndexBar(BuildContext context, BoxConstraints constraints) { final List _letters = INDEX_BAR_WORDS.map((String word) { return Expanded( child: Container( margin: EdgeInsets.only(right: 5), decoration: BoxDecoration( shape: BoxShape.circle, color: _currentLetter == word ? Colors.blue : Colors.transparent, ), alignment: Alignment.center, padding: EdgeInsets.all(2), width: 20, child: Text( word, textScaleFactor: 1.0, style: TextStyle( fontSize: 10, color: _currentLetter == word ? Colors.white : Colors.black), ))); }).toList(); final _totalHeight = constraints.biggest.height; final _tileHeight = _totalHeight / _letters.length; return GestureDetector( onVerticalDragDown: (DragDownDetails details) { setState(() { _currentLetter = getLetter(context, _tileHeight, details.globalPosition); _jumpToIndex(_currentLetter); }); }, onVerticalDragEnd: (DragEndDetails details) { setState(() { //_indexBarBgColor = Colors.transparent; _currentLetter = null; }); }, onVerticalDragCancel: () { setState(() { //_indexBarBgColor = Colors.transparent; _currentLetter = null; }); }, onVerticalDragUpdate: (DragUpdateDetails details) { setState(() { //var _letter = getLetter(context, _tileHeight, details.globalPosition); _currentLetter = getLetter(context, _tileHeight, details.globalPosition); _jumpToIndex(_currentLetter); }); }, child: Column( children: _letters, ), ); } @override Widget build(BuildContext context) { if (friendList == null) { return Scaffold( appBar: AppBar( leading: CustomUI.buildCustomLeading(context), ), body: Center(child: CircularProgressIndicator())); } final List _body = []; if (!_hasdeleteIcon) { friendList.sort((a, b) => a.nameTag.compareTo(b.nameTag)); updateIndexPos(friendList); _body.addAll([ ListView.builder( controller: _scrollController, itemBuilder: (BuildContext context, int index) { bool _isGroupTitle = true; FriendModel _contact = friendList[index]; if (index >= 1 && _contact.nameTag == friendList[index - 1].nameTag) { _isGroupTitle = false; } return FriendSelectItem( friendModel: _contact, isShowDivder: _isGroupTitle, isSingle: isSingle, isSelected: originalUserIdSet.contains(_contact.friendId) && widget.pageType == GroupOperatingPageType.AddMember, groupTitle: _isGroupTitle ? _contact.nameTag : null); }, itemCount: friendList.length, ), Positioned( width: Constants.IndexBarWidth, right: 0.0, top: 0.0, bottom: 0.0, child: Container( child: LayoutBuilder( builder: _buildIndexBar, ), ), ) ]); } else { _body.add(ListView.builder( controller: _scrollController, itemBuilder: (BuildContext context, int index) { FriendModel _contact = searchList[index]; return FriendSelectItem( isSingle: isSingle, friendModel: _contact, isShowDivder: true, isSelected: originalUserIdSet.contains(_contact.friendId) && widget.pageType == GroupOperatingPageType.AddMember, groupTitle: null); }, itemCount: searchList.length, )); } if (_currentLetter != null && _currentLetter.isNotEmpty && !_hasdeleteIcon) { _body.add(Center( child: Container( width: Constants.IndexLetterBoxSize, height: Constants.IndexLetterBoxSize, decoration: BoxDecoration( color: AppColors.IndexLetterBoxBgColor, borderRadius: BorderRadius.all( Radius.circular(Constants.IndexLetterBoxRadius)), ), child: Center( child: Text(_currentLetter, style: AppStyles.IndexLetterBoxTextStyle), ), ), )); } String title = ''; switch (widget.pageType) { case GroupOperatingPageType.AddMember: case GroupOperatingPageType.CreateGroup: title = I18n.of(context).add_member; break; case GroupOperatingPageType.DeleteMember: title = I18n.of(context).delete_member; break; case GroupOperatingPageType.SelectGroupOwner: title = I18n.of(context).choose_group_owner; break; default: } return ChangeNotifierProvider( create: (_) => _groupSelectProvider, child: Scaffold( resizeToAvoidBottomPadding: false, appBar: AppBar( backgroundColor: AppColors.NewAppbarBgColor, title: Text( title, textScaleFactor: 1.0, style: TextStyle(color: AppColors.NewAppbarTextColor), ), centerTitle: true, leading: CustomUI.buildCustomLeading(context), elevation: 0, actions: [ InkWell( child: Padding( padding: EdgeInsets.only(right: 15, top: 14, bottom: 14), child: Consumer( builder: (context, counter, child) => Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(4.5), color: _groupSelectProvider .curSelectFriendList.length == 0 ? Colors.grey[350] : (widget.pageType == GroupOperatingPageType .DeleteMember ? Colors.red : const Color(0xFF3875E9)), ), padding: EdgeInsets.symmetric(horizontal: 18), alignment: Alignment.center, child: fixedText( (widget.pageType == GroupOperatingPageType .DeleteMember ? I18n.of(context).delete : I18n.of(context).determine) + "(${_groupSelectProvider.curSelectFriendList.length})", color: Colors.white, fontSize: 12.67), ))), onTap: () async { if (_groupSelectProvider.curSelectFriendList.length == 0) return; switch (widget.pageType) { case GroupOperatingPageType.CreateGroup: createGroup(); break; case GroupOperatingPageType.AddMember: addMember(); break; case GroupOperatingPageType.DeleteMember: deleteMember(); break; case GroupOperatingPageType.SelectGroupOwner: selectGroupOwner(); break; default: } }, ) ], bottom: PreferredSize( preferredSize: Size.fromHeight(49), child: Container( color: Colors.white, child: Column( children: [ Container( height: 6, color: const Color(0xFFE9E9E9), ), Row( children: [ Consumer( builder: (context, counter, child) { return Container( margin: EdgeInsets.only(left: 10), constraints: BoxConstraints( maxWidth: Screen.width - 100), height: 45, width: (Constants.ContactAvatarSize + 3) * counter.curSelectFriendList.length, child: ListView( reverse: true, controller: _headScrollCtrl, scrollDirection: Axis.horizontal, children: counter.curSelectFriendList.reversed .map((friend) => InkWell( onTap: () { var selectProvider = Provider.of< GroupSelectProvider>(context); bool isSelect = selectProvider.isSelect(friend); if (isSelect) { selectProvider .removeFriend(friend); } else { selectProvider.addFriend(friend); } }, child: Container( margin: EdgeInsets.only(right: 3), child: _createAvatar( friend.avatar)))) .toList(), ), ); }), Expanded( child: _createSearch(), ) ], ) ], ), )), ), body: Stack( children: _body, ))); } deleteMember() { List members = []; for (var i = 0; i < _groupSelectProvider.curSelectFriendList.length; i++) { var fdInfo = _groupSelectProvider.curSelectFriendList[i]; members.add(fdInfo.friendId); } MsgHandler.removeGroupMember(widget.groupId, members); Navigator.of(context).pop(); } addMember() { List members = []; for (var i = 0; i < _groupSelectProvider.curSelectFriendList.length; i++) { var fdInfo = _groupSelectProvider.curSelectFriendList[i]; members.add(fdInfo.friendId); } MsgHandler.addGroupMember(widget.groupId, members); Navigator.of(context).pop(); } selectGroupOwner() { FriendModel fdInfo = _groupSelectProvider.curSelectFriendList[0]; MsgHandler.updateGroupHoster(widget.groupId, fdInfo.friendId); Navigator.of(context).pop('close'); } createGroup() { //创建群 print('创建群:成员数${_groupSelectProvider.curSelectFriendList.length}'); var myId = UserData().basicInfo.userId; var members = [myId]; for (var i = 0; i < _groupSelectProvider.curSelectFriendList.length; i++) { var fdInfo = _groupSelectProvider.curSelectFriendList[i]; members.add(fdInfo.friendId); } if (isCreating) { showToast(I18n.of(context).creating_group); return; } isCreating = true; MsgHandler.createGroup(members, (GroupInfoModel groupInfoModel) { Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => GroupChatPage( key: Key('GroupChat'), groupInfoModel: groupInfoModel))); }); } }