Hibok
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 
 

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