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.
 
 
 
 
 
 

409 lines
14 KiB

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