Hibok
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

537 строки
17 KiB

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