Browse Source

control device

master
daivph 5 years ago
parent
commit
dd581fc038
12 changed files with 256 additions and 118 deletions
  1. +1
    -1
      ios/Flutter/.last_build_id
  2. +3
    -3
      ios/Runner.xcodeproj/project.pbxproj
  3. +5
    -1
      lib/custom_model/Device.dart
  4. +5
    -5
      lib/data/api/dio_provider.dart
  5. +2
    -2
      lib/data/api/rest_client.dart
  6. +2
    -2
      lib/data/api/rest_client.g.dart
  7. +2
    -2
      lib/data/repository/repository.dart
  8. +82
    -0
      lib/presentation/custom_widgets/widget_search.dart
  9. +16
    -1
      lib/presentation/screens/control_device/bloc/device_bloc.dart
  10. +8
    -0
      lib/presentation/screens/control_device/bloc/device_event.dart
  11. +36
    -20
      lib/presentation/screens/control_device/sc_control_device.dart
  12. +94
    -81
      lib/presentation/screens/control_device/widget_device_list.dart

+ 1
- 1
ios/Flutter/.last_build_id View File

af0eb765f94aecba228edd3e3fe3c4f4
440505e9ea1eee7043d2cbfeb318f6bc

+ 3
- 3
ios/Runner.xcodeproj/project.pbxproj View File

"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 0.10.0;
MARKETING_VERSION = 0.10.1;
PRODUCT_BUNDLE_IDENTIFIER = vn.azteam.tpfarm; PRODUCT_BUNDLE_IDENTIFIER = vn.azteam.tpfarm;
PRODUCT_NAME = Runner; PRODUCT_NAME = Runner;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 0.10.0;
MARKETING_VERSION = 0.10.1;
PRODUCT_BUNDLE_IDENTIFIER = vn.azteam.tpfarm; PRODUCT_BUNDLE_IDENTIFIER = vn.azteam.tpfarm;
PRODUCT_NAME = Runner; PRODUCT_NAME = Runner;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 0.10.0;
MARKETING_VERSION = 0.10.1;
PRODUCT_BUNDLE_IDENTIFIER = vn.azteam.tpfarm; PRODUCT_BUNDLE_IDENTIFIER = vn.azteam.tpfarm;
PRODUCT_NAME = Runner; PRODUCT_NAME = Runner;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

+ 5
- 1
lib/custom_model/Device.dart View File

String name; String name;
String status; String status;
String location; String location;
num mode;
bool isSelected; bool isSelected;


Device({this.id, this.name, this.status, this.location});
Device({this.id, this.name, this.status, this.location, this.mode});


Device.clone(Device device) { Device.clone(Device device) {
this.id = device.id; this.id = device.id;
this.name = device.name; this.name = device.name;
this.status = device.status; this.status = device.status;
this.location = device.location; this.location = device.location;
this.mode = device.mode;
} }


Device.fromJson(Map<String, dynamic> json) { Device.fromJson(Map<String, dynamic> json) {
name = json['name']; name = json['name'];
status = json['status']; status = json['status'];
location = json['location']; location = json['location'];
mode = json['mode'];
isSelected = false; isSelected = false;
} }


data['name'] = this.name; data['name'] = this.name;
data['status'] = this.status; data['status'] = this.status;
data['location'] = this.location; data['location'] = this.location;
data['mode'] = this.mode;
return data; return data;
} }
} }

+ 5
- 5
lib/data/api/dio_provider.dart View File

var token = await pref.getString(DATA_CONST.TOKEN_KEY); var token = await pref.getString(DATA_CONST.TOKEN_KEY);
options.headers["Authorization"] = "Bearer $token"; options.headers["Authorization"] = "Bearer $token";
options.receiveTimeout = 20000; options.receiveTimeout = 20000;
// log("onRequest: ${options.uri}\n"
// "data=${options.data}\n"
// "method=${options.method}\n"
// "headers=${options.headers}\n"
// "queryParameters=${options.queryParameters}");
log("onRequest: ${options.uri}\n"
"data=${options.data}\n"
"method=${options.method}\n"
"headers=${options.headers}\n"
"queryParameters=${options.queryParameters}");
return options; return options;
} }



+ 2
- 2
lib/data/api/rest_client.dart View File

@PUT("/api/tb-crops") @PUT("/api/tb-crops")
Future<void> updateCrop(@Body() TbCropDTO crop); Future<void> updateCrop(@Body() TbCropDTO crop);
//Device //Device
@GET("/api/listDeviceOfUserCustomers")
Future<List<Device>> getDevices();
@GET("/api/listDeviceOfUserCustomers?query={query}")
Future<List<Device>> getDevices({@Path() String query});
//Get environment parameter //Get environment parameter
@GET("/api/list-environment-updates-display/{cropId}?page={page}&size={size}") @GET("/api/list-environment-updates-display/{cropId}?page={page}&size={size}")
Future<List<EnvironmentParameter>> getEnvironmentParameters( Future<List<EnvironmentParameter>> getEnvironmentParameters(

+ 2
- 2
lib/data/api/rest_client.g.dart View File

} }


@override @override
getDevices() async {
getDevices({query}) async {
const _extra = <String, dynamic>{}; const _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{}; final queryParameters = <String, dynamic>{};
final _data = <String, dynamic>{}; final _data = <String, dynamic>{};
final Response<List<dynamic>> _result = await _dio.request( final Response<List<dynamic>> _result = await _dio.request(
'/api/listDeviceOfUserCustomers',
'/api/listDeviceOfUserCustomers?query=$query',
queryParameters: queryParameters, queryParameters: queryParameters,
options: RequestOptions( options: RequestOptions(
method: 'GET', method: 'GET',

+ 2
- 2
lib/data/repository/repository.dart View File

} }


//Device //Device
Future<List<Device>> getDevices() {
Future<List<Device>> getDevices(String query) {
final client = RestClient(dio); final client = RestClient(dio);
return client.getDevices();
return client.getDevices(query: query);
} }


//Environment Parameter //Environment Parameter

+ 82
- 0
lib/presentation/custom_widgets/widget_search.dart View File

import 'package:farm_tpf/utils/const_color.dart';
import 'package:flutter/material.dart';

class SearchWidget extends StatefulWidget {
final Function(String) searchPressed;
SearchWidget({@required this.searchPressed});
@override
_SearchWidgetState createState() => _SearchWidgetState();
}

class _SearchWidgetState extends State<SearchWidget> {
BuildContext _blocContext;
TextEditingController _searchController = TextEditingController();

@override
void initState() {
super.initState();
_searchController.addListener(() {
final keyword = _searchController.text;
if (keyword.isNotEmpty) {
//search when text change
}
});
}

Widget getSearchBarUI() {
_searchController.text = "";
return Padding(
padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
child: Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 8, top: 8, bottom: 0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(
Radius.circular(38.0),
),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.grey.withOpacity(0.2),
offset: const Offset(0, 2),
blurRadius: 8.0),
],
),
child: Padding(
padding: const EdgeInsets.only(
left: 16, right: 16, top: 4, bottom: 4),
child: TextField(
textInputAction: TextInputAction.done,
controller: _searchController,
onChanged: (String txt) {},
cursorColor: COLOR_CONST.GRAY1,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Tìm kiếm ...',
),
onSubmitted: widget.searchPressed,
),
),
),
),
),
],
),
);
}

@override
Widget build(BuildContext context) {
_blocContext = context;
return Container(child: getSearchBarUI());
}

@override
void dispose() {
_searchController.dispose();
super.dispose();
}
}

+ 16
- 1
lib/presentation/screens/control_device/bloc/device_bloc.dart View File

} else if (event is ControlDevice) { } else if (event is ControlDevice) {
yield* _mapControlDeviceToState( yield* _mapControlDeviceToState(
event.currentDevices, event.updatedDeviceId); event.currentDevices, event.updatedDeviceId);
} else if (event is OnSearch) {
yield* _mapOnSearchToState(event.query);
}
}

Stream<DeviceState> _mapOnSearchToState(String query) async* {
yield DisplayDevice.loading();
try {
List<Device> devices = new List<Device>();
final response = await repository.getDevices(query);
devices = response;
devices.sort((a, b) => (a.id).compareTo(b.id));
yield DisplayDevice.data(devices);
} catch (e) {
yield DisplayDevice.error(AppException.handleError(e));
} }
} }


yield DisplayDevice.loading(); yield DisplayDevice.loading();
try { try {
List<Device> devices = new List<Device>(); List<Device> devices = new List<Device>();
final response = await repository.getDevices();
final response = await repository.getDevices("");
devices = response; devices = response;
devices.sort((a, b) => (a.id).compareTo(b.id)); devices.sort((a, b) => (a.id).compareTo(b.id));
yield DisplayDevice.data(devices); yield DisplayDevice.data(devices);

+ 8
- 0
lib/presentation/screens/control_device/bloc/device_event.dart View File

List<Object> get props => []; List<Object> get props => [];
} }


class OnSearch extends DeviceEvent {
final String query;
OnSearch({@required this.query});

@override
List<Object> get props => [query];
}

class ControlDevice extends DeviceEvent { class ControlDevice extends DeviceEvent {
final List<Device> currentDevices; final List<Device> currentDevices;
final int updatedDeviceId; final int updatedDeviceId;

+ 36
- 20
lib/presentation/screens/control_device/sc_control_device.dart View File

import 'package:farm_tpf/data/repository/repository.dart'; import 'package:farm_tpf/data/repository/repository.dart';
import 'package:farm_tpf/presentation/custom_widgets/widget_search.dart';
import 'package:farm_tpf/presentation/screens/control_device/widget_device_list.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 'package:flutter_bloc/flutter_bloc.dart';


class _ControlDeviceScreenState extends State<ControlDeviceScreen> { class _ControlDeviceScreenState extends State<ControlDeviceScreen> {
BuildContext _blocContext; BuildContext _blocContext;
DeviceBloc _deviceBloc = DeviceBloc(repository: Repository());
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_deviceBloc.add(OpenScreen());
} }


@override @override
} }


Widget _buildContent() { Widget _buildContent() {
return BlocBuilder<DeviceBloc, DeviceState>(
builder: (context, state) {
if (state is DisplayDevice) {
if (state.loading) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
return Column(
children: [
SearchWidget(searchPressed: (value) {
FocusScope.of(context).requestFocus(FocusNode());
_deviceBloc.add(OnSearch(query: value));
}),
Expanded(
child: BlocBuilder<DeviceBloc, DeviceState>(
cubit: _deviceBloc,
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();
}
},
if (state.devices != null) {
return Container(
child: WidgetDeviceList(
devices: state.devices,
deviceBloc: _deviceBloc,
),
);
}
return Container();
} else {
return Container();
}
},
))
],
); );
} }
} }

+ 94
- 81
lib/presentation/screens/control_device/widget_device_list.dart View File

import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:farm_tpf/custom_model/Device.dart'; import 'package:farm_tpf/custom_model/Device.dart';
import 'package:farm_tpf/data/api/app_exception.dart';
import 'package:farm_tpf/presentation/custom_widgets/widget_loading.dart'; import 'package:farm_tpf/presentation/custom_widgets/widget_loading.dart';
import 'package:farm_tpf/presentation/custom_widgets/widget_utils.dart'; import 'package:farm_tpf/presentation/custom_widgets/widget_utils.dart';
import 'package:farm_tpf/presentation/screens/control_device/bloc/device_bloc.dart'; import 'package:farm_tpf/presentation/screens/control_device/bloc/device_bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';


class WidgetDeviceList extends StatefulWidget { class WidgetDeviceList extends StatefulWidget {
List<Device> devices;
WidgetDeviceList({@required this.devices});
final DeviceBloc deviceBloc;
final List<Device> devices;
WidgetDeviceList({@required this.devices, @required this.deviceBloc});
@override @override
_WidgetDeviceListState createState() => _WidgetDeviceListState(); _WidgetDeviceListState createState() => _WidgetDeviceListState();
} }
} }


Widget widgetDeviceList(List<ItemDeviceVM> items, BuildContext context) { 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);
return RefreshIndicator(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return _widgetItemDevice(items[index], context);
}, },
).toList(),
));
itemCount: items.length,
),
onRefresh: () async {
widget.deviceBloc.add(OpenScreen());
},
);
} }


Widget _widgetItemDevice(ItemDeviceVM item, BuildContext context) { Widget _widgetItemDevice(ItemDeviceVM item, BuildContext context) {
return GestureDetector( 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)
],
)
]),
));
onTap: () {
//Navigator.of(context).push(MaterialPageRoute(builder: (context) => DeviceDetail(device: _device,)));
},
child: Card(
child: ListTile(
leading: powerBtn(item, context),
title: Text(
'${item.name} - ${item.location ?? ''}',
style: TextStyle(
color: Colors.black54, fontSize: 13, fontWeight: FontWeight.bold),
),
subtitle: widgetStatus(item),
)),
);
} }


Widget powerBtn(ItemDeviceVM item, BuildContext _context) { Widget powerBtn(ItemDeviceVM item, BuildContext _context) {
}, },
builder: (context, state) { builder: (context, state) {
if (state is DisplayDevice) { if (state is DisplayDevice) {
if (state.loading) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}

if (state.devices != null) { if (state.devices != null) {
currentDevices = state.devices; 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);
});
//mode = 1: auto -> cho phep dieu khien
if (item.mode == 1) {
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: () {});
}
} else { } else {
//loi
return IconButton( return IconButton(
icon: Icon(Icons.power_settings_new), icon: Icon(Icons.power_settings_new),
color: Colors.grey, color: Colors.grey,
onPressed: () {}); onPressed: () {});
} }
} }
return Container();
return IconButton(
icon: Icon(Icons.power_settings_new),
color: Colors.grey,
onPressed: () {});
} else { } else {
return Container();
return IconButton(
icon: Icon(Icons.power_settings_new),
color: Colors.grey,
onPressed: () {});
} }
}, },
); );
} }


Widget widgetStatus(ItemDeviceVM item) { Widget widgetStatus(ItemDeviceVM item) {
var manualModeString = (item.mode != 1) ? ' - Điều khiển thủ công' : '';
if (item.status == "0") { if (item.status == "0") {
return Text(
"Đang Tắt",
style: TextStyle(color: Colors.black54, fontSize: 13),
return RichText(
text: TextSpan(
text: 'Đang Tắt',
style: TextStyle(color: Colors.black54, fontSize: 13),
children: <TextSpan>[
TextSpan(
text: manualModeString,
style: TextStyle(color: Colors.black54, fontSize: 13)),
],
),
); );
} else if (item.status == "1") { } else if (item.status == "1") {
return Text(
"Đang Bật",
style: TextStyle(color: Colors.green, fontSize: 13),
return RichText(
text: TextSpan(
text: 'Đang Bật',
style: TextStyle(color: Colors.green, fontSize: 13),
children: <TextSpan>[
TextSpan(
text: '$manualModeString',
style: TextStyle(color: Colors.black54, fontSize: 13)),
],
),
); );
} else { } else {
return Text( return Text(
var response = await client.put(urlTurnOff); var response = await client.put(urlTurnOff);


if (200 <= response.statusCode && response.statusCode < 299) { if (200 <= response.statusCode && response.statusCode < 299) {
BlocProvider.of<DeviceBloc>(_context).add(ControlDevice(
LoadingDialog.hideLoadingDialog(_context);
widget.deviceBloc.add(ControlDevice(
currentDevices: currentDevices, updatedDeviceId: item.id)); currentDevices: currentDevices, updatedDeviceId: item.id));
Utils.showSnackBarSuccess( Utils.showSnackBarSuccess(
message: 'Điều khiển thành công thiết bị ${item.name}'); message: 'Điều khiển thành công thiết bị ${item.name}');
} }
} catch (error) { } catch (error) {
Utils.showSnackBarError(
message: 'Điều khiển thiết bị ${item.name} thất bại');
LoadingDialog.hideLoadingDialog(_context);
var errorMessage = AppException.handleError(error,
customMessageError:
"Thiết bị ${item.name} đã được $statusDialogView.\nTải lại để cập nhật trạng thái mới nhất");
Utils.showSnackBarError(message: errorMessage);
} }
LoadingDialog.hideLoadingDialog(_context);
}, },
); );
CupertinoAlertDialog alert = CupertinoAlertDialog( CupertinoAlertDialog alert = CupertinoAlertDialog(
String name; String name;
String status; String status;
String location; String location;
num mode;


ItemDeviceVM(this.id, this.name, this.status);
ItemDeviceVM(this.id, this.name, this.status, this.location, this.mode);
ItemDeviceVM.fromDevice(Device device) { ItemDeviceVM.fromDevice(Device device) {
this.device = device; this.device = device;
id = device.id; id = device.id;
name = device.name.toString(); name = device.name.toString();
status = device.status; status = device.status;
location = device.location; location = device.location;
mode = device.mode;
} }
} }

Loading…
Cancel
Save