Hibok
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

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