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.
 
 
 
 
 
 

401 lines
14 KiB

  1. import 'package:chat/data/UserData.dart';
  2. import 'package:chat/data/constants.dart';
  3. import 'package:chat/generated/i18n.dart';
  4. import 'package:chat/home/add_friend.dart';
  5. import 'package:chat/utils/CustomUI.dart';
  6. import 'package:chat/utils/HttpUtil.dart';
  7. import 'package:chat/utils/MessageMgr.dart';
  8. import 'package:chat/utils/TokenMgr.dart';
  9. import 'package:chat/utils/conversation_table.dart';
  10. import 'package:dio/dio.dart';
  11. import 'package:cached_network_image/cached_network_image.dart';
  12. import 'package:flutter/material.dart';
  13. import 'package:flutter/services.dart';
  14. import 'ProfilePage.dart';
  15. class _ContactItem extends StatelessWidget {
  16. _ContactItem(
  17. {@required this.avatar,
  18. @required this.title,
  19. @required this.userId,
  20. this.groupTitle,
  21. this.onPressed,
  22. this.gradient,
  23. this.iconCode,
  24. this.isShowDivder: true,
  25. this.state});
  26. final int userId;
  27. final int iconCode;
  28. final String avatar;
  29. final String title;
  30. final String groupTitle;
  31. final VoidCallback onPressed;
  32. final Gradient gradient;
  33. final bool isShowDivder;
  34. final int state;
  35. static const double MARGIN_VERTICAL = 10.0;
  36. static const double GROUP_TITLE_HEIGHT = 24.0;
  37. @override
  38. Widget build(BuildContext context) {
  39. Widget _avatarIcon;
  40. if (iconCode == null) {
  41. _avatarIcon = ClipRRect(
  42. borderRadius: BorderRadius.circular(6),
  43. child: CachedNetworkImage(
  44. imageUrl: this.avatar,
  45. width: Constants.ContactAvatarSize,
  46. height: Constants.ContactAvatarSize,
  47. ));
  48. } else {
  49. _avatarIcon = Container(
  50. width: Constants.ContactAvatarSize,
  51. height: Constants.ContactAvatarSize,
  52. decoration: BoxDecoration(
  53. gradient: gradient, borderRadius: BorderRadius.circular(6)),
  54. child: Icon(
  55. IconData(this.iconCode, fontFamily: Constants.IconFontFamily),
  56. color: Colors.white,
  57. ),
  58. );
  59. }
  60. Widget _button = Container(
  61. padding: const EdgeInsets.symmetric(
  62. vertical: MARGIN_VERTICAL, horizontal: 16.0),
  63. decoration: BoxDecoration(color: Colors.white),
  64. child: Row(
  65. children: <Widget>[
  66. _avatarIcon,
  67. SizedBox(width: 10.0),
  68. Expanded(child: Text(title, textScaleFactor: 1.0)),
  69. state == 1
  70. ? InkWell(
  71. child: Container(
  72. padding: EdgeInsets.symmetric(horizontal: 21, vertical: 7),
  73. child: Text(
  74. I18n.of(context).added,
  75. textScaleFactor: 1.0,
  76. style: TextStyle(color: const Color(0xFF8A8B8B)),
  77. ),
  78. ),
  79. )
  80. : (state == 0
  81. ? InkWell(
  82. child: Container(
  83. padding:
  84. EdgeInsets.symmetric(horizontal: 21, vertical: 7),
  85. child: Text(
  86. I18n.of(context).already_applied,
  87. textScaleFactor: 1.0,
  88. style: TextStyle(color: const Color(0xFF8A8B8B)),
  89. ),
  90. ),
  91. )
  92. : InkWell(
  93. onTap: () {
  94. Navigator.of(context).push(
  95. new MaterialPageRoute(
  96. builder: (context) {
  97. return AddFriendPage(
  98. userId: this.userId,
  99. pageType: SendMessagePageType.AddFriends,
  100. originalName: I18n.of(context)
  101. .i_am
  102. .replaceFirst(
  103. '/s1', UserData().basicInfo.nickName),
  104. );
  105. },
  106. ),
  107. );
  108. },
  109. child: Container(
  110. padding:
  111. EdgeInsets.symmetric(horizontal: 21, vertical: 7),
  112. decoration: BoxDecoration(
  113. color: const Color(0xFF3875E9),
  114. borderRadius: BorderRadius.circular(5)),
  115. child: Text(
  116. I18n.of(context).add,
  117. textScaleFactor: 1.0,
  118. style: TextStyle(color: Colors.white),
  119. ),
  120. ),
  121. )),
  122. ],
  123. ),
  124. );
  125. //分组标签
  126. Widget _itemBody;
  127. if (this.groupTitle != null) {
  128. _itemBody = Column(
  129. children: <Widget>[
  130. Container(
  131. height: GROUP_TITLE_HEIGHT,
  132. padding: EdgeInsets.only(left: 16.0, right: 16.0),
  133. color: const Color(AppColors.ContactGroupTitleBgColor),
  134. alignment: Alignment.centerLeft,
  135. child: Text(this.groupTitle,
  136. textScaleFactor: 1.0, style: AppStyles.GroupTitleItemTextStyle),
  137. ),
  138. _button,
  139. ],
  140. );
  141. } else {
  142. _itemBody = _button;
  143. }
  144. return InkWell(
  145. onTap: () {
  146. Navigator.of(context).push(
  147. new MaterialPageRoute(
  148. builder: (context) {
  149. return ProfilePage(
  150. userId: userId,
  151. );
  152. },
  153. ),
  154. );
  155. },
  156. child: Container(
  157. color: Colors.white,
  158. child: Column(
  159. children: <Widget>[
  160. _itemBody,
  161. isShowDivder
  162. ? Container(
  163. height: 1,
  164. color: const Color(0xFFF3F3F3),
  165. margin: EdgeInsets.only(
  166. left: 26 + Constants.ContactAvatarSize),
  167. )
  168. : Container()
  169. ],
  170. )));
  171. }
  172. }
  173. class ContactsPage extends StatefulWidget {
  174. @override
  175. _ContactsPageState createState() => _ContactsPageState();
  176. }
  177. class _ContactsPageState extends State<ContactsPage> {
  178. String _currentLetter = '';
  179. ScrollController _scrollController;
  180. TextEditingController _txtCtrl = new TextEditingController();
  181. FocusNode editFocus = FocusNode();
  182. bool _hasdeleteIcon = false;
  183. bool isLoadingFinish = false;
  184. List<FriendModel> searchList = [];
  185. List<FriendModel> friendList = [];
  186. @override
  187. void initState() {
  188. print('ContactsPage initState');
  189. super.initState();
  190. getFriendList();
  191. _scrollController = new ScrollController();
  192. MessageMgr().on('post_add_friend', msgAddFriend);
  193. }
  194. msgAddFriend(data) {
  195. for (int i = 0; i < friendList.length; i++) {
  196. if (friendList[i].friendId == data) {
  197. setState(() {
  198. friendList[i].state = 0;
  199. });
  200. break;
  201. }
  202. }
  203. }
  204. getFriendList() async {
  205. Map data = {
  206. "userId": UserData().basicInfo.userId,
  207. };
  208. data['sign'] = TokenMgr().getSign(data);
  209. Response res = await HttpUtil().post('maillist/user/get', data: data);
  210. Map resData = res.data;
  211. isLoadingFinish = true;
  212. print(resData['data']);
  213. if (resData['code'] == 0 && resData['data'] != null) {
  214. resData['data'].forEach((f) {
  215. var friend = FriendModel.fromServerJson(f);
  216. if (friend.friendId != UserData().basicInfo.userId)
  217. friendList.add(friend);
  218. });
  219. setState(() {});
  220. }
  221. }
  222. @override
  223. void dispose() {
  224. _scrollController.dispose();
  225. editFocus.dispose();
  226. MessageMgr().off('post_add_friend', msgAddFriend);
  227. super.dispose();
  228. }
  229. @override
  230. Widget build(BuildContext context) {
  231. final List<Widget> _body = [];
  232. if (!_hasdeleteIcon) {
  233. friendList.sort((a, b) => a.nameTag.compareTo(b.nameTag));
  234. _body.add((friendList == null || friendList.length == 0)
  235. ? CustomUI.buildNoData(context)
  236. : ListView.builder(
  237. controller: _scrollController,
  238. itemBuilder: (BuildContext context, int index) {
  239. int _contactIndex = index;
  240. bool _isGroupTitle = true;
  241. FriendModel _contact = friendList[_contactIndex];
  242. if (_contactIndex >= 1 &&
  243. _contact.nameTag == friendList[_contactIndex - 1].nameTag) {
  244. _isGroupTitle = false;
  245. }
  246. return _ContactItem(
  247. userId: _contact.friendId,
  248. avatar: _contact.avatar,
  249. title: _contact.name,
  250. state: _contact.state,
  251. isShowDivder: _isGroupTitle,
  252. groupTitle: _isGroupTitle ? _contact.nameTag : null);
  253. },
  254. itemCount: friendList.length,
  255. ));
  256. } else {
  257. _body.add(ListView.builder(
  258. controller: _scrollController,
  259. itemBuilder: (BuildContext context, int index) {
  260. FriendModel _contact = searchList[index];
  261. return _ContactItem(
  262. userId: _contact.friendId,
  263. avatar: _contact.avatar,
  264. title: _contact.name,
  265. state: _contact.state,
  266. isShowDivder: true,
  267. groupTitle: null);
  268. },
  269. itemCount: searchList.length,
  270. ));
  271. }
  272. if (_currentLetter != null &&
  273. _currentLetter.isNotEmpty &&
  274. !_hasdeleteIcon) {
  275. _body.add(Center(
  276. child: Container(
  277. width: Constants.IndexLetterBoxSize,
  278. height: Constants.IndexLetterBoxSize,
  279. decoration: BoxDecoration(
  280. color: AppColors.IndexLetterBoxBgColor,
  281. borderRadius: BorderRadius.all(
  282. Radius.circular(Constants.IndexLetterBoxRadius)),
  283. ),
  284. child: Center(
  285. child: Text(_currentLetter,
  286. textScaleFactor: 1.0, style: AppStyles.IndexLetterBoxTextStyle),
  287. ),
  288. ),
  289. ));
  290. }
  291. return Scaffold(
  292. resizeToAvoidBottomPadding: false,
  293. appBar: AppBar(
  294. backgroundColor: AppColors.NewAppbarBgColor,
  295. title: Text(
  296. I18n.of(context).contact_add,
  297. textScaleFactor: 1.0,
  298. style: TextStyle(color: AppColors.NewAppbarTextColor),
  299. ),
  300. centerTitle: true,
  301. leading: CustomUI.buildCustomLeading(context),
  302. elevation: 1,
  303. bottom: PreferredSize(
  304. preferredSize: Size.fromHeight(49),
  305. child: Container(
  306. alignment: Alignment.center,
  307. margin: EdgeInsets.only(bottom: 14, left: 12.5, right: 12.5),
  308. height: 35,
  309. decoration: BoxDecoration(
  310. color: const Color(0xFFEEEEEE),
  311. borderRadius: BorderRadius.all(Radius.circular(8))),
  312. child: TextField(
  313. keyboardAppearance: Brightness.light,
  314. keyboardType: TextInputType.text,
  315. textInputAction: TextInputAction.search,
  316. controller: _txtCtrl,
  317. focusNode: editFocus,
  318. maxLines: 1,
  319. style: TextStyle(
  320. textBaseline: TextBaseline.alphabetic, fontSize: 14.5),
  321. autofocus: false,
  322. inputFormatters: [
  323. LengthLimitingTextInputFormatter(50),
  324. ],
  325. decoration: InputDecoration(
  326. hintText: I18n.of(context).search,
  327. hintStyle: TextStyle(fontSize: 14.5),
  328. prefixIcon: Icon(
  329. IconData(
  330. 0xe664,
  331. fontFamily: Constants.IconFontFamily,
  332. ),
  333. color: const Color(0xFFA0A0A0),
  334. size: 18,
  335. ),
  336. suffixIcon: Padding(
  337. padding: EdgeInsetsDirectional.only(
  338. start: 2.0, end: _hasdeleteIcon ? 20.0 : 0),
  339. child: _hasdeleteIcon
  340. ? new InkWell(
  341. onTap: (() {
  342. setState(() {
  343. WidgetsBinding.instance
  344. .addPostFrameCallback(
  345. (_) => _txtCtrl.clear());
  346. _hasdeleteIcon = false;
  347. });
  348. }),
  349. child: Icon(
  350. Icons.clear,
  351. size: 18.0,
  352. color: Constants.BlackTextColor,
  353. ))
  354. : new Text('')),
  355. filled: true,
  356. fillColor: Colors.transparent,
  357. border: InputBorder.none,
  358. ),
  359. onChanged: (str) async {
  360. setState(() {
  361. if (str.isEmpty) {
  362. _hasdeleteIcon = false;
  363. } else {
  364. _hasdeleteIcon = true;
  365. searchList = CustomUI().getSearchResult(
  366. str, friendList == null ? [] : friendList);
  367. }
  368. });
  369. },
  370. onEditingComplete: () {}),
  371. )),
  372. ),
  373. body: Stack(
  374. children: _body,
  375. ));
  376. }
  377. }