Hibok
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

518 linhas
16 KiB

  1. import 'package:cached_network_image/cached_network_image.dart';
  2. import 'package:chat/home/global_search.dart';
  3. import 'package:chat/home/new_addfriends.dart';
  4. import 'package:chat/home/new_friends.dart';
  5. import 'package:chat/models/friends_info.dart';
  6. import 'package:flutter/material.dart';
  7. import 'package:chat/data/UserData.dart';
  8. import 'package:chat/data/constants.dart';
  9. import 'package:chat/generated/i18n.dart';
  10. import 'package:chat/models/ref_name_provider.dart';
  11. import 'package:chat/utils/CustomUI.dart';
  12. import 'package:chat/utils/HttpUtil.dart';
  13. import 'package:chat/utils/MessageMgr.dart';
  14. import 'package:chat/utils/TokenMgr.dart';
  15. import 'package:chat/utils/conversation_table.dart';
  16. import 'package:chat/utils/friend_list_mgr.dart';
  17. import 'package:chat/utils/screen.dart';
  18. import 'package:dio/dio.dart';
  19. import 'package:oktoast/oktoast.dart';
  20. import 'package:permission_handler/permission_handler.dart';
  21. import 'package:provider/provider.dart';
  22. import 'package:shared_preferences/shared_preferences.dart';
  23. import 'address_book.dart';
  24. List showUserList = [];
  25. bool isHaveNewFriends() {
  26. return showUserList.length > 0;
  27. }
  28. class FriendPage extends StatefulWidget {
  29. @override
  30. _FriendPageState createState() => _FriendPageState();
  31. }
  32. class _FriendPageState extends State<FriendPage> {
  33. String _currentLetter = '';
  34. ScrollController _scrollController;
  35. List<FriendModel> friendList = [];
  36. List<Widget> _functionButtons = [];
  37. final Map _letterPosMap = {INDEX_BAR_WORDS[0]: 0.0};
  38. Set<String> userIdSet = new Set();
  39. //var _contactsFuture;
  40. @override
  41. void initState() {
  42. super.initState();
  43. print('FriendPage initState');
  44. initNewFriendsList([]);
  45. getFriendList();
  46. getNewFriendList(null);
  47. _scrollController = new ScrollController();
  48. MessageMgr().on('Add friend', msgAddfrend);
  49. MessageMgr().on('Delete friend', msgDeletefrend);
  50. MessageMgr().on('do_friend_apply', messageApply);
  51. MessageMgr().on('goto_new_friends', messageNew);
  52. }
  53. messageApply(data) {
  54. getNewFriendList(data);
  55. }
  56. messageNew(data) {
  57. gotoNewFriendsPage();
  58. }
  59. gotoNewFriendsPage() async {
  60. Navigator.of(context).push(
  61. new MaterialPageRoute(
  62. builder: (context) {
  63. return NewFriendsPage();
  64. },
  65. ),
  66. );
  67. SharedPreferences prefs = await SharedPreferences.getInstance();
  68. prefs.setStringList(Constants.NewFriendsList, userIdSet.toList());
  69. showUserList = [];
  70. initNewFriendsList([]);
  71. setState(() {});
  72. }
  73. Widget _buildNewFriends(list) {
  74. if (list.length == 0) {
  75. return FriendsInfo(
  76. avatar: '',
  77. userId: 0,
  78. iconCode: 0xe66c,
  79. title: I18n.of(Constants.getCurrentContext()).new_friends,
  80. gradient: LinearGradient(
  81. begin: Alignment.topCenter,
  82. end: Alignment.bottomCenter,
  83. colors: <Color>[
  84. const Color(0xFF58B7F5),
  85. const Color(0xFF1874C9),
  86. ]),
  87. onPressed: gotoNewFriendsPage);
  88. } else {
  89. return _buildFriendsItem(list);
  90. }
  91. }
  92. Widget _buildAvatar(url) {
  93. return ClipRRect(
  94. borderRadius: BorderRadius.circular(6),
  95. child: CachedNetworkImage(
  96. imageUrl: url,
  97. placeholder: (context, url) => Image.asset(
  98. Constants.DefaultHeadImgUrl,
  99. width: Constants.ContactAvatarSize,
  100. height: Constants.ContactAvatarSize,
  101. ),
  102. width: Constants.ContactAvatarSize,
  103. height: Constants.ContactAvatarSize,
  104. ));
  105. }
  106. Widget _buildFriendsItem(list) {
  107. Widget unreadRedDot = Container(
  108. margin: EdgeInsets.only(right: 15),
  109. width: Constants.UnReadMsgNotifyDotSize,
  110. height: Constants.UnReadMsgNotifyDotSize,
  111. alignment: Alignment.center,
  112. decoration: BoxDecoration(
  113. borderRadius:
  114. BorderRadius.circular(Constants.UnReadMsgNotifyDotSize / 2.0),
  115. color: Color(0xFFFF5454),
  116. ),
  117. child: Text(list.length > 99 ? "99+" : list.length.toString(),
  118. textScaleFactor: 1.0, style: AppStyles.UnreadMsgCountDotStyle),
  119. );
  120. var left;
  121. if (list.length == 1) {
  122. left = Row(
  123. children: <Widget>[
  124. _buildAvatar(list[0]['ApplyUrl']),
  125. SizedBox(width: 10.0),
  126. Expanded(
  127. child: Column(
  128. crossAxisAlignment: CrossAxisAlignment.start,
  129. children: <Widget>[
  130. Text(list[0]['ApplyName'],
  131. textScaleFactor: 1.0, style: TextStyle(fontSize: 12.66)),
  132. SizedBox(
  133. height: 5,
  134. ),
  135. Text(I18n.of(context).apply_fro_friends,
  136. textScaleFactor: 1.0,
  137. style:
  138. TextStyle(fontSize: 10, color: const Color(0xFF6A6A6A))),
  139. ],
  140. )),
  141. unreadRedDot,
  142. ],
  143. );
  144. } else {
  145. left = Row(
  146. children: <Widget>[
  147. Expanded(
  148. child: Container(
  149. height: Constants.ContactAvatarSize,
  150. constraints: BoxConstraints(maxWidth: Screen.width - 100),
  151. child: ListView(
  152. scrollDirection: Axis.horizontal,
  153. children: list
  154. .map<Widget>((f) => Container(
  155. child: _buildAvatar(f['ApplyUrl']),
  156. margin: EdgeInsets.only(right: 5),
  157. ))
  158. .toList(),
  159. ))),
  160. unreadRedDot,
  161. ],
  162. );
  163. }
  164. return InkWell(
  165. onTap: gotoNewFriendsPage,
  166. child: Container(
  167. padding: const EdgeInsets.symmetric(
  168. vertical: MARGIN_VERTICAL, horizontal: 16.0),
  169. decoration: BoxDecoration(color: Colors.white),
  170. child: left,
  171. ));
  172. }
  173. // showPermission() async {
  174. // if (await CustomUI.showPermissionSetting(
  175. // Constants.getCurrentContext(),
  176. // PermissionGroup.contacts,
  177. // I18n.of(Constants.getCurrentContext()).contact_permission)) {
  178. // MessageMgr().emit('PostContact');
  179. // Navigator.push(Constants.getCurrentContext(),
  180. // MaterialPageRoute<void>(builder: (BuildContext context) {
  181. // return ContactsPage();
  182. // }));
  183. // }
  184. // }
  185. getFriendList() async {
  186. friendList = await FriendListMgr().getFriendList();
  187. if (mounted) {
  188. setState(() {});
  189. }
  190. }
  191. getNewFriendList(userdata) async {
  192. Map data = {
  193. "userId": UserData().basicInfo.userId,
  194. "type": 1,
  195. };
  196. data['sign'] = TokenMgr().getSign(data);
  197. Response res =
  198. await HttpUtil().post('friendship/newFriends/record', data: data);
  199. if (res == null) {
  200. return;
  201. }
  202. var resData = res.data;
  203. if (resData['code'] == 0) {
  204. if (resData['data'] != null) {
  205. SharedPreferences prefs = await SharedPreferences.getInstance();
  206. List<String> list = prefs.getStringList(Constants.NewFriendsList);
  207. if (list != null) {
  208. userIdSet = new Set.from(list);
  209. } else {
  210. userIdSet = new Set();
  211. }
  212. if (userdata != null && userIdSet.contains(userdata['userId'])) {
  213. userIdSet.remove(userdata['userId']);
  214. }
  215. showUserList = [];
  216. for (int i = 0; i < resData['data'].length; i++) {
  217. if (!userIdSet
  218. .contains(resData['data'][i]['ApplyUserId'].toString())) {
  219. showUserList.add(resData['data'][i]);
  220. userIdSet.add(resData['data'][i]['ApplyUserId'].toString());
  221. }
  222. }
  223. initNewFriendsList(showUserList);
  224. if (mounted) {
  225. setState(() {});
  226. }
  227. }
  228. } else {
  229. showToast(resData['msg']);
  230. }
  231. }
  232. initNewFriendsList(showUserList) {
  233. _functionButtons = [_buildNewFriends(showUserList)];
  234. }
  235. msgAddfrend(data) {
  236. getFriendList();
  237. }
  238. msgDeletefrend(data) {
  239. getFriendList();
  240. }
  241. updateIndexPos(List<FriendModel> friendList) {
  242. //计算用于 IndexBar 进行定位的关键通讯录列表项的位置
  243. var _totalPos = _functionButtons.length * FriendsInfo.height(false);
  244. for (var i = 0; i < friendList.length; i++) {
  245. bool _hasGroupTitle = true;
  246. if (i > 0 &&
  247. friendList[i].nameTag.compareTo(friendList[i - 1].nameTag) == 0) {
  248. _hasGroupTitle = false;
  249. }
  250. if (_hasGroupTitle) {
  251. _letterPosMap[friendList[i].nameTag] = _totalPos;
  252. }
  253. _totalPos += FriendsInfo.height(_hasGroupTitle);
  254. }
  255. }
  256. @override
  257. void dispose() {
  258. _scrollController.dispose();
  259. print('FriendPage dispose');
  260. MessageMgr().off('Add friend', msgAddfrend);
  261. MessageMgr().off('Delete friend', msgDeletefrend);
  262. MessageMgr().off('do_friend_apply', messageApply);
  263. MessageMgr().off('goto_new_friends', messageNew);
  264. super.dispose();
  265. }
  266. String getLetter(BuildContext context, double tileHeight, Offset globalPos) {
  267. RenderBox _box = context.findRenderObject();
  268. var local = _box.globalToLocal(globalPos);
  269. int index = (local.dy ~/ tileHeight).clamp(0, INDEX_BAR_WORDS.length - 1);
  270. return INDEX_BAR_WORDS[index];
  271. }
  272. void _jumpToIndex(String letter) {
  273. if (_letterPosMap.isNotEmpty) {
  274. final _pos = _letterPosMap[letter];
  275. if (_pos != null) {
  276. _scrollController.animateTo(_letterPosMap[letter],
  277. curve: Curves.easeInOut, duration: Duration(microseconds: 200));
  278. }
  279. }
  280. }
  281. Widget _buildIndexBar(BuildContext context, BoxConstraints constraints) {
  282. final List<Widget> _letters = INDEX_BAR_WORDS.map((String word) {
  283. return Expanded(
  284. child: Container(
  285. margin: EdgeInsets.only(right: 5),
  286. decoration: BoxDecoration(
  287. shape: BoxShape.circle,
  288. color:
  289. _currentLetter == word ? Colors.blue : Colors.transparent,
  290. ),
  291. alignment: Alignment.center,
  292. padding: EdgeInsets.all(2),
  293. width: 20,
  294. child: Text(
  295. word,
  296. textScaleFactor: 1.0,
  297. style: TextStyle(
  298. fontSize: 10,
  299. color:
  300. _currentLetter == word ? Colors.white : Colors.black),
  301. )));
  302. }).toList();
  303. final _totalHeight = constraints.biggest.height;
  304. final _tileHeight = _totalHeight / _letters.length;
  305. return GestureDetector(
  306. onVerticalDragDown: (DragDownDetails details) {
  307. setState(() {
  308. _currentLetter =
  309. getLetter(context, _tileHeight, details.globalPosition);
  310. _jumpToIndex(_currentLetter);
  311. });
  312. },
  313. onVerticalDragEnd: (DragEndDetails details) {
  314. setState(() {
  315. //_indexBarBgColor = Colors.transparent;
  316. _currentLetter = null;
  317. });
  318. },
  319. onVerticalDragCancel: () {
  320. setState(() {
  321. //_indexBarBgColor = Colors.transparent;
  322. _currentLetter = null;
  323. });
  324. },
  325. onVerticalDragUpdate: (DragUpdateDetails details) {
  326. setState(() {
  327. //var _letter = getLetter(context, _tileHeight, details.globalPosition);
  328. _currentLetter =
  329. getLetter(context, _tileHeight, details.globalPosition);
  330. _jumpToIndex(_currentLetter);
  331. });
  332. },
  333. child: Column(
  334. children: _letters,
  335. ),
  336. );
  337. }
  338. @override
  339. Widget build(BuildContext context) {
  340. final List<Widget> _body = [];
  341. friendList.sort((a, b) => a.nameTag.compareTo(b.nameTag));
  342. updateIndexPos(friendList);
  343. _body.addAll([
  344. ListView.builder(
  345. controller: _scrollController,
  346. itemBuilder: (BuildContext context, int index) {
  347. if (index < _functionButtons.length) {
  348. if (index == 0) {
  349. return Padding(
  350. padding: EdgeInsets.only(top: 7),
  351. child: _functionButtons[index],
  352. );
  353. } else {
  354. return _functionButtons[index];
  355. }
  356. }
  357. var result;
  358. int _contactIndex = index - _functionButtons.length;
  359. bool _isGroupTitle = true;
  360. FriendModel _contact = friendList[_contactIndex];
  361. if (_contactIndex >= 1 &&
  362. _contact.nameTag == friendList[_contactIndex - 1].nameTag) {
  363. _isGroupTitle = false;
  364. }
  365. result = FriendsInfo(
  366. userId: _contact.friendId,
  367. avatar: _contact.avatar,
  368. title: Provider.of<RefNameProvider>(context)
  369. .getRefName(_contact.friendId, _contact.name),
  370. isShowDivder: true,
  371. groupTitle: _isGroupTitle ? _contact.nameTag : null);
  372. if (index == (friendList.length + _functionButtons.length - 1)) {
  373. return result = Column(
  374. children: <Widget>[
  375. result,
  376. Container(
  377. height: 50,
  378. color: Colors.white,
  379. child: Text(I18n.of(context)
  380. .total_friends_nus
  381. .replaceFirst('/s1', friendList.length.toString())),
  382. alignment: Alignment.center,
  383. width: Screen.width,
  384. ),
  385. ],
  386. );
  387. }
  388. return result;
  389. },
  390. itemCount: friendList.length + _functionButtons.length,
  391. ),
  392. Positioned(
  393. width: Constants.IndexBarWidth,
  394. right: 0.0,
  395. top: 0.0,
  396. bottom: 0.0,
  397. child: Container(
  398. //color: _indexBarBgColor,
  399. child: LayoutBuilder(
  400. builder: _buildIndexBar,
  401. ),
  402. ),
  403. )
  404. ]);
  405. if (_currentLetter != null && _currentLetter.isNotEmpty) {
  406. _body.add(Center(
  407. child: Container(
  408. width: Constants.IndexLetterBoxSize,
  409. height: Constants.IndexLetterBoxSize,
  410. decoration: BoxDecoration(
  411. color: AppColors.IndexLetterBoxBgColor,
  412. borderRadius: BorderRadius.all(
  413. Radius.circular(Constants.IndexLetterBoxRadius)),
  414. ),
  415. child: Center(
  416. child: Text(_currentLetter,
  417. textScaleFactor: 1.0, style: AppStyles.IndexLetterBoxTextStyle),
  418. ),
  419. ),
  420. ));
  421. }
  422. return Scaffold(
  423. resizeToAvoidBottomPadding: false,
  424. appBar: AppBar(
  425. backgroundColor: AppColors.NewAppbarBgColor,
  426. title: Text(I18n.of(context).contact,
  427. textScaleFactor: 1.0, style: Constants.MainTitleStyle),
  428. centerTitle: false,
  429. elevation: 1,
  430. actions: <Widget>[
  431. Container(
  432. child: IconButton(
  433. icon: CircleAvatar(
  434. backgroundColor: Constants.GreyBackgroundColor,
  435. radius: 13.75,
  436. child: Padding(
  437. padding: EdgeInsets.only(bottom: 1.5),
  438. child: Icon(
  439. IconData(0xe662,
  440. fontFamily: Constants.IconFontFamily),
  441. color: Constants.BlackTextColor,
  442. size: 21,
  443. ))),
  444. onPressed: () {
  445. Navigator.of(context).push(
  446. new MaterialPageRoute(
  447. builder: (context) {
  448. return NewAddFriendsPage();
  449. },
  450. ),
  451. );
  452. },
  453. ),
  454. ),
  455. ],
  456. bottom: CustomUI.buildSearchButton(context, () {
  457. Navigator.of(context).push(
  458. new MaterialPageRoute(
  459. builder: (context) {
  460. return GlobalSearchPage(
  461. type: GlobalSearchPageType.SearchMyFriends,
  462. );
  463. },
  464. ),
  465. );
  466. })),
  467. body: Stack(
  468. children: _body,
  469. ));
  470. }
  471. }