Hibok
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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