| @@ -1 +1 @@ | |||
| af5bc8188bfe648f3bf82e3093eb6f6d | |||
| d91c957b2422e26116533c8dae89710a | |||
| @@ -1,6 +1,6 @@ | |||
| part of 'noti_bloc.dart'; | |||
| abstract class NotiEvent extends Equatable { | |||
| abstract class NotiEvent { | |||
| const NotiEvent(); | |||
| @override | |||
| @@ -1,6 +1,6 @@ | |||
| part of 'noti_bloc.dart'; | |||
| abstract class NotiState extends Equatable { | |||
| abstract class NotiState { | |||
| const NotiState(); | |||
| @override | |||
| @@ -1,16 +1,13 @@ | |||
| import 'package:farm_tpf/custom_model/NotificationDTO.dart'; | |||
| import 'package:farm_tpf/data/repository/repository.dart'; | |||
| import 'package:farm_tpf/presentation/custom_widgets/app_bar_widget.dart'; | |||
| import 'package:farm_tpf/presentation/custom_widgets/bottom_loader.dart'; | |||
| import 'package:farm_tpf/presentation/custom_widgets/dash_line_widget.dart'; | |||
| import 'package:farm_tpf/presentation/custom_widgets/loading_list_page.dart'; | |||
| import 'package:farm_tpf/presentation/screens/notification/update_count_noti_bloc.dart'; | |||
| import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart'; | |||
| import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_information.dart'; | |||
| import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_parameter.dart'; | |||
| import 'package:farm_tpf/utils/NotificationsBloc.dart'; | |||
| import 'package:farm_tpf/utils/const_icons.dart'; | |||
| import 'package:farm_tpf/utils/pref.dart'; | |||
| import 'package:firebase_messaging/firebase_messaging.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:flutter_bloc/flutter_bloc.dart'; | |||
| import 'package:farm_tpf/utils/formatter.dart'; | |||
| @@ -24,66 +21,8 @@ class NotificationScreen extends StatefulWidget { | |||
| } | |||
| class _NotificationScreenState extends State<NotificationScreen> { | |||
| final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); | |||
| var notiBloc = NotiBloc(repository: Repository()); | |||
| @override | |||
| void initState() { | |||
| super.initState(); | |||
| _firebaseMessaging.configure( | |||
| onMessage: (Map<String, dynamic> message) async { | |||
| print("onMessage: $message"); | |||
| try { | |||
| notiBloc.add(OnRefreshFromNotification()); | |||
| updateCountNotiBloc.getNotifications((data) {}, (err) {}); | |||
| } catch (e) { | |||
| print(e); | |||
| } | |||
| }); | |||
| } | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return BlocBuilder( | |||
| cubit: notiBloc, | |||
| builder: (context, state) { | |||
| return HoldInfinityWidget( | |||
| notiBloc: notiBloc, | |||
| ); | |||
| }); | |||
| } | |||
| } | |||
| class HoldInfinityWidget extends StatelessWidget { | |||
| final NotiBloc notiBloc; | |||
| HoldInfinityWidget({@required this.notiBloc}); | |||
| final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(); | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return Scaffold( | |||
| key: _scaffoldKey, | |||
| backgroundColor: Colors.white, | |||
| body: BlocBuilder<NotiBloc, NotiState>( | |||
| cubit: notiBloc, | |||
| builder: (context, state) { | |||
| return SafeArea( | |||
| child: InfinityView( | |||
| notiBloc: notiBloc, | |||
| ), | |||
| ); | |||
| }, | |||
| )); | |||
| } | |||
| } | |||
| class InfinityView extends StatefulWidget { | |||
| final NotiBloc notiBloc; | |||
| InfinityView({@required this.notiBloc}); | |||
| @override | |||
| _InfinityViewState createState() => _InfinityViewState(); | |||
| } | |||
| class _InfinityViewState extends State<InfinityView> { | |||
| final _scrollController = ScrollController(); | |||
| final _scrollThreshold = 250.0; | |||
| List<NotificationDTO> currentItems = new List<NotificationDTO>(); | |||
| @@ -91,6 +30,7 @@ class _InfinityViewState extends State<InfinityView> { | |||
| int currentPage = 0; | |||
| bool currentHasReachedMax = true; | |||
| bool isUpdatingFromApi = true; | |||
| Stream<LocalNotification> _notificationsStream; | |||
| var pref = LocalPref(); | |||
| var token; | |||
| @@ -99,7 +39,7 @@ class _InfinityViewState extends State<InfinityView> { | |||
| final maxScroll = _scrollController.position.maxScrollExtent; | |||
| final currentScroll = _scrollController.position.pixels; | |||
| if (maxScroll - currentScroll < _scrollThreshold) { | |||
| widget.notiBloc.add(DataFetched()); | |||
| notiBloc.add(DataFetched()); | |||
| } | |||
| }); | |||
| token = await pref.getString(DATA_CONST.TOKEN_KEY); | |||
| @@ -108,14 +48,20 @@ class _InfinityViewState extends State<InfinityView> { | |||
| @override | |||
| void initState() { | |||
| getSharedPrefs(); | |||
| widget.notiBloc.add(DataFetched()); | |||
| notiBloc.add(DataFetched()); | |||
| _notificationsStream = NotificationsBloc.instance.notificationsStream; | |||
| _notificationsStream.listen((notification) { | |||
| updateCountNotiBloc.getNotifications((data) {}, (err) {}); | |||
| print('Notification: $notification'); | |||
| notiBloc.add(OnRefresh()); | |||
| }); | |||
| super.initState(); | |||
| } | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return BlocBuilder<NotiBloc, NotiState>( | |||
| cubit: widget.notiBloc, | |||
| cubit: notiBloc, | |||
| builder: (context, state) { | |||
| if (state is NotiFailure) { | |||
| return Center(child: Text(state.errorString)); | |||
| @@ -160,29 +106,16 @@ class _InfinityViewState extends State<InfinityView> { | |||
| style: TextStyle( | |||
| fontWeight: FontWeight.w500, fontSize: 22), | |||
| )), | |||
| BlocBuilder<NotiBloc, NotiState>( | |||
| cubit: widget.notiBloc, | |||
| builder: (context, state) { | |||
| if (state is NotiSuccess) { | |||
| if (state.items.length > 0) { | |||
| return FlatButton( | |||
| onPressed: () { | |||
| widget.notiBloc.add( | |||
| MarkAllNotificationUpdate(status: "1")); | |||
| }, | |||
| child: Text('Đánh dấu đã đọc tất cả', | |||
| style: TextStyle( | |||
| fontWeight: FontWeight.normal, | |||
| fontSize: 14, | |||
| color: Colors.blue))); | |||
| } else { | |||
| return SizedBox(); | |||
| } | |||
| } else { | |||
| return SizedBox(); | |||
| } | |||
| }, | |||
| ) | |||
| FlatButton( | |||
| onPressed: () { | |||
| notiBloc | |||
| .add(MarkAllNotificationUpdate(status: "1")); | |||
| }, | |||
| child: Text('Đánh dấu đã đọc tất cả', | |||
| style: TextStyle( | |||
| fontWeight: FontWeight.normal, | |||
| fontSize: 14, | |||
| color: Colors.blue))) | |||
| ], | |||
| )), | |||
| Expanded( | |||
| @@ -193,7 +126,7 @@ class _InfinityViewState extends State<InfinityView> { | |||
| return index >= state.items.length | |||
| ? BottomLoader() | |||
| : ItemInfinityWidget( | |||
| notiBloc: widget.notiBloc, | |||
| notiBloc: notiBloc, | |||
| unread: state.unread, | |||
| read: state.read, | |||
| currentItems: currentItems, | |||
| @@ -208,7 +141,7 @@ class _InfinityViewState extends State<InfinityView> { | |||
| controller: _scrollController, | |||
| ), | |||
| onRefresh: () async { | |||
| widget.notiBloc.add(OnRefresh()); | |||
| notiBloc.add(OnRefresh()); | |||
| })) | |||
| ], | |||
| ); | |||
| @@ -11,6 +11,7 @@ class UpdateCountNotiBloc { | |||
| void getNotifications(Function(NotificationObjectDTO) onSuccess, | |||
| Function(String) onError) async { | |||
| _repository.getNotifications().then((value) { | |||
| print('get noti ok ${value.numberUnreadTotal}'); | |||
| onSuccess(value); | |||
| _notiFetcher.sink.add(value); | |||
| }).catchError((onError) { | |||
| @@ -1,10 +1,4 @@ | |||
| import 'dart:io'; | |||
| import 'package:dio/dio.dart'; | |||
| import 'package:farm_tpf/custom_model/NotificationDTO.dart'; | |||
| import 'package:farm_tpf/data/repository/repository.dart'; | |||
| import 'package:farm_tpf/data/repository/user_repository.dart'; | |||
| import 'package:farm_tpf/main.dart'; | |||
| import 'package:farm_tpf/models/index.dart'; | |||
| import 'package:farm_tpf/presentation/custom_widgets/bottom_loader.dart'; | |||
| import 'package:farm_tpf/presentation/custom_widgets/loading_list_page.dart'; | |||
| @@ -12,14 +6,11 @@ import 'package:farm_tpf/presentation/screens/plot/widget_search.dart'; | |||
| import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart'; | |||
| import 'package:farm_tpf/utils/const_assets.dart'; | |||
| import 'package:farm_tpf/utils/const_color.dart'; | |||
| import 'package:farm_tpf/utils/const_common.dart'; | |||
| import 'package:farm_tpf/utils/pref.dart'; | |||
| import 'package:firebase_messaging/firebase_messaging.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:flutter_bloc/flutter_bloc.dart'; | |||
| import 'package:farm_tpf/utils/const_string.dart'; | |||
| import 'package:farm_tpf/utils/formatter.dart'; | |||
| import 'package:get/get.dart'; | |||
| import 'bloc/plot_bloc.dart'; | |||
| @@ -29,106 +20,15 @@ class PlotListScreen extends StatefulWidget { | |||
| } | |||
| class _PlotListScreenState extends State<PlotListScreen> { | |||
| UserRepository _userRepository = UserRepository(); | |||
| final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); | |||
| var pref = LocalPref(); | |||
| var token; | |||
| var client; | |||
| String pushkey = ""; | |||
| String currentFullName = ""; | |||
| Future<Null> getSharedPrefs() async { | |||
| token = await pref.getString(DATA_CONST.TOKEN_KEY); | |||
| pushkey = await pref.getString(DATA_CONST.PUSH_KEY); | |||
| currentFullName = await pref.getString(DATA_CONST.CURRENT_FULL_NAME); | |||
| var options = BaseOptions(baseUrl: ConstCommon.baseUrl); | |||
| options.headers["Authorization"] = "Bearer $token"; | |||
| client = Dio(options); | |||
| if (Platform.isIOS) { | |||
| _firebaseMessaging | |||
| .requestNotificationPermissions(IosNotificationSettings()); | |||
| } | |||
| _firebaseMessaging.configure( | |||
| onMessage: (Map<String, dynamic> message) async { | |||
| print("onMessage---: $message"); | |||
| }, | |||
| onBackgroundMessage: Platform.isIOS ? null : myBackgroundMessageHandler, | |||
| onLaunch: (Map<String, dynamic> message) async { | |||
| print("onLaunch: $message"); | |||
| Future.delayed(Duration(milliseconds: 500), () { | |||
| _notificationNavigateOnFCM(message); | |||
| }); | |||
| }, | |||
| onResume: (Map<String, dynamic> message) async { | |||
| print("onResume: $message"); | |||
| _notificationNavigateOnFCM(message); | |||
| }, | |||
| ); | |||
| _firebaseMessaging.requestNotificationPermissions( | |||
| const IosNotificationSettings( | |||
| sound: true, badge: true, alert: true, provisional: true)); | |||
| _firebaseMessaging.onIosSettingsRegistered | |||
| .listen((IosNotificationSettings settings) { | |||
| print("Settings registered: $settings"); | |||
| }); | |||
| if (pushkey?.isEmpty ?? true) { | |||
| _firebaseMessaging.getToken().then((String token) { | |||
| assert(token != null); | |||
| print("Push Messaging token: $token"); | |||
| _userRepository.updateFcmToken(token).then((value) { | |||
| print("send push key successful"); | |||
| pref.saveString(DATA_CONST.PUSH_KEY, token); | |||
| }); | |||
| // client.put(""); | |||
| }); | |||
| } else { | |||
| print("Don't need get push key"); | |||
| } | |||
| if (currentFullName?.isEmpty ?? true) { | |||
| try { | |||
| var currentUser = await _userRepository.getUser(); | |||
| pref.saveString(DATA_CONST.CURRENT_FULL_NAME, currentUser.fullName); | |||
| print("fullname: ${currentUser.fullName}"); | |||
| } catch (e) { | |||
| print("error: ${e.toString()}"); | |||
| } | |||
| } | |||
| } | |||
| _notificationNavigateOnFCM(Map<String, dynamic> message) { | |||
| //parse data difference between Ios and Android | |||
| var noti; | |||
| if (Platform.isAndroid) { | |||
| var data = message['data']; | |||
| noti = NotificationDTO() | |||
| ..contents = data['contents'] | |||
| ..tbCropId = data['tbCropId'] | |||
| ..type = data['type']; | |||
| } else { | |||
| noti = NotificationDTO.fromJson(message); | |||
| } | |||
| if (noti.contents == "ENV_UPDATE") { | |||
| Get.to(PlotDetailScreen( | |||
| cropType: noti.type, | |||
| cropId: noti.tbCropId, | |||
| initialIndex: 0, | |||
| )); | |||
| } else if (noti.contents == "PIC_UPDATE") { | |||
| Get.to(PlotDetailScreen( | |||
| cropType: noti.type, | |||
| cropId: noti.tbCropId, | |||
| initialIndex: 1, | |||
| )); | |||
| } else { | |||
| //Go home | |||
| } | |||
| } | |||
| @override | |||
| void initState() { | |||
| super.initState(); | |||
| // getSharedPrefs(); | |||
| } | |||
| @override | |||
| @@ -2,7 +2,6 @@ import 'dart:io'; | |||
| import 'package:badges/badges.dart'; | |||
| import 'package:dio/dio.dart'; | |||
| import 'package:farm_tpf/custom_model/NotificationDTO.dart'; | |||
| import 'package:farm_tpf/custom_model/NotificationObjectDTO.dart'; | |||
| import 'package:farm_tpf/data/repository/user_repository.dart'; | |||
| import 'package:farm_tpf/presentation/screens/account/sc_account.dart'; | |||
| @@ -11,6 +10,7 @@ import 'package:farm_tpf/presentation/screens/notification/sc_notification.dart' | |||
| import 'package:farm_tpf/presentation/screens/notification/update_count_noti_bloc.dart'; | |||
| import 'package:farm_tpf/presentation/screens/plot/sc_plot.dart'; | |||
| import 'package:farm_tpf/presentation/screens/plot_detail/sc_plot_detail.dart'; | |||
| import 'package:farm_tpf/utils/NotificationsBloc.dart'; | |||
| import 'package:farm_tpf/utils/const_color.dart'; | |||
| import 'package:farm_tpf/utils/const_common.dart'; | |||
| import 'package:farm_tpf/utils/const_icons.dart'; | |||
| @@ -32,6 +32,7 @@ class TabbarScreen extends StatefulWidget { | |||
| } | |||
| class _TabbarScreenState extends State<TabbarScreen> { | |||
| Stream<LocalNotification> _notificationsStream; | |||
| UserRepository _userRepository = UserRepository(); | |||
| final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); | |||
| var pref = LocalPref(); | |||
| @@ -67,10 +68,25 @@ class _TabbarScreenState extends State<TabbarScreen> { | |||
| } | |||
| _firebaseMessaging.configure( | |||
| onMessage: (Map<String, dynamic> message) async { | |||
| print("onMessage---: $message"); | |||
| print("onMessage--tabbar-: $message"); | |||
| try { | |||
| print('call bloc update noti'); | |||
| final String type = message['tbCropType']; | |||
| final String contents = message['contents']; | |||
| final String tbCropId = message['tbCropId']; | |||
| updateCountNotiBloc.getNotifications((data) {}, (err) {}); | |||
| final notification = LocalNotification(type, contents, tbCropId); | |||
| NotificationsBloc.instance.newNotification(notification); | |||
| if (contents == "ENV_UPDATE") { | |||
| if (Get.isSnackbarOpen) Get.back(); | |||
| Get.snackbar(null, 'Thông số môi trường được cập nhật'); | |||
| } else if (contents == "PIC_UPDATE") { | |||
| if (Get.isSnackbarOpen) Get.back(); | |||
| Get.snackbar(null, 'Người phụ trách được cập nhật'); | |||
| } else { | |||
| //Go home | |||
| } | |||
| } catch (e) { | |||
| print('error'); | |||
| print(e); | |||
| @@ -80,11 +96,13 @@ class _TabbarScreenState extends State<TabbarScreen> { | |||
| onLaunch: (Map<String, dynamic> message) async { | |||
| print("onLaunch: $message"); | |||
| Future.delayed(Duration(milliseconds: 500), () { | |||
| updateCountNotiBloc.getNotifications((data) {}, (err) {}); | |||
| _notificationNavigateOnFCM(message); | |||
| }); | |||
| }, | |||
| onResume: (Map<String, dynamic> message) async { | |||
| print("onResume: $message"); | |||
| updateCountNotiBloc.getNotifications((data) {}, (err) {}); | |||
| _notificationNavigateOnFCM(message); | |||
| }, | |||
| ); | |||
| @@ -126,23 +144,28 @@ class _TabbarScreenState extends State<TabbarScreen> { | |||
| getSharedPrefs(); | |||
| changeTabbar.initValue(); | |||
| updateCountNotiBloc.getNotifications((data) {}, (err) {}); | |||
| _notificationsStream = NotificationsBloc.instance.notificationsStream; | |||
| _notificationsStream.listen((notification) { | |||
| updateCountNotiBloc.getNotifications((data) {}, (err) {}); | |||
| print('Notification: $notification'); | |||
| }); | |||
| } | |||
| _notificationNavigateOnFCM(Map<String, dynamic> message) { | |||
| try { | |||
| final int type = message['tbCropType']; | |||
| final String type = message['tbCropType']; | |||
| final String contents = message['contents']; | |||
| final int tbCropId = message['tbCropId']; | |||
| final String tbCropId = message['tbCropId']; | |||
| if (contents == "ENV_UPDATE") { | |||
| Get.to(PlotDetailScreen( | |||
| cropType: type, | |||
| cropId: tbCropId, | |||
| cropType: int.parse(type), | |||
| cropId: int.parse(tbCropId), | |||
| initialIndex: 0, | |||
| )); | |||
| } else if (contents == "PIC_UPDATE") { | |||
| Get.to(PlotDetailScreen( | |||
| cropType: type, | |||
| cropId: tbCropId, | |||
| cropType: int.parse(type), | |||
| cropId: int.parse(tbCropId), | |||
| initialIndex: 1, | |||
| )); | |||
| } else { | |||
| @@ -0,0 +1,30 @@ | |||
| import 'package:rxdart/rxdart.dart'; | |||
| class LocalNotification { | |||
| final String type; | |||
| final String contents; | |||
| final String tbCropId; | |||
| LocalNotification(this.type, this.contents, this.tbCropId); | |||
| } | |||
| class NotificationsBloc { | |||
| NotificationsBloc._internal(); | |||
| static final NotificationsBloc instance = NotificationsBloc._internal(); | |||
| final BehaviorSubject<LocalNotification> _notificationsStreamController = | |||
| BehaviorSubject<LocalNotification>(); | |||
| Stream<LocalNotification> get notificationsStream { | |||
| return _notificationsStreamController; | |||
| } | |||
| void newNotification(LocalNotification notification) { | |||
| _notificationsStreamController.sink.add(notification); | |||
| } | |||
| void dispose() { | |||
| _notificationsStreamController?.close(); | |||
| } | |||
| } | |||