Hibok
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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