diff --git a/lib/Components/string_input_container.dart b/lib/Components/string_input_container.dart index c85fcd8..07eb0dd 100644 --- a/lib/Components/string_input_container.dart +++ b/lib/Components/string_input_container.dart @@ -8,6 +8,7 @@ class StringInputContainer extends StatelessWidget { final String initialValue; final ValueChanged onChanged; final bool isUrl; + final bool isSmall; const StringInputContainer({ Key key, this.color = kSecond, @@ -15,6 +16,7 @@ class StringInputContainer extends StatelessWidget { this.initialValue, this.onChanged, this.isUrl = false, + this.isSmall = false, }) : super(key: key); @override @@ -30,7 +32,7 @@ class StringInputContainer extends StatelessWidget { Padding( padding: const EdgeInsets.all(10.0), child: Container( - width: isUrl ? size.width *0.6 : size.width *0.2, + width: isUrl ? size.width *0.6 : isSmall != null ? size.width *0.1 : size.width *0.2, child: RoundedInputField( color: color, textColor: kBlack, diff --git a/lib/Screens/Configurations/configurations_screen.dart b/lib/Screens/Configurations/configurations_screen.dart index caf3b71..401f773 100644 --- a/lib/Screens/Configurations/configurations_screen.dart +++ b/lib/Screens/Configurations/configurations_screen.dart @@ -60,7 +60,7 @@ class _ConfigurationsScreenState extends State { gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 6), itemCount: data.length, itemBuilder: (BuildContext context, int index) { - return // User Picture + return InkWell( onTap: () { if (data[index].id == null) { diff --git a/lib/Screens/Devices/change_name_modal.dart b/lib/Screens/Devices/change_name_modal.dart new file mode 100644 index 0000000..2d9488c --- /dev/null +++ b/lib/Screens/Devices/change_name_modal.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:manager_app/Components/rounded_button.dart'; +import 'package:manager_app/Components/string_input_container.dart'; +import 'package:manager_app/constants.dart'; +import 'package:managerapi/api.dart'; + +showChangeNameModal (String text, String name, Function onGetResult, int maxLines, BuildContext mainContext, dynamic appContext) { + Size size = MediaQuery.of(mainContext).size; + + showDialog( + builder: (BuildContext context) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20.0)) + ), + title: Center(child: Text(text)), + content: SingleChildScrollView( + child: Center( + child: Container( + width: size.width * 0.3, + height: size.height * 0.15, + child: StringInputContainer( + label: "Nom :", + initialValue: name, + onChanged: (value) { + name = value; + }, + ), + ), + ) + ), + actions: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + width: 180, + height: 70, + child: RoundedButton( + text: "Annuler", + icon: Icons.undo, + color: kSecond, + press: () { + Navigator.of(context).pop(); + }, + fontSize: 20, + ), + ), + Container( + width: 180, + height: 70, + child: RoundedButton( + text: "Changer", + icon: Icons.check, + color: kPrimaryColor, + textColor: kWhite, + press: () { + onGetResult(name); + Navigator.of(context).pop(); + }, + fontSize: 20, + ), + ), + ], + ), + ], + ), context: mainContext + ); +} diff --git a/lib/Screens/Devices/devices_screen.dart b/lib/Screens/Devices/devices_screen.dart index 113e036..7e878de 100644 --- a/lib/Screens/Devices/devices_screen.dart +++ b/lib/Screens/Devices/devices_screen.dart @@ -1,5 +1,10 @@ +import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; +import 'package:manager_app/Models/managerContext.dart'; +import 'package:manager_app/Screens/Devices/change_name_modal.dart'; +import 'package:manager_app/Screens/Devices/select_config_modal.dart'; import 'package:manager_app/app_context.dart'; +import 'package:manager_app/constants.dart'; import 'package:managerapi/api.dart'; import 'package:provider/provider.dart'; @@ -19,9 +24,6 @@ class _DevicesScreenState extends State { return Container( child: Column( children: [ - Text( - "Devices" - ), FutureBuilder( future: getDevices(appContext), builder: (context, AsyncSnapshot snapshot) { @@ -31,8 +33,15 @@ class _DevicesScreenState extends State { gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 4), itemCount: snapshot.data.length, itemBuilder: (BuildContext context, int index) { - return // User Picture - Text("Test devices"); + return Container( + decoration: boxDecoration(), + padding: const EdgeInsets.all(15), + margin: EdgeInsets.symmetric(vertical: 15, horizontal: 15), + child: Align( + alignment: Alignment.center, + child: getElement(snapshot.data[index], size, appContext) + ), + ); } ); } else if (snapshot.connectionState == ConnectionState.none) { @@ -46,6 +55,149 @@ class _DevicesScreenState extends State { ), ); } + + getElement(DeviceDTO device, Size size, dynamic appContext) { + return Stack( + children: [ + Positioned( + top: 10, + right: 10, + child: Container( + width: 15, + height: 15, + decoration: BoxDecoration( + color: device.connected ? Colors.green : Colors.red, + shape: BoxShape.rectangle, + borderRadius: BorderRadius.circular(25.0), + boxShadow: [ + BoxShadow( + color: kSecond, + spreadRadius: 0.5, + blurRadius: 3, + offset: Offset(0, 1.5), // changes position of shadow + ), + ], + ), + ), + ), + Positioned( + top: 10, + left: 10, + child: Row( + children: [ + AutoSizeText( + device.name, + style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w300), + maxLines: 1, + ), + IconButton( + icon: Icon(Icons.edit), + onPressed: () { + showChangeNameModal( + "Nom du device", + device.name, + (String name) { + device.name = name; + + // Update device main info + updateMainInfos(device, appContext); + // For refresh + setState(() { + }); + }, + 1, + context, + appContext + ); + }, + color: kPrimaryColor, + ) + ], + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Align( + alignment: Alignment.centerLeft, + child: Row( + children: [ + AutoSizeText( + "Configuration: ", + style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w300), + maxLines: 1, + ), + device.configurationId != null ? + AutoSizeText( + device.configurationId, + style: new TextStyle(fontSize: 25), + maxLines: 1, + ) : InkWell( + onTap: () { + showSelectConfigModal( + "Sélectionner une configuration", + (String configurationId) { + + device.configurationId = configurationId; + // Update device main info + updateMainInfos(device, appContext); + + // For refresh // TODO better refresh + setState(() { + }); + }, + 1, + context, + appContext + ); + }, + child: Container( + decoration: BoxDecoration( + color: kPrimaryColor, + borderRadius: BorderRadius.circular(50), + ), + child: Padding( + padding: const EdgeInsets.only(left: 5, right: 5, top: 15, bottom: 15), + child: Center( + child: AutoSizeText( + "Sélectionner", + style: TextStyle(color: kWhite), + maxLines: 1, + ) + ), + ) + ), + ) + ], + ), + ), + ], + ), + ], + ); + } +} + +Future updateMainInfos(DeviceDTO deviceToUpdate, dynamic appContext) async { + ManagerAppContext managerAppContext = appContext.getContext(); + DeviceDTO device = await managerAppContext.clientAPI.deviceApi.deviceUpdateMainInfos(deviceToUpdate); +} + +boxDecoration() { + return BoxDecoration( + color: kTextLightColor, + shape: BoxShape.rectangle, + borderRadius: BorderRadius.circular(25.0), + boxShadow: [ + BoxShadow( + color: kSecond, + spreadRadius: 0.5, + blurRadius: 5, + offset: Offset(0, 1.5), // changes position of shadow + ), + ], + ); } Future> getDevices(dynamic appContext) async { diff --git a/lib/Screens/Devices/select_config_modal.dart b/lib/Screens/Devices/select_config_modal.dart new file mode 100644 index 0000000..b3d3853 --- /dev/null +++ b/lib/Screens/Devices/select_config_modal.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; +import 'package:manager_app/Components/rounded_button.dart'; +import 'package:manager_app/constants.dart'; +import 'package:managerapi/api.dart'; + +showSelectConfigModal (String text, Function onGetResult, int maxLines, BuildContext mainContext, dynamic appContext) { + Size size = MediaQuery.of(mainContext).size; + + showDialog( + builder: (BuildContext context) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20.0)) + ), + title: Center(child: Text(text)), + content: SingleChildScrollView( + child: Column( + children: [ + Container( + width: size.width * 0.2, + height: size.height * 0.3, + child: FutureBuilder( + future: getConfigurations(appContext), + builder: (context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + return ListView( + scrollDirection: Axis.vertical, + children: getConfigurationsElement(snapshot.data, onGetResult, () { + Navigator.of(context).pop(); + }), + ); + } else if (snapshot.connectionState == ConnectionState.none) { + return Text("No data"); + } else { + return Center(child: Container(height: size.height * 0.2, child: Text('LOADING TODO FRAISE'))); + } + } + ), + ), + ], + ) + ), + actions: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + width: 180, + height: 70, + child: RoundedButton( + text: "Annuler", + icon: Icons.undo, + color: kSecond, + press: () { + Navigator.of(context).pop(); + }, + fontSize: 20, + ), + ), + ], + ), + ], + ), context: mainContext + ); +} + +getConfigurationsElement(data, Function onGetResult, Function requestClose) { + List widgets = new List(); + for(var configuration in data as List) { + var widget = new InkWell( + onTap: () { + onGetResult(configuration.id); + requestClose(); + }, + child: ListTile( + leading: Icon(Icons.account_tree_rounded), + title: Text(configuration.label) + ), + ); + widgets.add(widget); + } + return widgets; +} + +Future> getConfigurations(dynamic appContext) async { + List configurations = await appContext.getContext().clientAPI.configurationApi.configurationGet(); + print("number of configurations " + configurations.length.toString()); + configurations.forEach((element) { + print(element); + }); + return configurations; +} diff --git a/manager_api/README.md b/manager_api/README.md index 2c1a06d..ab85a8a 100644 --- a/manager_api/README.md +++ b/manager_api/README.md @@ -76,6 +76,7 @@ Class | Method | HTTP request | Description *DeviceApi* | [**deviceGet**](doc\/DeviceApi.md#deviceget) | **GET** /api/Device | *DeviceApi* | [**deviceGetDetail**](doc\/DeviceApi.md#devicegetdetail) | **GET** /api/Device/{id}/detail | *DeviceApi* | [**deviceUpdate**](doc\/DeviceApi.md#deviceupdate) | **PUT** /api/Device | +*DeviceApi* | [**deviceUpdateMainInfos**](doc\/DeviceApi.md#deviceupdatemaininfos) | **PUT** /api/Device/mainInfos | *ResourceApi* | [**resourceCreate**](doc\/ResourceApi.md#resourcecreate) | **POST** /api/Resource | *ResourceApi* | [**resourceDelete**](doc\/ResourceApi.md#resourcedelete) | **DELETE** /api/Resource/{id} | *ResourceApi* | [**resourceGet**](doc\/ResourceApi.md#resourceget) | **GET** /api/Resource | diff --git a/manager_api/doc/DeviceApi.md b/manager_api/doc/DeviceApi.md index 257a6c9..96e70af 100644 --- a/manager_api/doc/DeviceApi.md +++ b/manager_api/doc/DeviceApi.md @@ -14,6 +14,7 @@ Method | HTTP request | Description [**deviceGet**](DeviceApi.md#deviceget) | **GET** /api/Device | [**deviceGetDetail**](DeviceApi.md#devicegetdetail) | **GET** /api/Device/{id}/detail | [**deviceUpdate**](DeviceApi.md#deviceupdate) | **PUT** /api/Device | +[**deviceUpdateMainInfos**](DeviceApi.md#deviceupdatemaininfos) | **PUT** /api/Device/mainInfos | # **deviceCreate** @@ -227,3 +228,46 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **deviceUpdateMainInfos** +> DeviceDTO deviceUpdateMainInfos(deviceDTO) + + + +### Example +```dart +import 'package:managerapi/api.dart'; +// TODO Configure OAuth2 access token for authorization: bearer +//defaultApiClient.getAuthentication('bearer').accessToken = 'YOUR_ACCESS_TOKEN'; + +final api_instance = DeviceApi(); +final deviceDTO = DeviceDTO(); // DeviceDTO | + +try { + final result = api_instance.deviceUpdateMainInfos(deviceDTO); + print(result); +} catch (e) { + print('Exception when calling DeviceApi->deviceUpdateMainInfos: $e\n'); +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **deviceDTO** | [**DeviceDTO**](DeviceDTO.md)| | + +### Return type + +[**DeviceDTO**](DeviceDTO.md) + +### Authorization + +[bearer](../README.md#bearer) + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/manager_api/lib/api/device_api.dart b/manager_api/lib/api/device_api.dart index a8b4ed7..7162ac9 100644 --- a/manager_api/lib/api/device_api.dart +++ b/manager_api/lib/api/device_api.dart @@ -322,4 +322,67 @@ class DeviceApi { } return Future.value(null); } + + /// Performs an HTTP 'PUT /api/Device/mainInfos' operation and returns the [Response]. + /// Parameters: + /// + /// * [DeviceDTO] deviceDTO (required): + Future deviceUpdateMainInfosWithHttpInfo(DeviceDTO deviceDTO) async { + // Verify required params are set. + if (deviceDTO == null) { + throw ApiException(HttpStatus.badRequest, 'Missing required param: deviceDTO'); + } + + final path = r'/api/Device/mainInfos'; + + Object postBody = deviceDTO; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + final contentTypes = ['application/json']; + final nullableContentType = contentTypes.isNotEmpty ? contentTypes[0] : null; + final authNames = ['bearer']; + + if ( + nullableContentType != null && + nullableContentType.toLowerCase().startsWith('multipart/form-data') + ) { + bool hasFields = false; + final mp = MultipartRequest(null, null); + if (hasFields) { + postBody = mp; + } + } else { + } + + return await apiClient.invokeAPI( + path, + 'PUT', + queryParams, + postBody, + headerParams, + formParams, + nullableContentType, + authNames, + ); + } + + /// Parameters: + /// + /// * [DeviceDTO] deviceDTO (required): + Future deviceUpdateMainInfos(DeviceDTO deviceDTO) async { + final response = await deviceUpdateMainInfosWithHttpInfo(deviceDTO); + if (response.statusCode >= HttpStatus.badRequest) { + throw ApiException(response.statusCode, _decodeBodyBytes(response)); + } + // When a remote server returns no body with a status of 204, we shall not decode it. + // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" + // FormatException when trying to decode an empty string. + if (response.body != null && response.statusCode != HttpStatus.noContent) { + return apiClient.deserialize(_decodeBodyBytes(response), 'DeviceDTO') as DeviceDTO; + } + return Future.value(null); + } } diff --git a/manager_api/swagger.yaml b/manager_api/swagger.yaml index 910214a..e7be1e3 100644 --- a/manager_api/swagger.yaml +++ b/manager_api/swagger.yaml @@ -310,6 +310,46 @@ paths: application/json: schema: type: string + /api/Device/mainInfos: + put: + tags: + - Device + operationId: Device_UpdateMainInfos + requestBody: + x-name: deviceIn + content: + application/json: + schema: + $ref: '#/components/schemas/DeviceDTO' + required: true + x-position: 1 + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/DeviceDTO' + '400': + description: '' + content: + application/json: + schema: + type: string + '404': + description: '' + content: + application/json: + schema: + type: string + '500': + description: '' + content: + application/json: + schema: + type: string + security: + - bearer: [] /api/Device/{id}: delete: tags: