diff --git a/assets/icons/gateway_icon.svg b/assets/icons/gateway_icon.svg new file mode 100644 index 0000000..d64135c --- /dev/null +++ b/assets/icons/gateway_icon.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/features/app_layout/bloc/home_cubit.dart b/lib/features/app_layout/bloc/home_cubit.dart index 48021cc..e0f5ce9 100644 --- a/lib/features/app_layout/bloc/home_cubit.dart +++ b/lib/features/app_layout/bloc/home_cubit.dart @@ -1,5 +1,4 @@ import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; @@ -275,7 +274,7 @@ class HomeCubit extends Cubit { size: 25, ), style: ButtonStyle( - foregroundColor: MaterialStateProperty.all(ColorsManager.textPrimaryColor), + foregroundColor: WidgetStateProperty.all(ColorsManager.textPrimaryColor), ), onPressed: () { Navigator.push( @@ -300,7 +299,7 @@ class HomeCubit extends Cubit { size: 25, ), style: ButtonStyle( - foregroundColor: MaterialStateProperty.all(ColorsManager.textPrimaryColor), + foregroundColor: WidgetStateProperty.all(ColorsManager.textPrimaryColor), ), onPressed: () {}, ), @@ -310,7 +309,7 @@ class HomeCubit extends Cubit { size: 25, ), style: ButtonStyle( - foregroundColor: MaterialStateProperty.all(ColorsManager.textPrimaryColor), + foregroundColor: WidgetStateProperty.all(ColorsManager.textPrimaryColor), ), onPressed: () {}, ), diff --git a/lib/features/auth/view/widgets/login_form.dart b/lib/features/auth/view/widgets/login_form.dart index 5432a4d..6493800 100644 --- a/lib/features/auth/view/widgets/login_form.dart +++ b/lib/features/auth/view/widgets/login_form.dart @@ -85,10 +85,10 @@ class LoginForm extends StatelessWidget { isDone: state is AuthLoginSuccess, isLoading: state is AuthLoading, customButtonStyle: ButtonStyle( - backgroundColor: MaterialStateProperty.all( + backgroundColor: WidgetStateProperty.all( Colors.black.withOpacity(.25), ), - foregroundColor: MaterialStateProperty.all( + foregroundColor: WidgetStateProperty.all( Colors.white, ), ), diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index 48341df..0f95620 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -87,8 +87,8 @@ class DevicesCubit extends Cubit { return const CurtainListView(); // case DeviceType.ThreeGang: // return const ThreeGangSwitchesView(); - case DeviceType.Gateway: - return const GateWayView(); + // case DeviceType.Gateway: + // return const GateWayView(); default: return null; } diff --git a/lib/features/devices/bloc/gateway_bloc/gateway_bloc.dart b/lib/features/devices/bloc/gateway_bloc/gateway_bloc.dart new file mode 100644 index 0000000..7154485 --- /dev/null +++ b/lib/features/devices/bloc/gateway_bloc/gateway_bloc.dart @@ -0,0 +1,23 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/gateway_bloc/gateway_event.dart'; +import 'package:syncrow_app/features/devices/bloc/gateway_bloc/gateway_state.dart'; +import 'package:syncrow_app/features/devices/model/device_model.dart'; +import 'package:syncrow_app/services/api/devices_api.dart'; + +class GatewayBloc extends Bloc { + GatewayBloc() : super(GatewayInitialState()) { + on(_fetchDevices); + } + + void _fetchDevices(GatewayInitial event, Emitter emit) async { + emit(GatewayLoadingState()); + try { + List devicesList = await DevicesAPI.getDevicesByGatewayId(event.gatewayId); + + emit(UpdateGatewayState(list: devicesList)); + } catch (e) { + emit(ErrorState(message: e.toString())); + return; + } + } +} diff --git a/lib/features/devices/bloc/gateway_bloc/gateway_event.dart b/lib/features/devices/bloc/gateway_bloc/gateway_event.dart new file mode 100644 index 0000000..cdcf715 --- /dev/null +++ b/lib/features/devices/bloc/gateway_bloc/gateway_event.dart @@ -0,0 +1,20 @@ +import 'package:equatable/equatable.dart'; + +abstract class GatewayEvent extends Equatable { + const GatewayEvent(); + + @override + List get props => []; +} + +class GatewayInitial extends GatewayEvent { + final String gatewayId; + const GatewayInitial({required this.gatewayId}); + + @override + List get props => [gatewayId]; +} + +class GatewayLoading extends GatewayEvent {} + +class GatewayUpdateState extends GatewayEvent {} diff --git a/lib/features/devices/bloc/gateway_bloc/gateway_state.dart b/lib/features/devices/bloc/gateway_bloc/gateway_state.dart new file mode 100644 index 0000000..29ac0fb --- /dev/null +++ b/lib/features/devices/bloc/gateway_bloc/gateway_state.dart @@ -0,0 +1,29 @@ +import 'package:equatable/equatable.dart'; +import 'package:syncrow_app/features/devices/model/device_model.dart'; + +abstract class GatewayState extends Equatable { + const GatewayState(); + + @override + List get props => []; +} + +class GatewayInitialState extends GatewayState {} + +class GatewayLoadingState extends GatewayState {} + +class UpdateGatewayState extends GatewayState { + final List list; + const UpdateGatewayState({required this.list}); + + @override + List get props => [list]; +} + +class ErrorState extends GatewayState { + final String message; + const ErrorState({required this.message}); + + @override + List get props => [message]; +} diff --git a/lib/features/devices/view/widgets/gateway/gateway_view.dart b/lib/features/devices/view/widgets/gateway/gateway_view.dart index 71065e3..25e1bb6 100644 --- a/lib/features/devices/view/widgets/gateway/gateway_view.dart +++ b/lib/features/devices/view/widgets/gateway/gateway_view.dart @@ -1,10 +1,128 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_app/features/devices/bloc/gateway_bloc/gateway_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/gateway_bloc/gateway_event.dart'; +import 'package:syncrow_app/features/devices/bloc/gateway_bloc/gateway_state.dart'; +import 'package:syncrow_app/features/devices/model/device_model.dart'; +import 'package:syncrow_app/features/devices/view/widgets/room_page_switch.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; +import 'package:syncrow_app/generated/assets.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; +import 'package:syncrow_app/utils/resource_manager/constants.dart'; +import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; class GateWayView extends StatelessWidget { - const GateWayView({super.key}); + final DeviceModel gatewayObj; + + const GateWayView({required this.gatewayObj, super.key}); @override Widget build(BuildContext context) { - return const Placeholder(); + return BlocProvider( + create: (context) => GatewayBloc()..add(GatewayInitial(gatewayId: gatewayObj.uuid ?? '')), + child: BlocBuilder(builder: (context, state) { + List devicesList = []; + if (state is UpdateGatewayState) { + devicesList = state.list; + } + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarColor: ColorsManager.primaryColor.withOpacity(0.5), + statusBarIconBrightness: Brightness.light, + ), + child: Scaffold( + backgroundColor: ColorsManager.backgroundColor, + extendBodyBehindAppBar: true, + extendBody: true, + appBar: AppBar( + backgroundColor: Colors.transparent, + centerTitle: true, + title: const BodyLarge( + text: 'Gateway', + fontColor: ColorsManager.primaryColor, + fontWeight: FontsManager.bold, + ), + ), + body: Container( + width: MediaQuery.sizeOf(context).width, + height: MediaQuery.sizeOf(context).height, + padding: const EdgeInsets.all(Constants.defaultPadding), + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage( + Assets.assetsImagesBackground, + ), + fit: BoxFit.cover, + opacity: 0.4, + ), + ), + child: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + height: MediaQuery.sizeOf(context).height * 0.3, + width: MediaQuery.sizeOf(context).width, + alignment: AlignmentDirectional.center, + child: Stack(children: [ + SvgPicture.asset( + Assets.gatewayIcon, + width: 125, + height: 125, + ), + Positioned( + right: 30, + top: 15, + child: Container( + width: 12, + height: 12, + decoration: const BoxDecoration( + color: ColorsManager.lightGreen, + shape: BoxShape.circle, + ), + ), + ), + ]), + ), + const BodyMedium( + text: 'Zigbee Devices', + fontSize: 15, + fontWeight: FontWeight.w700, + ), + const SizedBox( + height: 10, + ), + state is GatewayLoadingState + ? Center( + child: Container( + margin: const EdgeInsets.only(top: 20), + height: 50, + width: 50, + child: const RefreshProgressIndicator()), + ) + : Expanded( + child: GridView.builder( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 10, + mainAxisSpacing: 10, + childAspectRatio: 1.5, + ), + padding: const EdgeInsets.only(top: 10), + shrinkWrap: true, + itemCount: devicesList.length, + itemBuilder: (context, index) { + return RoomPageSwitch(device: devicesList[index]); + }, + ), + ) + ], + ), + ), + ))); + })); } } diff --git a/lib/features/devices/view/widgets/room_page_switch.dart b/lib/features/devices/view/widgets/room_page_switch.dart index 13e5b24..b550e68 100644 --- a/lib/features/devices/view/widgets/room_page_switch.dart +++ b/lib/features/devices/view/widgets/room_page_switch.dart @@ -3,20 +3,18 @@ /// This widget displays the icon and name of the device, along with a switch /// to control its state. Tapping on the widget opens the device interface. import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart'; +import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/wall_sensor/wall_sensor_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/ceiling_sensor/ceiling_sensor_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface.dart'; -import 'package:syncrow_app/features/shared_widgets/custom_switch.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; -import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/helpers/custom_page_route.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; @@ -31,46 +29,44 @@ class RoomPageSwitch extends StatelessWidget { @override Widget build(BuildContext context) { - return InkWell( + return GestureDetector( onTap: () { showDeviceInterface(device, context); }, child: DefaultContainer( - child: Padding( - padding: const EdgeInsets.only(top: 10, right: 10, left: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SvgPicture.asset( - device.icon!, - fit: BoxFit.contain, - ), - CustomSwitch( - device: device, - ), - ], - ), - Expanded( - child: FittedBox( - fit: BoxFit.scaleDown, - child: BodyLarge( - text: device.name ?? "", - style: context.bodyLarge.copyWith( - fontWeight: FontWeight.bold, - height: 0, - fontSize: 24, - color: Colors.grey, - ), + padding: const EdgeInsets.all(15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SvgPicture.asset( + device.icon!, + fit: BoxFit.contain, + ), + // CustomSwitch( + // device: device, + // ), + ], + ), + Flexible( + child: FittedBox( + child: Text( + device.name ?? "", + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: context.bodyLarge.copyWith( + fontWeight: FontWeight.bold, + fontSize: 20, + color: Colors.grey, ), ), ), - ], - ), + ), + ], ), ), ); @@ -117,6 +113,10 @@ void showDeviceInterface(DeviceModel device, BuildContext context) { // navigateToInterface(DoorInterface(doorlock: device), context); break; case DeviceType.Gateway: + Navigator.push( + context, + PageRouteBuilder( + pageBuilder: (context, animation1, animation2) => GateWayView(gatewayObj: device))); break; case DeviceType.LightBulb: navigateToInterface(LightInterface(light: device), context); diff --git a/lib/generated/assets.dart b/lib/generated/assets.dart index fabad48..eae0990 100644 --- a/lib/generated/assets.dart +++ b/lib/generated/assets.dart @@ -651,6 +651,7 @@ class Assets { static const String emptyCheckboxIcon = "assets/icons/empty_checkbox_ic.svg"; static const String pauseIcon = "assets/icons/pause_ic.svg"; static const String playIcon = "assets/icons/play_ic.svg"; + static const String gatewayIcon = "assets/icons/gateway_icon.svg"; /// Assets for assetsImagesAutomation /// assets/images/automation.jpg diff --git a/lib/services/api/api_links_endpoints.dart b/lib/services/api/api_links_endpoints.dart index ebf8c89..1555b5b 100644 --- a/lib/services/api/api_links_endpoints.dart +++ b/lib/services/api/api_links_endpoints.dart @@ -96,6 +96,7 @@ abstract class ApiEndpoints { static const String deviceByRoom = '$baseUrl/device/room'; static const String deviceByUuid = '$baseUrl/device/{deviceUuid}'; static const String deviceFunctions = '$baseUrl/device/{deviceUuid}/functions'; + static const String gatewayApi = '$baseUrl/device/getaway/{gatewayUuid}/devices'; static const String deviceFunctionsStatus = '$baseUrl/device/{deviceUuid}/functions/status'; ///Device Permission Module diff --git a/lib/services/api/devices_api.dart b/lib/services/api/devices_api.dart index 94a3984..64ce38c 100644 --- a/lib/services/api/devices_api.dart +++ b/lib/services/api/devices_api.dart @@ -50,7 +50,6 @@ class DevicesAPI { } static Future> getDevicesByRoomId(String roomId) async { - // print("Room ID: $roomId"); final response = await _httpService.get( path: ApiEndpoints.deviceByRoom, queryParameters: {"roomUuid": roomId}, @@ -68,4 +67,22 @@ class DevicesAPI { ); return response; } + + static Future> getDevicesByGatewayId(String gatewayId) async { + final response = await _httpService.get( + path: ApiEndpoints.gatewayApi.replaceAll('{gatewayUuid}', gatewayId), + showServerMessage: false, + expectedResponseModel: (json) { + List devices = []; + if (json == null || json.isEmpty || json == []) { + return devices; + } + for (var device in json['devices']) { + devices.add(DeviceModel.fromJson(device)); + } + return devices; + }, + ); + return response; + } } diff --git a/lib/utils/resource_manager/color_manager.dart b/lib/utils/resource_manager/color_manager.dart index b5edf52..05a1069 100644 --- a/lib/utils/resource_manager/color_manager.dart +++ b/lib/utils/resource_manager/color_manager.dart @@ -20,4 +20,5 @@ abstract class ColorsManager { static const Color dividerColor = Color(0xFFEBEBEB); static const Color slidingBlueColor = Color(0x99023DFE); static const Color blackColor = Color(0xFF000000); + static const Color lightGreen = Color(0xFF00FF0A); }