| @@ -0,0 +1,58 @@ | |||
| class NotificationDTO { | |||
| int id; | |||
| String subject; | |||
| String message; | |||
| int tbCropId; | |||
| int tbEntityId; | |||
| String contents; | |||
| String createdDate; | |||
| String sendDate; | |||
| int isRead; | |||
| NotificationDTO( | |||
| {this.id, | |||
| this.subject, | |||
| this.message, | |||
| this.tbCropId, | |||
| this.tbEntityId, | |||
| this.contents, | |||
| this.createdDate, | |||
| this.sendDate, | |||
| this.isRead}); | |||
| NotificationDTO.clone(NotificationDTO noti) { | |||
| this.id = noti.id; | |||
| this.contents = noti.contents; | |||
| this.tbCropId = noti.tbCropId; | |||
| this.tbEntityId = noti.tbEntityId; | |||
| this.subject = noti.subject; | |||
| this.message = noti.message; | |||
| this.createdDate = noti.createdDate; | |||
| this.sendDate = noti.sendDate; | |||
| this.isRead = noti.isRead; | |||
| } | |||
| NotificationDTO.fromJson(Map<String, dynamic> json) { | |||
| id = json['id']; | |||
| subject = json['subject']; | |||
| message = json['message']; | |||
| tbCropId = json['tbCropId']; | |||
| tbEntityId = json['tbEntityId']; | |||
| contents = json['contents']; | |||
| createdDate = json['createdDate']; | |||
| sendDate = json['sendDate']; | |||
| isRead = json['isRead']; | |||
| } | |||
| Map<String, dynamic> toJson() { | |||
| final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
| data['id'] = this.id; | |||
| data['subject'] = this.subject; | |||
| data['message'] = this.message; | |||
| data['tbCropId'] = this.tbCropId; | |||
| data['tbEntityId'] = this.tbEntityId; | |||
| data['contents'] = this.contents; | |||
| data['createdDate'] = this.createdDate; | |||
| data['sendDate'] = this.sendDate; | |||
| data['isRead'] = this.isRead; | |||
| return data; | |||
| } | |||
| } | |||
| @@ -0,0 +1,42 @@ | |||
| import 'NotificationDTO.dart'; | |||
| class NotificationObjectDTO { | |||
| int numberUnreadPage; | |||
| int numberReadPage; | |||
| int numberUnreadTotal; | |||
| int numberReadTotal; | |||
| List<NotificationDTO> notificationDTO; | |||
| NotificationObjectDTO( | |||
| {this.numberUnreadPage, | |||
| this.numberReadPage, | |||
| this.numberUnreadTotal, | |||
| this.numberReadTotal, | |||
| this.notificationDTO}); | |||
| NotificationObjectDTO.fromJson(Map<String, dynamic> json) { | |||
| numberUnreadPage = json['numberUnreadPage']; | |||
| numberReadPage = json['numberReadPage']; | |||
| numberUnreadTotal = json['numberUnreadTotal']; | |||
| numberReadTotal = json['numberReadTotal']; | |||
| if (json['tbnotificationDTOs'] != null) { | |||
| notificationDTO = new List<NotificationDTO>(); | |||
| json['tbnotificationDTOs'].forEach((v) { | |||
| notificationDTO.add(new NotificationDTO.fromJson(v)); | |||
| }); | |||
| } | |||
| } | |||
| Map<String, dynamic> toJson() { | |||
| final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
| data['numberUnreadPage'] = this.numberUnreadPage; | |||
| data['numberReadPage'] = this.numberReadPage; | |||
| data['numberUnreadTotal'] = this.numberUnreadTotal; | |||
| data['numberReadTotal'] = this.numberReadTotal; | |||
| if (this.notificationDTO != null) { | |||
| data['tbnotificationDTOs'] = | |||
| this.notificationDTO.map((v) => v.toJson()).toList(); | |||
| } | |||
| return data; | |||
| } | |||
| } | |||
| @@ -0,0 +1,18 @@ | |||
| class UpdateNoti { | |||
| int id; | |||
| int isRead; | |||
| UpdateNoti({this.id, this.isRead}); | |||
| UpdateNoti.fromJson(Map<String, dynamic> json) { | |||
| id = json['id']; | |||
| isRead = json['isRead']; | |||
| } | |||
| Map<String, dynamic> toJson() { | |||
| final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
| data['id'] = this.id; | |||
| data['isRead'] = this.isRead; | |||
| return data; | |||
| } | |||
| } | |||
| @@ -36,14 +36,14 @@ class HttpLogInterceptor extends InterceptorsWrapper { | |||
| @override | |||
| Future onResponse(Response response) { | |||
| // log("onResponse: $response"); | |||
| log("onResponse: $response"); | |||
| return super.onResponse(response); | |||
| } | |||
| @override | |||
| Future onError(DioError err) { | |||
| // log("onError: $err\n" | |||
| // "Response: ${err.response}"); | |||
| log("onError: $err\n" | |||
| "Response: ${err.response}"); | |||
| return super.onError(err); | |||
| } | |||
| } | |||
| @@ -4,6 +4,7 @@ import 'package:farm_tpf/custom_model/Device.dart'; | |||
| import 'package:farm_tpf/custom_model/EnvironmentParameter.dart'; | |||
| import 'package:farm_tpf/custom_model/Harvest.dart'; | |||
| import 'package:farm_tpf/custom_model/Supply.dart'; | |||
| import 'package:farm_tpf/custom_model/UpdateNoti.dart'; | |||
| import 'package:farm_tpf/custom_model/WaterType.dart'; | |||
| import 'package:farm_tpf/custom_model/account.dart'; | |||
| import 'package:farm_tpf/custom_model/password.dart'; | |||
| @@ -63,6 +64,12 @@ abstract class RestClient { | |||
| @GET("/api/listDeviceForActivity") | |||
| Future<List<Device>> getDeviceForActivity({@DioOptions() Options options}); | |||
| @PUT("/api/notifications/update-all") | |||
| Future<void> updateAllNotification(@Body() String status); | |||
| @PUT("/api/notifications/update") | |||
| Future<void> updateNoti(@Body() UpdateNoti updateNoti); | |||
| //Crop | |||
| @GET( | |||
| "/api/tb-crops-detail-for-app/{cropId}?page={page}&size={size}&sort=executeDate,DESC") | |||
| @@ -282,6 +282,41 @@ class _RestClient implements RestClient { | |||
| return value; | |||
| } | |||
| @override | |||
| updateAllNotification(status) async { | |||
| ArgumentError.checkNotNull(status, 'status'); | |||
| const _extra = <String, dynamic>{}; | |||
| final queryParameters = <String, dynamic>{}; | |||
| final _data = status; | |||
| await _dio.request<void>('/api/notifications/update-all', | |||
| queryParameters: queryParameters, | |||
| options: RequestOptions( | |||
| method: 'PUT', | |||
| headers: <String, dynamic>{}, | |||
| extra: _extra, | |||
| baseUrl: baseUrl), | |||
| data: _data); | |||
| return null; | |||
| } | |||
| @override | |||
| updateNoti(updateNoti) async { | |||
| ArgumentError.checkNotNull(updateNoti, 'updateNoti'); | |||
| const _extra = <String, dynamic>{}; | |||
| final queryParameters = <String, dynamic>{}; | |||
| final _data = <String, dynamic>{}; | |||
| _data.addAll(updateNoti?.toJson() ?? <String, dynamic>{}); | |||
| await _dio.request<void>('/api/notifications/update', | |||
| queryParameters: queryParameters, | |||
| options: RequestOptions( | |||
| method: 'PUT', | |||
| headers: <String, dynamic>{}, | |||
| extra: _extra, | |||
| baseUrl: baseUrl), | |||
| data: _data); | |||
| return null; | |||
| } | |||
| @override | |||
| getCropDetail(cropId, {page = 0, size = 20}) async { | |||
| ArgumentError.checkNotNull(cropId, 'cropId'); | |||
| @@ -6,7 +6,10 @@ import 'package:farm_tpf/custom_model/CropPlot.dart'; | |||
| import 'package:farm_tpf/custom_model/Device.dart'; | |||
| import 'package:farm_tpf/custom_model/EnvironmentParameter.dart'; | |||
| import 'package:farm_tpf/custom_model/Harvest.dart'; | |||
| import 'package:farm_tpf/custom_model/NotificationDTO.dart'; | |||
| import 'package:farm_tpf/custom_model/NotificationObjectDTO.dart'; | |||
| import 'package:farm_tpf/custom_model/Supply.dart'; | |||
| import 'package:farm_tpf/custom_model/UpdateNoti.dart'; | |||
| import 'package:farm_tpf/custom_model/WaterType.dart'; | |||
| import 'package:farm_tpf/custom_model/user.dart'; | |||
| import 'package:farm_tpf/custom_model/user_request.dart'; | |||
| @@ -92,6 +95,26 @@ class Repository { | |||
| return client.getDeviceForActivity(options: op); | |||
| } | |||
| Future<void> updateAllNotification(String status) { | |||
| final client = RestClient(dio); | |||
| return client.updateAllNotification(status); | |||
| } | |||
| Future<void> updateNoti(UpdateNoti updateNoti) { | |||
| final client = RestClient(dio); | |||
| return client.updateNoti(updateNoti); | |||
| } | |||
| Future<NotificationObjectDTO> getNotifications( | |||
| {int page = 0, int size = 20}) async { | |||
| var url = ConstCommon.baseUrl + | |||
| "/api/notifications-current-user?page=$page&size=$size&sort=sendDate,DESC"; | |||
| var response = await dio.get(url); | |||
| final value = NotificationObjectDTO.fromJson(response.data); | |||
| return value; | |||
| } | |||
| Object getInstanceClass() { | |||
| var instanceClass; | |||
| if (1 == 1) { | |||
| @@ -0,0 +1,134 @@ | |||
| import 'dart:async'; | |||
| import 'package:bloc/bloc.dart'; | |||
| import 'package:equatable/equatable.dart'; | |||
| import 'package:farm_tpf/custom_model/NotificationDTO.dart'; | |||
| import 'package:farm_tpf/custom_model/NotificationObjectDTO.dart'; | |||
| import 'package:farm_tpf/custom_model/UpdateNoti.dart'; | |||
| import 'package:farm_tpf/data/api/app_exception.dart'; | |||
| import 'package:farm_tpf/data/repository/repository.dart'; | |||
| import 'package:farm_tpf/utils/const_string.dart'; | |||
| import 'package:meta/meta.dart'; | |||
| part 'noti_event.dart'; | |||
| part 'noti_state.dart'; | |||
| class NotiBloc extends Bloc<NotiEvent, NotiState> { | |||
| final Repository repository; | |||
| NotiBloc({@required this.repository}) : super(NotiInitial()); | |||
| static int pageSize = 20; | |||
| @override | |||
| Stream<NotiState> mapEventToState( | |||
| NotiEvent event, | |||
| ) async* { | |||
| if (event is DataFetched && | |||
| !(state is NotiSuccess && (state as NotiSuccess).hasReachedMax)) { | |||
| try { | |||
| if (state is NotiInitial) { | |||
| yield NotiLoadding(); | |||
| final response = | |||
| await repository.getNotifications(page: 0, size: pageSize); | |||
| yield NotiSuccess( | |||
| unread: response.numberUnreadTotal, | |||
| read: response.numberReadTotal, | |||
| items: response.notificationDTO, | |||
| page: 0, | |||
| hasReachedMax: | |||
| response.notificationDTO.length < pageSize ? true : false); | |||
| } | |||
| if (state is NotiSuccess) { | |||
| final currentState = state as NotiSuccess; | |||
| int page = currentState.page + 1; | |||
| final response = | |||
| await repository.getNotifications(page: page, size: pageSize); | |||
| yield response.notificationDTO.isEmpty | |||
| ? currentState.copyWith(hasReachedMax: true) | |||
| : NotiSuccess( | |||
| unread: response.numberUnreadTotal, | |||
| read: response.numberReadTotal, | |||
| items: currentState.items + response.notificationDTO, | |||
| page: currentState.page + 1, | |||
| hasReachedMax: false); | |||
| } | |||
| } catch (e) { | |||
| yield NotiFailure(errorString: AppException.handleError(e)); | |||
| } | |||
| } | |||
| if (event is OnRefresh) { | |||
| yield NotiLoadding(); | |||
| try { | |||
| final response = | |||
| await repository.getNotifications(page: 0, size: pageSize); | |||
| List<NotificationDTO> items = new List<NotificationDTO>(); | |||
| response.notificationDTO | |||
| .forEach((e) => items.add(NotificationDTO.clone(e))); | |||
| yield NotiSuccess( | |||
| unread: response.numberUnreadTotal, | |||
| read: response.numberReadTotal, | |||
| items: items, | |||
| page: 0, | |||
| hasReachedMax: | |||
| response.notificationDTO.length < pageSize ? true : false); | |||
| } catch (e) { | |||
| yield NotiFailure(errorString: AppException.handleError(e)); | |||
| } | |||
| } | |||
| if (event is OnUpdate) { | |||
| yield NotiLoadding(); | |||
| try { | |||
| //Change status notification if mark read | |||
| if (event.currentItemId != null) { | |||
| var updateNoti = UpdateNoti() | |||
| ..id = event.currentItemId | |||
| ..isRead = 1; | |||
| await repository.updateNoti(updateNoti); | |||
| } | |||
| yield NotiSuccess( | |||
| unread: event.unread, | |||
| read: event.read, | |||
| items: event.currentItems, | |||
| page: event.currentPage, | |||
| hasReachedMax: event.hasReachedMax); | |||
| } catch (e) { | |||
| yield NotiFailure(errorString: exception_common); | |||
| } | |||
| } else if (event is MarkAllNotificationUpdate) { | |||
| yield NotiLoadding(); | |||
| try { | |||
| await repository.updateAllNotification(event.status); | |||
| final response = | |||
| await repository.getNotifications(page: 0, size: pageSize); | |||
| List<NotificationDTO> items = new List<NotificationDTO>(); | |||
| response.notificationDTO | |||
| .forEach((e) => items.add(NotificationDTO.clone(e))); | |||
| yield NotiSuccess( | |||
| unread: response.numberUnreadTotal, | |||
| read: response.numberReadTotal, | |||
| items: items, | |||
| page: 0, | |||
| hasReachedMax: | |||
| response.notificationDTO.length < pageSize ? true : false); | |||
| } catch (e) { | |||
| yield NotiFailure(errorString: exception_common); | |||
| } | |||
| } else if (event is ReceiveDataFromSocket) { | |||
| List<NotificationDTO> updatedItems = new List<NotificationDTO>(); | |||
| event.updatedItemObject.notificationDTO.forEach((e) { | |||
| updatedItems.add(NotificationDTO.clone(e)); | |||
| }); | |||
| event.currentItems.forEach((e) { | |||
| updatedItems.add(NotificationDTO.clone(e)); | |||
| }); | |||
| yield NotiSuccess( | |||
| unread: event.updatedItemObject.numberUnreadTotal, | |||
| read: event.updatedItemObject.numberReadTotal, | |||
| items: updatedItems, | |||
| page: event.page, | |||
| hasReachedMax: updatedItems.length < pageSize ? true : false); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,45 @@ | |||
| part of 'noti_bloc.dart'; | |||
| abstract class NotiEvent extends Equatable { | |||
| const NotiEvent(); | |||
| @override | |||
| List<Object> get props => []; | |||
| } | |||
| class DataFetched extends NotiEvent {} | |||
| class OnRefresh extends NotiEvent {} | |||
| class OnUpdate<T> extends NotiEvent { | |||
| final int unread; | |||
| final int read; | |||
| final int currentItemId; | |||
| final List<T> currentItems; | |||
| final int currentPage; | |||
| final bool hasReachedMax; | |||
| OnUpdate( | |||
| {@required this.unread, | |||
| @required this.read, | |||
| this.currentItemId, | |||
| @required this.currentItems, | |||
| @required this.currentPage, | |||
| @required this.hasReachedMax}); | |||
| } | |||
| class MarkAllNotificationUpdate extends NotiEvent { | |||
| final String status; | |||
| MarkAllNotificationUpdate({@required this.status}); | |||
| } | |||
| class ReceiveDataFromSocket extends NotiEvent { | |||
| final List<NotificationDTO> currentItems; | |||
| final int page; | |||
| final bool hasReachedMax; | |||
| final NotificationObjectDTO updatedItemObject; | |||
| ReceiveDataFromSocket( | |||
| {@required this.currentItems, | |||
| this.page, | |||
| this.hasReachedMax, | |||
| this.updatedItemObject}); | |||
| } | |||
| @@ -0,0 +1,40 @@ | |||
| part of 'noti_bloc.dart'; | |||
| abstract class NotiState extends Equatable { | |||
| const NotiState(); | |||
| @override | |||
| List<Object> get props => []; | |||
| } | |||
| class NotiInitial extends NotiState {} | |||
| class NotiLoadding extends NotiState {} | |||
| class NotiFailure extends NotiState { | |||
| final String errorString; | |||
| NotiFailure({@required this.errorString}); | |||
| } | |||
| class NotiSuccess<T> extends NotiState { | |||
| final int unread; | |||
| final int read; | |||
| final List<T> items; | |||
| final int page; | |||
| final bool hasReachedMax; | |||
| const NotiSuccess( | |||
| {this.unread, this.read, this.items, this.page, this.hasReachedMax}); | |||
| NotiSuccess copyWith({List<T> items, int page, bool hasReachedMax}) { | |||
| return NotiSuccess( | |||
| unread: unread ?? this.unread, | |||
| read: read ?? this.read, | |||
| items: items ?? this.items, | |||
| page: page ?? this.page, | |||
| hasReachedMax: hasReachedMax ?? this.hasReachedMax); | |||
| } | |||
| @override | |||
| List<Object> get props => [items, hasReachedMax]; | |||
| } | |||
| @@ -1,4 +1,15 @@ | |||
| import 'package:farm_tpf/custom_model/NotificationDTO.dart'; | |||
| import 'package:farm_tpf/data/repository/repository.dart'; | |||
| import 'package:farm_tpf/presentation/custom_widgets/bottom_loader.dart'; | |||
| import 'package:farm_tpf/presentation/custom_widgets/loading_list_page.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/utils/pref.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:flutter_bloc/flutter_bloc.dart'; | |||
| import 'package:farm_tpf/utils/formatter.dart'; | |||
| import 'bloc/noti_bloc.dart'; | |||
| class NotificationScreen extends StatefulWidget { | |||
| @override | |||
| @@ -6,12 +17,306 @@ class NotificationScreen extends StatefulWidget { | |||
| } | |||
| class _NotificationScreenState extends State<NotificationScreen> { | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return BlocProvider( | |||
| create: (context) => | |||
| NotiBloc(repository: Repository())..add(DataFetched()), | |||
| child: HoldInfinityWidget(), | |||
| ); | |||
| } | |||
| } | |||
| class HoldInfinityWidget extends StatelessWidget { | |||
| final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>(); | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return Scaffold( | |||
| appBar: AppBar( | |||
| title: Text("Thông báo"), | |||
| key: _scaffoldKey, | |||
| appBar: AppBar( | |||
| centerTitle: true, | |||
| title: Text("Thông báo"), | |||
| actions: <Widget>[ | |||
| IconButton( | |||
| icon: Icon(Icons.done_all), | |||
| onPressed: () { | |||
| BlocProvider.of<NotiBloc>(context) | |||
| .add(MarkAllNotificationUpdate(status: "1")); | |||
| }) | |||
| ], | |||
| ), | |||
| body: InfinityView()); | |||
| } | |||
| } | |||
| class InfinityView extends StatefulWidget { | |||
| @override | |||
| _InfinityViewState createState() => _InfinityViewState(); | |||
| } | |||
| class _InfinityViewState extends State<InfinityView> { | |||
| final _scrollController = ScrollController(); | |||
| final _scrollThreshold = 250.0; | |||
| NotiBloc _notiBloc; | |||
| List<NotificationDTO> currentItems = new List<NotificationDTO>(); | |||
| int latestId = 0; | |||
| int currentPage = 0; | |||
| bool currentHasReachedMax = true; | |||
| bool isUpdatingFromApi = true; | |||
| var pref = LocalPref(); | |||
| // final SocketService socketService = injector.get<SocketService>(); | |||
| var token; | |||
| Future<Null> getSharedPrefs() async { | |||
| _scrollController.addListener(() { | |||
| final maxScroll = _scrollController.position.maxScrollExtent; | |||
| final currentScroll = _scrollController.position.pixels; | |||
| if (maxScroll - currentScroll < _scrollThreshold) { | |||
| _notiBloc.add(DataFetched()); | |||
| } | |||
| }); | |||
| token = await pref.getString(DATA_CONST.TOKEN_KEY); | |||
| // socketService.initial(token); | |||
| _notiBloc = BlocProvider.of<NotiBloc>(context); | |||
| } | |||
| @override | |||
| void initState() { | |||
| getSharedPrefs(); | |||
| super.initState(); | |||
| } | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return BlocConsumer<NotiBloc, NotiState>( | |||
| listener: (context, state) { | |||
| //Handle Socket | |||
| /* | |||
| if (state is NotiLoadding) { | |||
| isUpdatingFromApi = true; | |||
| } | |||
| if (state is NotiSuccess) { | |||
| currentItems = List<NotificationDTO>.from(state.items); | |||
| latestId = int.parse(currentItems[0].id) > latestId | |||
| ? int.parse(currentItems[0].id) | |||
| : latestId; | |||
| socketService.createSocketNotificationConnection(latestId, (data) { | |||
| print("receive data"); | |||
| if (isUpdatingFromApi == false) { | |||
| print("Update from socket"); | |||
| var notis = | |||
| NotificationObjectDTO.fromJson(data, NotificationDTO()); | |||
| _notiBloc.add(ReceiveDataFromSocket( | |||
| currentItems: currentItems, | |||
| page: currentPage, | |||
| hasReachedMax: currentHasReachedMax, | |||
| updatedItemObject: notis)); | |||
| } else { | |||
| //dont need update from socket | |||
| print("dont need update from socket"); | |||
| } | |||
| }, (error) {}); | |||
| isUpdatingFromApi = false; | |||
| } | |||
| */ | |||
| }, | |||
| builder: (context, state) { | |||
| if (state is NotiFailure) { | |||
| return Center(child: Text(state.errorString)); | |||
| } | |||
| if (state is NotiSuccess) { | |||
| if (state.items.isEmpty) { | |||
| return Center(child: Text("Dữ liệu rỗng")); | |||
| } | |||
| currentItems = List<NotificationDTO>.from(state.items); | |||
| currentPage = state.page; | |||
| currentHasReachedMax = state.hasReachedMax; | |||
| return Column( | |||
| children: <Widget>[ | |||
| Container( | |||
| child: | |||
| countNotification(unread: state.unread, read: state.read), | |||
| ), | |||
| Expanded( | |||
| child: RefreshIndicator( | |||
| child: ListView.builder( | |||
| itemBuilder: (BuildContext context, int index) { | |||
| return index >= state.items.length | |||
| ? BottomLoader() | |||
| : ItemInfinityWidget( | |||
| unread: state.unread, | |||
| read: state.read, | |||
| currentItems: currentItems, | |||
| item: state.items[index], | |||
| currentPage: state.page, | |||
| currentReachedMax: state.hasReachedMax, | |||
| ); | |||
| }, | |||
| itemCount: state.hasReachedMax | |||
| ? state.items.length | |||
| : state.items.length + 1, | |||
| controller: _scrollController, | |||
| ), | |||
| onRefresh: () async { | |||
| _notiBloc.add(OnRefresh()); | |||
| })) | |||
| ], | |||
| ); | |||
| } | |||
| return Center( | |||
| child: LoadingListPage(), | |||
| ); | |||
| }, | |||
| ); | |||
| } | |||
| Widget countNotification({num unread, num read}) { | |||
| return Container( | |||
| child: Row( | |||
| mainAxisAlignment: MainAxisAlignment.center, | |||
| mainAxisSize: MainAxisSize.max, | |||
| children: <Widget>[ | |||
| Expanded( | |||
| child: OutlineButton( | |||
| child: RichText( | |||
| text: TextSpan( | |||
| text: "Chưa đọc ", | |||
| style: TextStyle( | |||
| color: Colors.black, fontWeight: FontWeight.bold), | |||
| children: <TextSpan>[ | |||
| TextSpan( | |||
| text: "($unread)", | |||
| style: TextStyle(color: Colors.blue)), | |||
| ])), | |||
| onPressed: () {})), | |||
| Expanded( | |||
| child: OutlineButton( | |||
| child: RichText( | |||
| text: TextSpan( | |||
| text: "Đã đọc ", | |||
| style: TextStyle( | |||
| color: Colors.black, fontWeight: FontWeight.bold), | |||
| children: <TextSpan>[ | |||
| TextSpan( | |||
| text: "($read)", | |||
| style: TextStyle(color: Colors.grey)), | |||
| ])), | |||
| onPressed: () {})) | |||
| ], | |||
| ), | |||
| ); | |||
| } | |||
| @override | |||
| void dispose() { | |||
| _scrollController.dispose(); | |||
| // socketService.disconnect(); | |||
| super.dispose(); | |||
| } | |||
| } | |||
| class ItemInfinityWidget extends StatelessWidget { | |||
| final int unread; | |||
| final int read; | |||
| final NotificationDTO item; | |||
| final List<NotificationDTO> currentItems; | |||
| final int currentPage; | |||
| final bool currentReachedMax; | |||
| const ItemInfinityWidget( | |||
| {Key key, | |||
| @required this.unread, | |||
| @required this.read, | |||
| @required this.currentItems, | |||
| @required this.item, | |||
| @required this.currentPage, | |||
| @required this.currentReachedMax}) | |||
| : super(key: key); | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return GestureDetector( | |||
| child: Card( | |||
| margin: EdgeInsets.all(4.0), | |||
| child: ListTile( | |||
| title: Text(item.subject), | |||
| subtitle: Column( | |||
| crossAxisAlignment: CrossAxisAlignment.start, | |||
| children: <Widget>[ | |||
| Text(item.message), | |||
| Text( | |||
| item.sendDate.format_DDMMYY_HHmm(), | |||
| style: TextStyle( | |||
| color: item.isRead == 1 ? Colors.grey : Colors.blue), | |||
| ), | |||
| ], | |||
| ), | |||
| leading: Icon( | |||
| Icons.notifications_active, | |||
| color: item.isRead == 1 ? Colors.grey : Colors.blue, | |||
| ))), | |||
| onTap: () { | |||
| if (item.contents == "ENV_UPDATE") { | |||
| Navigator.push( | |||
| context, | |||
| MaterialPageRoute( | |||
| builder: (BuildContext context) => | |||
| PlotDetailScreen(cropId: item.tbCropId))).then((value) { | |||
| if (item.isRead == 0) { | |||
| _updateReadNotification( | |||
| context: context, | |||
| unread: unread, | |||
| read: read, | |||
| item: item, | |||
| currentItems: currentItems, | |||
| currentPage: currentPage, | |||
| currentReachedMax: currentReachedMax); | |||
| } | |||
| }); | |||
| } else if (item.contents == "PIC_UPDATE") { | |||
| Navigator.push( | |||
| context, | |||
| MaterialPageRoute( | |||
| builder: (BuildContext context) => PlotInformationScreen( | |||
| cropId: item.tbCropId, | |||
| ))).then((value) { | |||
| if (item.isRead == 0) { | |||
| _updateReadNotification( | |||
| context: context, | |||
| unread: unread, | |||
| read: read, | |||
| item: item, | |||
| currentItems: currentItems, | |||
| currentPage: currentPage, | |||
| currentReachedMax: currentReachedMax); | |||
| } | |||
| }); | |||
| } else {} | |||
| }); | |||
| } | |||
| _updateReadNotification( | |||
| {BuildContext context, | |||
| int unread, | |||
| int read, | |||
| NotificationDTO item, | |||
| List<NotificationDTO> currentItems, | |||
| int currentPage, | |||
| bool currentReachedMax}) { | |||
| List<NotificationDTO> updatedItems = new List<NotificationDTO>(); | |||
| currentItems.forEach((e) { | |||
| if (e.id == item.id) { | |||
| e.isRead = 1; | |||
| } else {} | |||
| updatedItems.add(NotificationDTO.clone(e)); | |||
| }); | |||
| BlocProvider.of<NotiBloc>(context).add(OnUpdate<NotificationDTO>( | |||
| unread: unread - 1, | |||
| read: read + 1, | |||
| currentItemId: item.id, | |||
| currentItems: updatedItems, | |||
| currentPage: currentPage, | |||
| hasReachedMax: currentReachedMax)); | |||
| } | |||
| } | |||