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.

357 lines
12KB

  1. import 'package:farm_tpf/custom_model/NotificationDTO.dart';
  2. import 'package:farm_tpf/data/repository/repository.dart';
  3. import 'package:farm_tpf/presentation/custom_widgets/app_bar_widget.dart';
  4. import 'package:farm_tpf/presentation/custom_widgets/bottom_loader.dart';
  5. import 'package:farm_tpf/presentation/custom_widgets/dash_line_widget.dart';
  6. import 'package:farm_tpf/presentation/custom_widgets/loading_list_page.dart';
  7. import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart';
  8. import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_information.dart';
  9. import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_parameter.dart';
  10. import 'package:farm_tpf/utils/const_icons.dart';
  11. import 'package:farm_tpf/utils/pref.dart';
  12. import 'package:firebase_messaging/firebase_messaging.dart';
  13. import 'package:flutter/material.dart';
  14. import 'package:flutter_bloc/flutter_bloc.dart';
  15. import 'package:farm_tpf/utils/formatter.dart';
  16. import 'package:flutter_svg/svg.dart';
  17. import 'bloc/noti_bloc.dart';
  18. class NotificationScreen extends StatefulWidget {
  19. @override
  20. _NotificationScreenState createState() => _NotificationScreenState();
  21. }
  22. class _NotificationScreenState extends State<NotificationScreen> {
  23. final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
  24. var notiBloc = NotiBloc(repository: Repository());
  25. @override
  26. void initState() {
  27. super.initState();
  28. _firebaseMessaging.configure(
  29. onMessage: (Map<String, dynamic> message) async {
  30. print("onMessage: $message");
  31. try {
  32. notiBloc.add(OnRefreshFromNotification());
  33. } catch (e) {
  34. print(e);
  35. }
  36. });
  37. }
  38. @override
  39. Widget build(BuildContext context) {
  40. return BlocBuilder(
  41. cubit: notiBloc,
  42. builder: (context, state) {
  43. return HoldInfinityWidget(
  44. notiBloc: notiBloc,
  45. );
  46. });
  47. }
  48. }
  49. class HoldInfinityWidget extends StatelessWidget {
  50. final NotiBloc notiBloc;
  51. HoldInfinityWidget({@required this.notiBloc});
  52. final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  53. @override
  54. Widget build(BuildContext context) {
  55. return Scaffold(
  56. key: _scaffoldKey,
  57. backgroundColor: Colors.white,
  58. body: BlocBuilder<NotiBloc, NotiState>(
  59. cubit: notiBloc,
  60. builder: (context, state) {
  61. return SafeArea(
  62. child: InfinityView(
  63. notiBloc: notiBloc,
  64. ),
  65. );
  66. },
  67. ));
  68. }
  69. }
  70. class InfinityView extends StatefulWidget {
  71. final NotiBloc notiBloc;
  72. InfinityView({@required this.notiBloc});
  73. @override
  74. _InfinityViewState createState() => _InfinityViewState();
  75. }
  76. class _InfinityViewState extends State<InfinityView> {
  77. final _scrollController = ScrollController();
  78. final _scrollThreshold = 250.0;
  79. List<NotificationDTO> currentItems = new List<NotificationDTO>();
  80. int latestId = 0;
  81. int currentPage = 0;
  82. bool currentHasReachedMax = true;
  83. bool isUpdatingFromApi = true;
  84. var pref = LocalPref();
  85. var token;
  86. Future<Null> getSharedPrefs() async {
  87. _scrollController.addListener(() {
  88. final maxScroll = _scrollController.position.maxScrollExtent;
  89. final currentScroll = _scrollController.position.pixels;
  90. if (maxScroll - currentScroll < _scrollThreshold) {
  91. widget.notiBloc.add(DataFetched());
  92. }
  93. });
  94. token = await pref.getString(DATA_CONST.TOKEN_KEY);
  95. }
  96. @override
  97. void initState() {
  98. getSharedPrefs();
  99. widget.notiBloc.add(DataFetched());
  100. super.initState();
  101. }
  102. @override
  103. Widget build(BuildContext context) {
  104. return BlocBuilder<NotiBloc, NotiState>(
  105. cubit: widget.notiBloc,
  106. builder: (context, state) {
  107. if (state is NotiFailure) {
  108. return Center(child: Text(state.errorString));
  109. } else if (state is NotiSuccess) {
  110. if (state.items.isEmpty) {
  111. return Column(
  112. crossAxisAlignment: CrossAxisAlignment.start,
  113. children: [
  114. SizedBox(
  115. height: 8,
  116. ),
  117. Padding(
  118. padding: const EdgeInsets.all(8.0),
  119. child: Text('Thông báo',
  120. style:
  121. TextStyle(fontWeight: FontWeight.w500, fontSize: 22)),
  122. ),
  123. Expanded(
  124. child: Center(child: Text("Không có thông báo")),
  125. ),
  126. ],
  127. );
  128. }
  129. currentItems = List<NotificationDTO>.from(state.items);
  130. currentPage = state.page;
  131. currentHasReachedMax = state.hasReachedMax;
  132. return Column(
  133. children: <Widget>[
  134. Container(
  135. padding: EdgeInsets.all(8),
  136. color: Colors.white,
  137. child: Row(
  138. children: [
  139. SizedBox(
  140. height: 8,
  141. ),
  142. Expanded(
  143. child: Text(
  144. 'Thông báo',
  145. style: TextStyle(
  146. fontWeight: FontWeight.w500, fontSize: 22),
  147. )),
  148. BlocBuilder<NotiBloc, NotiState>(
  149. cubit: widget.notiBloc,
  150. builder: (context, state) {
  151. if (state is NotiSuccess) {
  152. if (state.items.length > 0) {
  153. return FlatButton(
  154. onPressed: () {
  155. widget.notiBloc.add(
  156. MarkAllNotificationUpdate(status: "1"));
  157. },
  158. child: Text('Đánh dấu đã đọc tất cả',
  159. style: TextStyle(
  160. fontWeight: FontWeight.normal,
  161. fontSize: 14,
  162. color: Colors.blue)));
  163. } else {
  164. return SizedBox();
  165. }
  166. } else {
  167. return SizedBox();
  168. }
  169. },
  170. )
  171. ],
  172. )),
  173. Expanded(
  174. child: RefreshIndicator(
  175. child: ListView.builder(
  176. itemBuilder: (BuildContext context, int index) {
  177. return index >= state.items.length
  178. ? BottomLoader()
  179. : ItemInfinityWidget(
  180. notiBloc: widget.notiBloc,
  181. unread: state.unread,
  182. read: state.read,
  183. currentItems: currentItems,
  184. item: state.items[index],
  185. currentPage: state.page,
  186. currentReachedMax: state.hasReachedMax,
  187. );
  188. },
  189. itemCount: state.hasReachedMax
  190. ? state.items.length
  191. : state.items.length + 1,
  192. controller: _scrollController,
  193. ),
  194. onRefresh: () async {
  195. widget.notiBloc.add(OnRefresh());
  196. }))
  197. ],
  198. );
  199. } else if (state is NotiLoadding) {
  200. return Center(
  201. child: LoadingListPage(),
  202. );
  203. }
  204. return Container();
  205. },
  206. );
  207. }
  208. @override
  209. void dispose() {
  210. _scrollController.dispose();
  211. super.dispose();
  212. }
  213. }
  214. class ItemInfinityWidget extends StatelessWidget {
  215. final int unread;
  216. final int read;
  217. final NotificationDTO item;
  218. final List<NotificationDTO> currentItems;
  219. final int currentPage;
  220. final bool currentReachedMax;
  221. final NotiBloc notiBloc;
  222. const ItemInfinityWidget(
  223. {Key key,
  224. @required this.unread,
  225. @required this.read,
  226. @required this.currentItems,
  227. @required this.item,
  228. @required this.currentPage,
  229. @required this.currentReachedMax,
  230. @required this.notiBloc})
  231. : super(key: key);
  232. @override
  233. Widget build(BuildContext context) {
  234. return Column(
  235. children: [
  236. GestureDetector(
  237. child: Container(
  238. margin: EdgeInsets.all(4.0),
  239. child: Column(
  240. children: [
  241. ListTile(
  242. title: Text(item.subject),
  243. subtitle: Column(
  244. crossAxisAlignment: CrossAxisAlignment.start,
  245. children: <Widget>[
  246. Text(item.message),
  247. Row(children: [
  248. Icon(Icons.access_time,
  249. color: item.isRead == 1
  250. ? Colors.grey
  251. : Colors.blue,
  252. size: 18),
  253. SizedBox(
  254. width: 4,
  255. ),
  256. Text(item.sendDate.format_DDMMYY_HHmm(),
  257. style: TextStyle(
  258. color: item.isRead == 1
  259. ? Colors.grey
  260. : Colors.blue))
  261. ]),
  262. ],
  263. ),
  264. leading: SvgPicture.asset(AppIcons.icNotificationItem)),
  265. ],
  266. )),
  267. onTap: () {
  268. if (item.contents == "ENV_UPDATE") {
  269. Navigator.push(
  270. context,
  271. MaterialPageRoute(
  272. builder: (BuildContext context) => PlotParameterScreen(
  273. cropId: item.tbCropId,
  274. isShowAppbar: true,
  275. ))).then((value) {
  276. if (item.isRead == 0) {
  277. _updateReadNotification(
  278. context: context,
  279. unread: unread,
  280. read: read,
  281. item: item,
  282. currentItems: currentItems,
  283. currentPage: currentPage,
  284. currentReachedMax: currentReachedMax);
  285. }
  286. });
  287. } else if (item.contents == "PIC_UPDATE") {
  288. Navigator.push(
  289. context,
  290. MaterialPageRoute(
  291. builder: (BuildContext context) =>
  292. PlotInformationScreen(
  293. cropId: item.tbCropId,
  294. isShowAppbar: true,
  295. ))).then((value) {
  296. if (item.isRead == 0) {
  297. _updateReadNotification(
  298. context: context,
  299. unread: unread,
  300. read: read,
  301. item: item,
  302. currentItems: currentItems,
  303. currentPage: currentPage,
  304. currentReachedMax: currentReachedMax);
  305. }
  306. });
  307. } else {}
  308. }),
  309. Container(
  310. padding: EdgeInsets.only(left: 16, right: 16),
  311. child: DashLineWidget())
  312. ],
  313. );
  314. }
  315. _updateReadNotification(
  316. {BuildContext context,
  317. int unread,
  318. int read,
  319. NotificationDTO item,
  320. List<NotificationDTO> currentItems,
  321. int currentPage,
  322. bool currentReachedMax}) {
  323. List<NotificationDTO> updatedItems = new List<NotificationDTO>();
  324. currentItems.forEach((e) {
  325. if (e.id == item.id) {
  326. e.isRead = 1;
  327. } else {}
  328. updatedItems.add(NotificationDTO.clone(e));
  329. });
  330. notiBloc.add(OnUpdate<NotificationDTO>(
  331. unread: unread - 1,
  332. read: read + 1,
  333. currentItemId: item.id,
  334. currentItems: updatedItems,
  335. currentPage: currentPage,
  336. hasReachedMax: currentReachedMax));
  337. }
  338. }