| class Device { | |||||
| int id; | |||||
| String name; | |||||
| String status; | |||||
| String location; | |||||
| Device({this.id, this.name, this.status, this.location}); | |||||
| Device.clone(Device device) { | |||||
| this.id = device.id; | |||||
| this.name = device.name; | |||||
| this.status = device.status; | |||||
| this.location = device.location; | |||||
| } | |||||
| Device.fromJson(Map<String, dynamic> json) { | |||||
| id = json['id']; | |||||
| name = json['name']; | |||||
| status = json['status']; | |||||
| location = json['location']; | |||||
| } | |||||
| Map<String, dynamic> toJson() { | |||||
| final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
| data['id'] = this.id; | |||||
| data['name'] = this.name; | |||||
| data['status'] = this.status; | |||||
| data['location'] = this.location; | |||||
| return data; | |||||
| } | |||||
| } |
| import 'package:dio/dio.dart'; | import 'package:dio/dio.dart'; | ||||
| import 'package:farm_tpf/custom_model/CropPlot.dart'; | import 'package:farm_tpf/custom_model/CropPlot.dart'; | ||||
| import 'package:farm_tpf/custom_model/Device.dart'; | |||||
| import 'package:farm_tpf/custom_model/account.dart'; | import 'package:farm_tpf/custom_model/account.dart'; | ||||
| import 'package:farm_tpf/custom_model/password.dart'; | import 'package:farm_tpf/custom_model/password.dart'; | ||||
| import 'package:farm_tpf/custom_model/user.dart'; | import 'package:farm_tpf/custom_model/user.dart'; | ||||
| @PUT("/api/tb-crops") | @PUT("/api/tb-crops") | ||||
| Future<void> updateCrop(@Body() TbCropDTO crop); | Future<void> updateCrop(@Body() TbCropDTO crop); | ||||
| //Device | |||||
| @GET("/api/listDeviceOfUserCustomers") | |||||
| Future<List<Device>> getDevices(); | |||||
| } | } |
| data: _data); | data: _data); | ||||
| return null; | return null; | ||||
| } | } | ||||
| @override | |||||
| getDevices() async { | |||||
| const _extra = <String, dynamic>{}; | |||||
| final queryParameters = <String, dynamic>{}; | |||||
| final _data = <String, dynamic>{}; | |||||
| final Response<List<dynamic>> _result = await _dio.request( | |||||
| '/api/listDeviceOfUserCustomers', | |||||
| queryParameters: queryParameters, | |||||
| options: RequestOptions( | |||||
| method: 'GET', | |||||
| headers: <String, dynamic>{}, | |||||
| extra: _extra, | |||||
| baseUrl: baseUrl), | |||||
| data: _data); | |||||
| var value = _result.data | |||||
| .map((dynamic i) => Device.fromJson(i as Map<String, dynamic>)) | |||||
| .toList(); | |||||
| return value; | |||||
| } | |||||
| } | } |
| import 'package:dio/dio.dart'; | import 'package:dio/dio.dart'; | ||||
| import 'package:farm_tpf/custom_model/CropPlot.dart'; | import 'package:farm_tpf/custom_model/CropPlot.dart'; | ||||
| import 'package:farm_tpf/custom_model/Device.dart'; | |||||
| import 'package:farm_tpf/custom_model/user.dart'; | import 'package:farm_tpf/custom_model/user.dart'; | ||||
| import 'package:farm_tpf/custom_model/user_request.dart'; | import 'package:farm_tpf/custom_model/user_request.dart'; | ||||
| import 'package:farm_tpf/data/api/app_exception.dart'; | import 'package:farm_tpf/data/api/app_exception.dart'; | ||||
| onError(AppException.handleError(e)); | onError(AppException.handleError(e)); | ||||
| } | } | ||||
| } | } | ||||
| //Device | |||||
| Future<List<Device>> getDevices() { | |||||
| final client = RestClient(dio); | |||||
| return client.getDevices(); | |||||
| } | |||||
| } | } |
| import 'dart:async'; | |||||
| import 'package:bloc/bloc.dart'; | |||||
| import 'package:equatable/equatable.dart'; | |||||
| import 'package:farm_tpf/custom_model/Device.dart'; | |||||
| import 'package:farm_tpf/data/api/app_exception.dart'; | |||||
| import 'package:farm_tpf/data/repository/repository.dart'; | |||||
| import 'package:meta/meta.dart'; | |||||
| part 'device_event.dart'; | |||||
| part 'device_state.dart'; | |||||
| class DeviceBloc extends Bloc<DeviceEvent, DeviceState> { | |||||
| final Repository repository; | |||||
| DeviceBloc({@required this.repository}) : super(DeviceInitial()); | |||||
| @override | |||||
| Stream<DeviceState> mapEventToState( | |||||
| DeviceEvent event, | |||||
| ) async* { | |||||
| if (event is OpenScreen) { | |||||
| yield* _mapOpenScreenToState(); | |||||
| } else if (event is ControlDevice) { | |||||
| yield* _mapControlDeviceToState( | |||||
| event.currentDevices, event.updatedDeviceId); | |||||
| } | |||||
| } | |||||
| Stream<DeviceState> _mapOpenScreenToState() async* { | |||||
| yield DisplayDevice.loading(); | |||||
| try { | |||||
| List<Device> devices = new List<Device>(); | |||||
| final response = await repository.getDevices(); | |||||
| devices = response; | |||||
| devices.sort((a, b) => (a.id).compareTo(b.id)); | |||||
| yield DisplayDevice.data(devices); | |||||
| } catch (e) { | |||||
| yield DisplayDevice.error(AppException.handleError(e)); | |||||
| } | |||||
| } | |||||
| Stream<DeviceState> _mapControlDeviceToState( | |||||
| List<Device> currentDevices, int updatedDeviceId) async* { | |||||
| List<Device> devices = new List<Device>(); | |||||
| currentDevices.forEach((device) { | |||||
| if (device.id == updatedDeviceId) { | |||||
| var updatedStatus = device.status == "1" ? "0" : "1"; | |||||
| device.status = updatedStatus; | |||||
| } | |||||
| devices.add(Device.clone(device)); | |||||
| }); | |||||
| yield DisplayDevice.data(devices); | |||||
| } | |||||
| } |
| part of 'device_bloc.dart'; | |||||
| abstract class DeviceEvent extends Equatable { | |||||
| const DeviceEvent(); | |||||
| @override | |||||
| List<Object> get props => []; | |||||
| } | |||||
| class OpenScreen extends DeviceEvent { | |||||
| OpenScreen(); | |||||
| @override | |||||
| List<Object> get props => []; | |||||
| } | |||||
| class ControlDevice extends DeviceEvent { | |||||
| final List<Device> currentDevices; | |||||
| final int updatedDeviceId; | |||||
| ControlDevice( | |||||
| {@required this.currentDevices, @required this.updatedDeviceId}); | |||||
| } |
| part of 'device_bloc.dart'; | |||||
| abstract class DeviceState extends Equatable { | |||||
| const DeviceState(); | |||||
| @override | |||||
| List<Object> get props => []; | |||||
| } | |||||
| class DeviceInitial extends DeviceState {} | |||||
| class DisplayDevice extends DeviceState { | |||||
| List<Device> devices; | |||||
| bool loading; | |||||
| String msg; | |||||
| DisplayDevice({this.devices, this.loading, this.msg}); | |||||
| factory DisplayDevice.loading() { | |||||
| return DisplayDevice(devices: null, loading: true, msg: null); | |||||
| } | |||||
| factory DisplayDevice.data(List<Device> data) { | |||||
| return DisplayDevice(devices: data, loading: false, msg: null); | |||||
| } | |||||
| factory DisplayDevice.error(String msg) { | |||||
| return DisplayDevice(devices: null, loading: false, msg: msg); | |||||
| } | |||||
| @override | |||||
| List<Object> get props => [devices, loading, msg]; | |||||
| } |
| import 'package:farm_tpf/data/repository/repository.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/control_device/widget_device_list.dart'; | |||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
| import 'bloc/device_bloc.dart'; | |||||
| class ControlDeviceScreen extends StatefulWidget { | class ControlDeviceScreen extends StatefulWidget { | ||||
| @override | @override | ||||
| } | } | ||||
| class _ControlDeviceScreenState extends State<ControlDeviceScreen> { | class _ControlDeviceScreenState extends State<ControlDeviceScreen> { | ||||
| BuildContext _blocContext; | |||||
| @override | |||||
| void initState() { | |||||
| super.initState(); | |||||
| } | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| _blocContext = context; | |||||
| return Scaffold( | return Scaffold( | ||||
| appBar: AppBar( | |||||
| title: Text("Điều khiển thiết bị"), | |||||
| ), | |||||
| appBar: AppBar( | |||||
| title: Text("Điều khiển thiết bị"), | |||||
| ), | |||||
| body: BlocProvider<DeviceBloc>( | |||||
| create: (context) => | |||||
| DeviceBloc(repository: Repository())..add(OpenScreen()), | |||||
| child: _buildContent())); | |||||
| } | |||||
| Widget _buildContent() { | |||||
| return BlocBuilder<DeviceBloc, DeviceState>( | |||||
| builder: (context, state) { | |||||
| if (state is DisplayDevice) { | |||||
| if (state.loading) { | |||||
| return Container( | |||||
| child: Center( | |||||
| child: CircularProgressIndicator(), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| if (state.devices != null) { | |||||
| return Container( | |||||
| child: WidgetDeviceList(devices: state.devices), | |||||
| ); | |||||
| } | |||||
| return Container(); | |||||
| } else { | |||||
| return Container(); | |||||
| } | |||||
| }, | |||||
| ); | ); | ||||
| } | } | ||||
| } | } |
| import 'package:dio/dio.dart'; | |||||
| import 'package:farm_tpf/custom_model/Device.dart'; | |||||
| import 'package:farm_tpf/presentation/custom_widgets/widget_loading.dart'; | |||||
| import 'package:farm_tpf/presentation/screens/control_device/bloc/device_bloc.dart'; | |||||
| import 'package:farm_tpf/utils/const_common.dart'; | |||||
| import 'package:farm_tpf/utils/pref.dart'; | |||||
| import 'package:flutter/cupertino.dart'; | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:flutter/widgets.dart'; | |||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
| class WidgetDeviceList extends StatefulWidget { | |||||
| List<Device> devices; | |||||
| WidgetDeviceList({@required this.devices}); | |||||
| @override | |||||
| _WidgetDeviceListState createState() => _WidgetDeviceListState(); | |||||
| } | |||||
| class _WidgetDeviceListState extends State<WidgetDeviceList> { | |||||
| List<Device> currentDevices = new List<Device>(); | |||||
| BuildContext _context; | |||||
| var pref = LocalPref(); | |||||
| var token; | |||||
| var client; | |||||
| Future<Null> getSharedPrefs() async { | |||||
| token = await pref.getString(DATA_CONST.TOKEN_KEY); | |||||
| var options = BaseOptions(baseUrl: ConstCommon.baseUrl); | |||||
| options.headers["Authorization"] = "Bearer $token"; | |||||
| client = Dio(options); | |||||
| } | |||||
| @override | |||||
| void initState() { | |||||
| super.initState(); | |||||
| getSharedPrefs(); | |||||
| } | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| _context = context; | |||||
| if (widget.devices.isNotEmpty) { | |||||
| currentDevices = widget.devices; | |||||
| return widgetDeviceList( | |||||
| widget.devices.map((show) => ItemDeviceVM.fromDevice(show)).toList(), | |||||
| _context); | |||||
| } else { | |||||
| return Container( | |||||
| child: Center( | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.symmetric(horizontal: 32), | |||||
| child: Text('Không có dữ liệu'), | |||||
| ), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } | |||||
| Widget widgetDeviceList(List<ItemDeviceVM> items, BuildContext context) { | |||||
| return Container( | |||||
| child: GridView.count( | |||||
| childAspectRatio: (10 / 7), | |||||
| crossAxisCount: 2, | |||||
| children: items.map( | |||||
| (item) { | |||||
| return _widgetItemDevice(item, context); | |||||
| }, | |||||
| ).toList(), | |||||
| )); | |||||
| } | |||||
| Widget _widgetItemDevice(ItemDeviceVM item, BuildContext context) { | |||||
| return GestureDetector( | |||||
| onTap: () { | |||||
| //Navigator.of(context).push(MaterialPageRoute(builder: (context) => DeviceDetail(device: _device,))); | |||||
| }, | |||||
| child: Card( | |||||
| margin: EdgeInsets.all(8.0), | |||||
| shadowColor: Colors.grey, | |||||
| elevation: 3, | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.center, | |||||
| mainAxisAlignment: MainAxisAlignment.center, | |||||
| children: <Widget>[ | |||||
| Column( | |||||
| children: <Widget>[ | |||||
| powerBtn(item, context), | |||||
| Text( | |||||
| item.name, | |||||
| style: TextStyle( | |||||
| color: Colors.black54, | |||||
| fontSize: 13, | |||||
| fontWeight: FontWeight.bold), | |||||
| overflow: TextOverflow.clip, | |||||
| maxLines: 2, | |||||
| textAlign: TextAlign.center, | |||||
| ), | |||||
| Text(""), | |||||
| widgetStatus(item) | |||||
| ], | |||||
| ) | |||||
| ]), | |||||
| )); | |||||
| } | |||||
| Widget powerBtn(ItemDeviceVM item, BuildContext _context) { | |||||
| return BlocConsumer<DeviceBloc, DeviceState>( | |||||
| listener: (context, state) {}, | |||||
| buildWhen: (prev, current) { | |||||
| return current is DisplayDevice; | |||||
| }, | |||||
| builder: (context, state) { | |||||
| if (state is DisplayDevice) { | |||||
| if (state.loading) { | |||||
| return Container( | |||||
| child: Center( | |||||
| child: CircularProgressIndicator(), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| if (state.devices != null) { | |||||
| currentDevices = state.devices; | |||||
| if (item.status == "0") { | |||||
| //tat | |||||
| return IconButton( | |||||
| icon: Icon(Icons.power_settings_new), | |||||
| color: Colors.grey, | |||||
| onPressed: () async { | |||||
| //bat | |||||
| _controlSwitchDevice(item, context); | |||||
| }); | |||||
| } else if (item.status == "1") { | |||||
| //Bat | |||||
| return IconButton( | |||||
| icon: Icon(Icons.power_settings_new), | |||||
| color: Colors.blue, | |||||
| onPressed: () async { | |||||
| //tat | |||||
| _controlSwitchDevice(item, context); | |||||
| }); | |||||
| } else { | |||||
| //loi | |||||
| return IconButton( | |||||
| icon: Icon(Icons.power_settings_new), | |||||
| color: Colors.grey, | |||||
| onPressed: () {}); | |||||
| } | |||||
| } | |||||
| return Container(); | |||||
| } else { | |||||
| return Container(); | |||||
| } | |||||
| }, | |||||
| ); | |||||
| } | |||||
| Widget widgetStatus(ItemDeviceVM item) { | |||||
| if (item.status == "0") { | |||||
| return Text( | |||||
| "Đang Tắt", | |||||
| style: TextStyle(color: Colors.black54, fontSize: 13), | |||||
| ); | |||||
| } else if (item.status == "1") { | |||||
| return Text( | |||||
| "Đang Bật", | |||||
| style: TextStyle(color: Colors.green, fontSize: 13), | |||||
| ); | |||||
| } else { | |||||
| return Text( | |||||
| "Không kết nối", | |||||
| style: TextStyle(color: Colors.red, fontSize: 13), | |||||
| ); | |||||
| } | |||||
| } | |||||
| _controlSwitchDevice(ItemDeviceVM item, BuildContext context) { | |||||
| //neu status =1 ->tat . Neu Khong = bat | |||||
| var deviceOnOff = (item.status == "1") ? "0" : "1"; | |||||
| var idDevice = item.id; | |||||
| var statusDialogView = (item.status == "1") ? "Tắt" : "Bật"; | |||||
| Widget cancelButton = CupertinoDialogAction( | |||||
| child: Text("Huỷ"), | |||||
| onPressed: () { | |||||
| Navigator.of(context).pop(); | |||||
| }, | |||||
| ); | |||||
| Widget continueButton = CupertinoDialogAction( | |||||
| child: Text("Ok"), | |||||
| onPressed: () async { | |||||
| Navigator.of(context).pop(); | |||||
| LoadingDialog.showLoadingDialog(_context); | |||||
| try { | |||||
| String urlTurnOff = | |||||
| "/api/equipment-of-customers-on-off/$idDevice/$deviceOnOff"; | |||||
| var response = await client.put(urlTurnOff); | |||||
| if (200 <= response.statusCode && response.statusCode < 299) { | |||||
| BlocProvider.of<DeviceBloc>(_context).add(ControlDevice( | |||||
| currentDevices: currentDevices, updatedDeviceId: item.id)); | |||||
| Scaffold.of(context) | |||||
| ..hideCurrentSnackBar() | |||||
| ..showSnackBar( | |||||
| SnackBar( | |||||
| content: Row( | |||||
| mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
| children: <Widget>[ | |||||
| Text('Điều khiển thành công thiết bị ${item.name}'), | |||||
| Icon(Icons.done), | |||||
| ], | |||||
| ), | |||||
| backgroundColor: Colors.green, | |||||
| ), | |||||
| ); | |||||
| } | |||||
| } catch (error) { | |||||
| Scaffold.of(context) | |||||
| ..hideCurrentSnackBar() | |||||
| ..showSnackBar( | |||||
| SnackBar( | |||||
| content: Row( | |||||
| mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
| children: <Widget>[ | |||||
| Text('Điều khiển thiết bị ${item.name} thất bại'), | |||||
| Icon(Icons.error), | |||||
| ], | |||||
| ), | |||||
| backgroundColor: Colors.red, | |||||
| ), | |||||
| ); | |||||
| } | |||||
| LoadingDialog.hideLoadingDialog(_context); | |||||
| }, | |||||
| ); | |||||
| CupertinoAlertDialog alert = CupertinoAlertDialog( | |||||
| title: Text("Điều khiển thiết bị"), | |||||
| content: Text("$statusDialogView thiết bị ${item.name}?"), | |||||
| actions: [ | |||||
| cancelButton, | |||||
| continueButton, | |||||
| ], | |||||
| ); | |||||
| showDialog( | |||||
| context: context, | |||||
| builder: (BuildContext context) { | |||||
| return alert; | |||||
| }, | |||||
| ); | |||||
| } | |||||
| } | |||||
| class ItemDeviceVM { | |||||
| Device device; | |||||
| num id; | |||||
| String name; | |||||
| String status; | |||||
| String location; | |||||
| ItemDeviceVM(this.id, this.name, this.status); | |||||
| ItemDeviceVM.fromDevice(Device device) { | |||||
| this.device = device; | |||||
| id = device.id; | |||||
| name = device.name.toString(); | |||||
| status = device.status; | |||||
| location = device.location; | |||||
| } | |||||
| } |