Merge pull request #12 from SyncrowIOT/Configure_devices_statuses

Configure devices statuses
This commit is contained in:
Mohammad Salameh
2024-04-14 12:01:57 +03:00
committed by GitHub
71 changed files with 1933 additions and 1194 deletions

6
.vscode/launch.json vendored
View File

@ -11,6 +11,12 @@
"type": "dart",
"deviceId": "0147FC23-3D6C-406A-BE2C-9E67BAF3DA9B"
},
{
"name": "Iphone 15 Pro",
"request": "launch",
"type": "dart",
"deviceId": "9C9E6EEF-0E9C-4FA9-B201-CBA8AFB0D1D8"
},
{
"name": "Iphone SE",
"request": "launch",

View File

@ -1,5 +1,6 @@
#Wed Apr 03 23:37:40 EET 2024
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
zipStoreBase=GRADLE_USER_HOME

View File

@ -5,6 +5,7 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdown.dart';
import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/room_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart';
import 'package:syncrow_app/features/menu/view/menu_view.dart';
@ -17,26 +18,35 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
part 'home_state.dart';
class HomeCubit extends Cubit<HomeState> {
HomeCubit() : super(SpacesInitial()) {
if (HomeCubit.spaces != null) {
if (selectedSpace == null) {
fetchSpaces().then((value) {
if (selectedSpace != null) {
print('selectedSpace: ${selectedSpace!.name}');
fetchRooms(selectedSpace!);
}
});
}
} else {
fetchSpaces(); // this is for the first time
HomeCubit._() : super(HomeInitial()) {
if (selectedSpace == null) {
fetchSpaces().then((value) {
if (selectedSpace != null) {
fetchRooms(selectedSpace!);
}
});
}
}
static HomeCubit? _instance;
static HomeCubit getInstance() {
// If an instance already exists, return it
_instance ??= HomeCubit._();
return _instance!;
}
void emitSafe(HomeState newState) {
final cubit = this;
if (!cubit.isClosed) {
cubit.emit(newState);
}
}
static HomeCubit get(context) => BlocProvider.of(context);
static List<SpaceModel>? spaces;
List<SpaceModel>? spaces;
static SpaceModel? selectedSpace;
SpaceModel? selectedSpace;
RoomModel? selectedRoom;
@ -46,9 +56,14 @@ class HomeCubit extends Cubit<HomeState> {
var duration = const Duration(milliseconds: 300);
selectSpace(SpaceModel space) {
// selectSpace(SpaceModel space) async {
// selectedSpace = space;
// emit(SpaceSelected(space));
// }
changeSelectedSpace(SpaceModel space) {
selectedSpace = space;
emit(SpaceSelected(space));
emitSafe(SpaceSelected(space));
}
roomSliderPageChanged(int index) {
@ -62,7 +77,7 @@ class HomeCubit extends Cubit<HomeState> {
unselectRoom();
} else {
selectedRoom = selectedSpace!.rooms![index - 1];
emit(RoomSelected(selectedRoom!));
emitSafe(RoomSelected(selectedRoom!));
}
}
@ -77,12 +92,12 @@ class HomeCubit extends Cubit<HomeState> {
unselectRoom();
} else {
selectedRoom = selectedSpace!.rooms![index - 1];
emit(RoomSelected(selectedRoom!));
emitSafe(RoomSelected(selectedRoom!));
}
}
unselectRoom() {
selectedRoom = null;
// selectedRoom = null;
devicesPageController.animateToPage(
0,
duration: duration,
@ -95,35 +110,40 @@ class HomeCubit extends Cubit<HomeState> {
curve: Curves.linear,
);
emit(RoomUnSelected());
emitSafe(RoomUnSelected());
}
//////////////////////////////////////// API ////////////////////////////////////////
fetchSpaces() async {
emit(GetSpacesLoading());
emitSafe(GetSpacesLoading());
try {
spaces = await SpacesAPI.getSpaces();
selectedSpace = spaces!.isNotEmpty ? selectSpace(spaces!.first) : null;
emit(GetSpacesLoaded(spaces!));
selectedSpace = spaces!.isNotEmpty
?
// selectSpace(spaces!.first)
selectedSpace = spaces!.first
: null;
emitSafe(GetSpacesLoaded(spaces!));
} on DioException catch (e) {
emit(GetSpacesError(ServerFailure.fromDioError(e).errMessage));
emitSafe(GetSpacesError(ServerFailure.fromDioError(e).errMessage));
}
}
fetchRooms(SpaceModel space) async {
emit(GetSpaceRoomsLoading());
emitSafe(GetSpaceRoomsLoading());
try {
space.rooms = await SpacesAPI.getRooms(space.id!);
space.rooms = await SpacesAPI.getRoomsBySpaceId(space.id!);
if (space.rooms != null) {
emit(GetSpaceRoomsLoaded(space.rooms!));
emitSafe(GetSpaceRoomsLoaded(space.rooms!));
} else {
emit(GetSpaceRoomsError("No rooms found"));
emitSafe(GetSpaceRoomsError("No rooms found"));
}
} on DioException catch (e) {
emit(GetSpacesError(ServerFailure.fromDioError(e).errMessage));
emitSafe(GetSpacesError(ServerFailure.fromDioError(e).errMessage));
}
}
////////////////////////////////////////Nav////////////////////////////////////////
/////////////////////////////////////// Nav ///////////////////////////////////////
static clear() {
pageIndex = 0;
@ -247,7 +267,10 @@ class HomeCubit extends Cubit<HomeState> {
final List<Widget> pages = [
const DashboardView(),
// const LayoutPage(),
const DevicesViewBody(),
BlocProvider(
create: (context) => DevicesCubit.getInstance(),
child: const DevicesViewBody(),
),
const SceneView(),
const MenuView(),
];
@ -255,7 +278,7 @@ class HomeCubit extends Cubit<HomeState> {
void updatePageIndex(int index) {
pageIndex = index;
emit(NavChangePage());
emitSafe(NavChangePage());
}
}

View File

@ -2,7 +2,7 @@ part of 'home_cubit.dart';
abstract class HomeState {}
class SpacesInitial extends HomeState {}
class HomeInitial extends HomeState {}
class GetSpacesLoading extends HomeState {}

View File

@ -6,7 +6,6 @@ import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/app_layout/view/widgets/app_body.dart';
import 'package:syncrow_app/features/app_layout/view/widgets/default_app_bar.dart';
import 'package:syncrow_app/features/app_layout/view/widgets/default_nav_bar.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@ -15,16 +14,9 @@ class AppLayout extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => HomeCubit(),
),
BlocProvider(
create: (context) => DevicesCubit(),
),
],
child: BlocListener<HomeCubit, HomeState>(
return BlocProvider(
create: (context) => HomeCubit.getInstance(),
child: BlocConsumer<HomeCubit, HomeState>(
listener: (context, state) {
if (state is GetSpacesError) {
ScaffoldMessenger.of(context).showSnackBar(
@ -36,30 +28,38 @@ class AppLayout extends StatelessWidget {
.popUntil((route) => route.settings.name == Routes.authLogin);
}
},
child: BlocBuilder<HomeCubit, HomeState>(
builder: (context, state) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
builder: (context, state) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: SafeArea(
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: HomeCubit.getInstance().spaces != null
? const DefaultAppBar()
: null,
body: const AppBody(),
bottomNavigationBar: const DefaultNavBar(),
// floatingActionButton: FloatingActionButton(
// onPressed: () {
// Navigator.push(
// context,
// CustomPageRoute(
// builder: (context) =>
// const ThreeGangSwitchesView(),
// ),
// );
// },
// child: const Icon(Icons.arrow_forward_ios_sharp),
// ),
),
child: SafeArea(
child: BlocBuilder<HomeCubit, HomeState>(
builder: (context, state) {
return const Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: DefaultAppBar(),
body: AppBody(),
bottomNavigationBar: DefaultNavBar(),
);
},
),
),
);
},
),
),
);
},
),
);
}

View File

@ -3,76 +3,73 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.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/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import '../../../../generated/assets.dart';
class AppBarHomeDropdown extends StatelessWidget {
const AppBarHomeDropdown({
super.key,
});
const AppBarHomeDropdown({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<HomeCubit, HomeState>(
builder: (context, state) {
return HomeCubit.selectedSpace == null
? const Center(child: BodyMedium(text: 'No Home Selected'))
: Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: DropdownButton(
icon: const Icon(
Icons.expand_more,
color: Colors.black,
size: 25,
),
underline: const SizedBox.shrink(),
padding: const EdgeInsets.all(0),
borderRadius: BorderRadius.circular(20),
value: HomeCubit.selectedSpace!.id,
items: HomeCubit.spaces!.map((space) {
return DropdownMenuItem(
value: space.id,
child: SizedBox(
width: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SvgPicture.asset(
Assets.iconsHome,
width: 25,
height: 25,
colorFilter: const ColorFilter.mode(
ColorsManager.textPrimaryColor,
BlendMode.srcIn,
),
),
const SizedBox(width: 5),
Expanded(
child: BodyMedium(
text: space.name ?? "??",
style: context.bodyMedium.copyWith(
fontSize: 15,
color: ColorsManager.textPrimaryColor,
overflow: TextOverflow.ellipsis,
),
),
),
],
return Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: DropdownButton(
icon: const Icon(
Icons.expand_more,
color: Colors.black,
size: 25,
),
underline: const SizedBox.shrink(),
padding: const EdgeInsets.all(0),
borderRadius: BorderRadius.circular(20),
value: HomeCubit.getInstance().selectedSpace!.id,
items: HomeCubit.getInstance().spaces!.map((space) {
return DropdownMenuItem(
value: space.id,
child: SizedBox(
width: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SvgPicture.asset(
Assets.iconsHome,
width: 25,
height: 25,
colorFilter: const ColorFilter.mode(
ColorsManager.textPrimaryColor,
BlendMode.srcIn,
),
),
);
}).toList(),
onChanged: (value) {
if (value != null) {
HomeCubit.get(context).selectSpace(HomeCubit.spaces!
.firstWhere((element) => element.id == value));
}
},
const SizedBox(width: 5),
Expanded(
child: BodyMedium(
text: space.name ?? "??",
style: context.bodyMedium.copyWith(
fontSize: 15,
color: ColorsManager.textPrimaryColor,
overflow: TextOverflow.ellipsis,
),
),
),
],
),
),
);
}).toList(),
onChanged: (value) {
if (value != null) {
HomeCubit.getInstance().changeSelectedSpace(
HomeCubit.getInstance()
.spaces!
.firstWhere((element) => element.id == value));
}
},
),
);
},
);
}

View File

@ -3,7 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import '../../../../generated/assets.dart';
import 'package:syncrow_app/generated/assets.dart';
class AppBody extends StatelessWidget {
const AppBody({
@ -37,9 +37,10 @@ class AppBody extends StatelessWidget {
}
},
builder: (context, state) {
return state is! GetSpacesLoading ||
state is! GetSpaceRoomsLoading
? HomeCubit.get(context).pages[HomeCubit.pageIndex]
return state is! GetSpacesLoading
? state is! GetSpaceRoomsLoading
? HomeCubit.getInstance().pages[HomeCubit.pageIndex]
: const Center(child: CircularProgressIndicator())
: const Center(child: CircularProgressIndicator());
},
),

View File

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
@ -20,11 +19,9 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
backgroundColor: Colors.transparent,
leadingWidth: 150,
toolbarHeight: Constants.appBarHeight,
leading: HomeCubit.spaces != null
? HomeCubit.spaces!.isNotEmpty
? HomeCubit.appBarLeading[
HomeCubit.bottomNavItems[HomeCubit.pageIndex].label]
: const Center(child: BodySmall(text: 'Create Home'))
leading: HomeCubit.getInstance().spaces!.isNotEmpty
? HomeCubit.appBarLeading[
HomeCubit.bottomNavItems[HomeCubit.pageIndex].label]
: null,
actions: HomeCubit.appBarActions[
HomeCubit.bottomNavItems[HomeCubit.pageIndex].label],

View File

@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.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';
@ -15,19 +16,22 @@ class DefaultNavBar extends StatelessWidget {
Widget build(BuildContext context) {
return BlocBuilder<HomeCubit, HomeState>(
builder: (context, state) {
var cubit = HomeCubit.get(context);
var cubit = HomeCubit.getInstance();
return SizedBox(
height: Constants.bottomNavBarHeight,
child: BottomNavigationBar(
backgroundColor: Colors.transparent,
onTap: (int index) {
cubit.updatePageIndex(index);
if (DevicesCubit.get(context).chosenCategoryView != null) {
DevicesCubit().clearCategoriesSelection(context);
}
if (HomeCubit.get(context).selectedRoom != null) {
HomeCubit.get(context).unselectRoom();
}
// if (DevicesCubit.getInstance().chosenCategoryView != null) {
// DevicesCubit.getInstance()
// .clearCategoriesSelection(context);
// }
// if (HomeCubit.getInstance().selectedRoom != null) {
// HomeCubit.getInstance().unselectRoom();
// }
HomeCubit.getInstance().updatePageIndex(index);
},
currentIndex: HomeCubit.pageIndex,
selectedItemColor: ColorsManager.primaryColor,

View File

@ -30,15 +30,17 @@ class LoginForm extends StatelessWidget {
TextFormField(
controller: AuthCubit.get(context).emailController,
validator: (value) {
if (value != null) {
if (value.isEmpty) {
return 'Please enter your email';
}
//Regex for email validation
if (!RegExp(
r'^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$')
.hasMatch(value)) {
return 'Please enter a valid email';
if (state is! AuthTokenError) {
if (value != null) {
if (value.isEmpty) {
return 'Please enter your email';
}
//Regex for email validation
if (!RegExp(
r'^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$')
.hasMatch(value)) {
return 'Please enter a valid email';
}
}
}
return null;
@ -57,13 +59,15 @@ class LoginForm extends StatelessWidget {
TextFormField(
controller: AuthCubit.get(context).passwordController,
validator: (value) {
if (value != null) {
if (value.isNotEmpty) {
if (value.length < 6) {
return 'Password must be at least 8 characters';
if (state is! AuthTokenError) {
if (value != null) {
if (value.isNotEmpty) {
if (value.length < 6) {
return 'Password must be at least 8 characters';
}
} else {
return 'Please enter your password';
}
} else {
return 'Please enter your password';
}
}
return null;

View File

@ -3,7 +3,7 @@ import 'package:syncrow_app/features/dashboard/view/widgets/card_title.dart';
import 'package:syncrow_app/features/shared_widgets/united_text.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
import '../../../../generated/assets.dart';
import 'package:syncrow_app/generated/assets.dart';
class Consumption extends StatelessWidget {
const Consumption({

View File

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:syncrow_app/features/dashboard/view/widgets/live_monitor_widget.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
import '../../../../generated/assets.dart';
import 'package:syncrow_app/generated/assets.dart';
class LiveMonitorTab extends StatelessWidget {
const LiveMonitorTab({

View File

@ -0,0 +1,51 @@
// import 'package:bloc/bloc.dart';
// import 'package:flutter/foundation.dart';
// import 'package:meta/meta.dart';
// import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
// import 'package:syncrow_app/features/devices/model/device_category_model.dart';
// import 'package:syncrow_app/features/devices/model/device_model.dart';
// part 'ac_state.dart';
// class AcCubit extends Cubit<AcState> {
// AcCubit() : super(AcInitial());
// DeviceModel? getSelectedAC() {
// DevicesCategoryModel category = DevicesCubit.allCategories![0];
// for (var device in category.devices) {
// if (device is && device.isSelected) {
// return device;
// }
// }
// return null;
// }
// void setTempToAll(double temperature) {
// for (DeviceModel ac in category.devices) {
// if (ac is DeviceModel) {
// if (ac.temperature != temperature &&
// ac.bounds.min <= temperature &&
// temperature <= ac.bounds.max) {
// setACTemp(ac, temperature);
// }
// }
// }
// universalACTemp = temperature;
// emit(ACsTempChanged(temperature));
// }
// void setACTemp(DeviceModel model, double temp) {
// if (model.bounds.min <= temp && temp <= model.bounds.max) {
// model.temperature = temp;
// }
// emit(ACsTempChanged(temp));
// }
// double getTemp(int index) {
// var device = category.devices[index];
// if (device is DeviceModel) {
// return device.temperature;
// }
// return 0.0; // or any default value you prefer
// }
// }

View File

@ -0,0 +1,6 @@
// part of 'ac_cubit.dart';
// @immutable
// sealed class AcState {}
// final class AcInitial extends AcState {}

View File

@ -8,32 +8,54 @@ import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/lights/lights_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/lights_switches/light_switches.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_view.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/network_exception.dart';
import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
part 'devices_state.dart';
class DevicesCubit extends Cubit<DevicesState> {
DevicesCubit() : super(DevicesInitial()) {
if (HomeCubit.selectedSpace != null) {
fetchGroups(HomeCubit.selectedSpace!.id!);
DevicesCubit._() : super(DevicesInitial()) {
if (HomeCubit.getInstance().selectedSpace != null) {
fetchGroups(HomeCubit.getInstance().selectedSpace!.id!);
for (var room in HomeCubit.getInstance().selectedSpace!.rooms!) {
fetchDevicesByRoomId(room.id!);
}
}
}
bool _isClosed = false;
static DevicesCubit? _instance;
static DevicesCubit getInstance() {
print('device cubit instance found : ${_instance != null}');
print('selected space : ${HomeCubit.getInstance().selectedSpace != null}');
return _instance ??= DevicesCubit._();
}
DeviceModel? selectedDevice;
@override
Future<void> close() {
_isClosed = true;
_instance = null;
return super.close();
}
void emitSafe(DevicesState newState) {
final cubit = this;
if (!cubit.isClosed) {
cubit.emit(newState);
}
}
static DevicesCubit get(context) => BlocProvider.of(context);
static List<DevicesCategoryModel>? allCategories;
@ -46,14 +68,14 @@ class DevicesCubit extends Cubit<DevicesState> {
allCategories![i].isSelected = false;
}
}
emit(DevicesCategoryChanged());
emitSafe(DevicesCategoryChanged());
}
unselectAllCategories() {
for (var category in allCategories!) {
category.isSelected = false;
}
emit(DevicesCategoryChanged());
emitSafe(DevicesCategoryChanged());
}
Widget? get chosenCategoryView {
@ -63,14 +85,14 @@ class DevicesCubit extends Cubit<DevicesState> {
switch (category.type) {
case DeviceType.AC:
return const ACsView();
case DeviceType.Lights:
case DeviceType.LightBulb:
return const LightsView();
case DeviceType.DoorLock:
return const DoorView();
case DeviceType.Curtain:
return const CurtainView();
case DeviceType.ThreeGang:
return const LightSwitchesView();
// case DeviceType.ThreeGang:
// return const ThreeGangSwitchesView();
case DeviceType.Gateway:
return const GateWayView();
default:
@ -97,14 +119,14 @@ class DevicesCubit extends Cubit<DevicesState> {
for (var device in category.devices!) {
if (device.isSelected) {
category.isSelected = false;
emit(DeviceSelected());
emitSafe(DeviceSelected());
return;
}
}
}
}
device.isSelected = !device.isSelected;
emit(DeviceSelected());
emitSafe(DeviceSelected());
}
DeviceModel? getSelectedDevice() {
@ -125,24 +147,24 @@ class DevicesCubit extends Cubit<DevicesState> {
category.devicesStatus = !category.devicesStatus!;
if (category.devices != null) {
for (var device in category.devices!) {
device.status = category.devicesStatus;
device.isOnline = category.devicesStatus;
}
}
} else {
category.devicesStatus = true;
if (category.devices != null) {
for (var device in category.devices!) {
device.status = true;
device.isOnline = true;
}
}
}
updateDevicesStatus(category);
emit(CategorySwitchChanged());
emitSafe(CategorySwitchChanged());
}
turnOnOffDevice(DeviceModel device) {
device.status = !device.status!;
device.isOnline = !device.isOnline!;
DevicesCategoryModel category = allCategories!.firstWhere((category) {
if (category.devices != null) {
return category.devices!.contains(device);
@ -151,26 +173,26 @@ class DevicesCubit extends Cubit<DevicesState> {
}
});
updateDevicesStatus(category);
emit(DeviceSwitchChanged());
emitSafe(DeviceSwitchChanged());
}
updateDevicesStatus(DevicesCategoryModel category) {
if (category.devices != null) {
if (category.devices!.isNotEmpty) {
bool? tempStatus = category.devices![0].status;
bool? tempStatus = category.devices![0].isOnline;
for (var ac in category.devices!) {
//check if there any ac have a different status than the initial ==> turn off the universal switch
if (ac.status != tempStatus) {
if (ac.isOnline != tempStatus) {
category.devicesStatus = null;
emit(DeviceSwitchChanged());
emitSafe(DeviceSwitchChanged());
return;
}
category.devicesStatus = tempStatus;
emit(DeviceSwitchChanged());
emitSafe(DeviceSwitchChanged());
}
} else {
category.devicesStatus = null;
emit(DeviceSwitchChanged());
emitSafe(DeviceSwitchChanged());
}
}
}
@ -179,11 +201,11 @@ class DevicesCubit extends Cubit<DevicesState> {
if (category.devices != null) {
if (category.devices!.isNotEmpty) {
for (var device in category.devices!) {
device.status = false;
device.isOnline = false;
}
changeCategorySwitchValue(category);
updateDevicesStatus(category);
emit(CategorySwitchChanged());
emitSafe(CategorySwitchChanged());
}
}
}
@ -192,11 +214,11 @@ class DevicesCubit extends Cubit<DevicesState> {
if (category.devices != null) {
if (category.devices!.isNotEmpty) {
for (var device in category.devices!) {
device.status = true;
device.isOnline = true;
}
changeCategorySwitchValue(category);
updateDevicesStatus(category);
emit(CategorySwitchChanged());
emitSafe(CategorySwitchChanged());
}
}
}
@ -204,9 +226,9 @@ class DevicesCubit extends Cubit<DevicesState> {
areAllDevicesOff(DevicesCategoryModel category) {
if (category.devices != null) {
for (var device in category.devices!) {
if (device.status ?? false) {
if (device.isOnline ?? false) {
category.devicesStatus = false;
emit(CategorySwitchChanged());
emitSafe(CategorySwitchChanged());
return;
}
}
@ -224,16 +246,34 @@ class DevicesCubit extends Cubit<DevicesState> {
}
Navigator.popUntil(context, (route) => route.isFirst);
emit(DevicesCategoryChanged());
emitSafe(DevicesCategoryChanged());
}
deviceControl(DeviceControlModel control) async {
emit(DeviceControlLoading());
///////////////////////// API CALLS //////////////////////////
deviceControl(DeviceControlModel control, String deviceId) async {
emitSafe(DeviceControlLoading(
code: control.code,
));
try {
await DevicesAPI.controlDevice(control);
emit(DeviceControlSuccess());
await DevicesAPI.controlDevice(control).then((response) {
emitSafe(DeviceControlSuccess(
code: control.code,
));
if (response['success'] ?? false) {
Future.delayed(const Duration(milliseconds: 400), () {
getDevicesStatues(
deviceId,
HomeCubit.getInstance().selectedSpace!.rooms!.indexOf(
HomeCubit.getInstance().selectedRoom!,
),
code: control.code);
});
} else {
emitSafe(DeviceControlError('Failed to control the device'));
}
});
} on DioException catch (e) {
emit(DeviceControlError(ServerFailure.fromDioError(e).errMessage));
emitSafe(DeviceControlError(ServerFailure.fromDioError(e).errMessage));
}
}
@ -241,16 +281,77 @@ class DevicesCubit extends Cubit<DevicesState> {
if (_isClosed) return;
try {
emit(DevicesCategoriesLoading());
emitSafe(DevicesCategoriesLoading());
allCategories = await DevicesAPI.fetchGroups(spaceId);
emit(DevicesCategoriesSuccess());
emitSafe(DevicesCategoriesSuccess());
} on DioException catch (error) {
emit(
emitSafe(
DevicesCategoriesError(ServerFailure.fromDioError(error).errMessage),
);
}
}
fetchDevicesByRoomId(int? roomId) async {
if (_isClosed) return;
if (roomId == null) return;
try {
emitSafe(GetDevicesLoading());
int roomIndex = HomeCubit.getInstance()
.selectedSpace!
.rooms!
.indexWhere((element) => element.id == roomId);
HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices =
await SpacesAPI.getDevicesByRoomId(roomId);
//get status for each device
for (var device in HomeCubit.getInstance()
.selectedSpace!
.rooms![roomIndex]
.devices!) {
getDevicesStatues(device.id!, roomIndex);
}
emitSafe(GetDevicesSuccess());
} on DioException catch (error) {
emitSafe(
GetDevicesError(ServerFailure.fromDioError(error).errMessage),
);
}
}
getDevicesStatues(String deviceId, int roomIndex, {String? code}) async {
if (_isClosed) return;
try {
emitSafe(GetDeviceStatusLoading(code: code));
int deviceIndex = HomeCubit.getInstance()
.selectedSpace!
.rooms![roomIndex]
.devices!
.indexWhere((element) => element.id == deviceId);
List<StatusModel> statuses = [];
var response = await DevicesAPI.getDeviceStatus(deviceId);
// if (response['result']['status'].length > 4)
// print('response : ${response['result']['status'][4]}');
for (var status in response['result']['status']) {
statuses.add(StatusModel.fromJson(status));
}
HomeCubit.getInstance()
.selectedSpace!
.rooms![roomIndex]
.devices![deviceIndex]
.status = statuses;
emitSafe(GetDeviceStatusSuccess(code: code));
} on DioException catch (error) {
emitSafe(
GetDeviceStatusError(ServerFailure.fromDioError(error).errMessage),
);
}
}
///Lights
onHorizontalDragUpdate(DeviceModel light, double dx, double screenWidth) {
double newBrightness = (dx / (screenWidth - 15) * 100);
@ -272,17 +373,17 @@ class DevicesCubit extends Cubit<DevicesState> {
// setLightingMode(DeviceModel light, LightMode mode) {
// light.lightingMode =
// lightModes.entries.firstWhere((element) => element.value == mode).key;
// emit(LightModeChanged(mode));
// emitSafe(LightModeChanged(mode));
// }
//
// toggleLight(DeviceModel light) {
// light.status != null ? light.status = !light.status! : light.status = true;
// emit(LightToggled(light));
// light.isOnline != null ? light.isOnline = !light.isOnline! : light.isOnline = true;
// emitSafe(LightToggled(light));
// }
//
// setColor(DeviceModel light, int color) {
// light.color = color;
// emit(LightColorChanged(color));
// emitSafe(LightColorChanged(color));
// }
//
// int getBrightness(DeviceModel light) {
@ -293,48 +394,9 @@ class DevicesCubit extends Cubit<DevicesState> {
// value = (value / 5).ceil() * 5;
// if (value != light.brightness) {
// light.brightness = value;
// emit(LightBrightnessChanged(value));
// emitSafe(LightBrightnessChanged(value));
// }
// }
///ACs
// DeviceModel? getSelectedAC() {
// for (var ac in category.devices) {
// if (ac is DeviceModel && ac.isSelected) {
// return ac;
// }
// }
// return null;
// }
//
// void setTempToAll(double temperature) {
// for (DeviceModel ac in category.devices) {
// if (ac is DeviceModel) {
// if (ac.temperature != temperature &&
// ac.bounds.min <= temperature &&
// temperature <= ac.bounds.max) {
// setACTemp(ac, temperature);
// }
// }
// }
// universalACTemp = temperature;
// emit(ACsTempChanged(temperature));
// }
//
// void setACTemp(DeviceModel model, double temp) {
// if (model.bounds.min <= temp && temp <= model.bounds.max) {
// model.temperature = temp;
// }
// emit(ACsTempChanged(temp));
// }
//
// double getTemp(int index) {
// var device = category.devices[index];
// if (device is DeviceModel) {
// return device.temperature;
// }
// return 0.0; // or any default value you prefer
// }
}
enum LightMode {

View File

@ -14,6 +14,35 @@ class DevicesFailure extends DevicesState {}
class ChangeIndex extends DevicesState {}
// Devices
class GetDeviceStatusLoading extends DevicesState {
final String? code;
GetDeviceStatusLoading({this.code});
}
class GetDeviceStatusSuccess extends DevicesState {
final String? code;
GetDeviceStatusSuccess({this.code});
}
class GetDeviceStatusError extends DevicesState {
final String errorMsg;
GetDeviceStatusError(this.errorMsg);
}
class GetDevicesLoading extends DevicesState {}
class GetDevicesSuccess extends DevicesState {}
class GetDevicesError extends DevicesState {
final String errorMsg;
GetDevicesError(this.errorMsg);
}
class DevicesCategoryChanged extends DevicesState {}
class CategorySwitchChanged extends DevicesState {}
@ -23,9 +52,17 @@ class DeviceSwitchChanged extends DevicesState {}
class DeviceSelected extends DevicesState {}
// Device Control
class DeviceControlLoading extends DevicesState {}
class DeviceControlLoading extends DevicesState {
final String? code;
class DeviceControlSuccess extends DevicesState {}
DeviceControlLoading({this.code});
}
class DeviceControlSuccess extends DevicesState {
final String? code;
DeviceControlSuccess({this.code});
}
class DeviceControlError extends DevicesState {
final String errorMsg;

View File

@ -24,9 +24,9 @@ class DevicesCategoryModel {
//sets the initial status of the devices
if (devices != null) {
if (devices!.isNotEmpty) {
bool tempStatus = devices!.first.status ?? false;
bool tempStatus = devices!.first.isOnline ?? false;
for (var device in devices!) {
if (device.status != tempStatus) {
if (device.isOnline != tempStatus) {
devicesStatus = false;
break;
}
@ -41,9 +41,9 @@ class DevicesCategoryModel {
DevicesCategoryModel.fromJson(Map<String, dynamic> json)
: name = json['groupName'],
id = json['groupId'],
type = deviceTypeMap[json['groupName']] ?? DeviceType.Other,
type = devicesTypesMap[json['productType']] ?? DeviceType.Other,
icon = deviceTypeIconMap[
deviceTypeMap[json['groupName']] ?? DeviceType.Other] ??
devicesTypesMap[json['productType']] ?? DeviceType.Other] ??
'',
devices = [],
isSelected = false;
@ -53,22 +53,14 @@ class DevicesCategoryModel {
}
}
Map<String, DeviceType> deviceTypeMap = {
'Ceiling Presence Sensors': DeviceType.Sensors,
'Wall presence sensor': DeviceType.Sensors,
'Door Locks': DeviceType.DoorLock,
'Gateways': DeviceType.Gateway,
'ACs': DeviceType.AC,
'3Gang': DeviceType.Gang,
};
Map<DeviceType, String> deviceTypeIconMap = {
DeviceType.AC: Assets.iconsAC,
DeviceType.Lights: Assets.iconsLight,
DeviceType.LightBulb: Assets.iconsLight,
DeviceType.DoorLock: Assets.iconsDoorLock,
DeviceType.Curtain: Assets.iconsCurtain,
DeviceType.Gateway: Assets.iconsGateway,
DeviceType.Sensors: Assets.iconsSensors,
DeviceType.Gang: Assets.iconsGang,
DeviceType.CeilingSensor: Assets.iconsSensors,
DeviceType.WallSensor: Assets.iconsSensors,
DeviceType.ThreeGang: Assets.iconsGang,
DeviceType.Other: Assets.iconsAC,
};

View File

@ -1,7 +1,7 @@
class DeviceControlModel {
String? deviceId;
String? code;
bool? value;
dynamic value;
DeviceControlModel({
required this.deviceId,

View File

@ -1,46 +1,146 @@
import 'package:syncrow_app/features/devices/model/function_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class DeviceModel {
final int? id;
final String? name;
final DeviceType? type;
bool? status;
final String? image;
final double? timer;
late final String icon;
int? activeTime;
String? category; //unused
String? categoryName; //unused
int? createTime; //unused
String? gatewayId; //unused
String? icon; //unused
String? id;
String? ip; //unused
double? lat; //unused
String? localKey;
double? lon; //unused
String? model;
String? name;
String? nodeId; //remove
bool? isOnline;
List<StatusModel> status = [];
String? ownerId; //unused
String? productId; //unused
String? productName;
bool? isSub; //unused
String? timeZone;
int? updateTime;
String? uuid;
DeviceType? productType;
bool isSelected = false;
late List<FunctionModel> functions;
DeviceModel({
required this.id,
required this.name,
required this.type,
this.activeTime,
this.category,
this.categoryName,
this.createTime,
this.gatewayId,
this.icon,
this.id,
this.ip,
this.lat,
this.localKey,
this.lon,
this.model,
this.name,
this.nodeId,
this.isOnline,
required this.status,
required this.image,
required this.timer,
required this.functions,
this.ownerId,
this.productId,
this.productName,
this.isSub,
this.timeZone,
this.updateTime,
this.uuid,
this.productType,
}) {
switch (type) {
case DeviceType.AC:
icon = Assets.iconsAC;
break;
case DeviceType.Lights:
icon = Assets.iconsLight;
break;
case DeviceType.DoorLock:
icon = Assets.iconsDoorLock;
break;
case DeviceType.Curtain:
icon = Assets.iconsCurtain;
break;
case DeviceType.Gateway:
icon = Assets.iconsGateway;
break;
default:
icon = '';
}
functions = getFunctions(productType!);
}
factory DeviceModel.fromJson(Map<String, dynamic> json) {
String icon = '';
DeviceType type = devicesTypesMap[json['productId']] ?? DeviceType.Other;
if (type == DeviceType.LightBulb) {
icon = Assets.iconsLight;
} else if (type == DeviceType.CeilingSensor ||
type == DeviceType.WallSensor) {
icon = Assets.iconsSensors;
} else if (type == DeviceType.AC) {
icon = Assets.iconsAC;
} else if (type == DeviceType.DoorLock) {
icon = Assets.iconsDoorLock;
} else if (type == DeviceType.Curtain) {
icon = Assets.iconsCurtain;
} else if (type == DeviceType.ThreeGang) {
icon = Assets.icons3GangSwitch;
} else if (type == DeviceType.Gateway) {
icon = Assets.iconsGateway;
} else {
icon = Assets.iconsLogo;
}
return DeviceModel(
activeTime: json['activeTime'],
category: json['category'],
categoryName: json['categoryName'],
createTime: json['createTime'],
gatewayId: json['gatewayId'],
icon: icon,
id: json['id'],
ip: json['ip'],
lat: double.tryParse(json['lat']),
localKey: json['localKey'],
lon: double.tryParse(json['lon']),
model: json['model'],
name: json['name'],
nodeId: json['nodeId'],
isOnline: json['online'],
ownerId: json['ownerId'],
productId: json['productId'],
productName: json['productName'],
isSub: json['sub'],
timeZone: json['timeZone'],
updateTime: json['updateTime'],
uuid: json['uuid'],
productType: type,
status: [],
// json['status']
// .map<StatusModel>((e) => StatusModel.fromJson(e))
// .toList(),
// devicesTypesMap[json['productName']] ?? DeviceType.Other,
);
}
Map<String, dynamic> toJson() {
return {
'activeTime': activeTime,
'category': category,
'categoryName': categoryName,
'createTime': createTime,
'gatewayId': gatewayId,
'icon': icon,
'id': id,
'ip': ip,
'lat': lat,
'localKey': localKey,
'lon': lon,
'model': model,
'name': name,
'nodeId': nodeId,
'online': isOnline,
'ownerId': ownerId,
'productId': productId,
'productName': productName,
'sub': isSub,
'timeZone': timeZone,
'updateTime': updateTime,
'uuid': uuid,
'productType': productType,
};
}
List<FunctionModel> getFunctions(DeviceType type) =>
devicesFunctionsMap[productType] ?? [];
}

View File

@ -1,21 +1,10 @@
//{
// "code": "switch_1",
// "desc": "switch 1",
// "name": "switch 1",
// "type": "Boolean",
// "values": "{}"
// }
class FunctionModel {
String? code;
String? desc;
String? name;
String? type;
String? values;
FunctionModel({
required this.code,
required this.desc,
required this.name,
required this.type,
required this.values,
});
@ -23,8 +12,6 @@ class FunctionModel {
factory FunctionModel.fromJson(Map<String, dynamic> json) {
return FunctionModel(
code: json['code'],
desc: json['desc'],
name: json['name'],
type: json['type'],
values: json['values'],
);
@ -33,8 +20,6 @@ class FunctionModel {
Map<String, dynamic> toJson() {
return {
'code': code,
'desc': desc,
'name': name,
'type': type,
'values': values,
};

View File

@ -1,30 +1,36 @@
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
class RoomModel {
final int? id;
final String? name;
final List<DevicesCategoryModel>? categories;
List<DeviceModel>? devices;
RoomModel({
required this.id,
required this.name,
required this.categories,
required this.devices,
});
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'devices': categories,
'devices': devices,
};
}
factory RoomModel.fromJson(Map<String, dynamic> json) {
List<DeviceModel> devices = [];
if (json['devices'] != null) {
for (var device in json['devices']) {
devices.add(DeviceModel.fromJson(device));
}
}
return RoomModel(
id: json['roomId'],
name: json['roomName'],
categories: json['devices'],
devices: devices,
);
}
}

View File

@ -0,0 +1,23 @@
class StatusModel {
String? code;
dynamic value;
StatusModel({
required this.code,
required this.value,
});
factory StatusModel.fromJson(Map<String, dynamic> json) {
return StatusModel(
code: json['code'],
value: json['value'],
);
}
Map<String, dynamic> toJson() {
return {
'code': code,
'value': value,
};
}
}

View File

@ -1,20 +1,17 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart';
// import 'package:flutter/material.dart';
// import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart';
class DevicesView extends StatelessWidget {
const DevicesView({super.key});
// class DevicesView extends StatelessWidget {
// const DevicesView({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) => Container(
padding: const EdgeInsets.all(8),
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
child: const DevicesViewBody(),
),
);
}
}
// @override
// Widget build(BuildContext context) {
// print('built DevicesView');
// return Container(
// padding: const EdgeInsets.all(8),
// width: MediaQuery.of(context).size.width,
// height: MediaQuery.of(context).size.height,
// child: const DevicesViewBody(),
// );
// }
// }

View File

@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.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/ac_interface_controls.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart';
@ -22,65 +24,78 @@ class AcInterface extends StatelessWidget {
statusBarIconBrightness: Brightness.light,
),
child: SafeArea(
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: BodyLarge(
text: deviceModel.name ?? "",
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
body: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.imagesBackground,
child: BlocConsumer<DevicesCubit, DevicesState>(
listener: (context, state) {
if (state is DeviceControlError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.errorMsg),
),
fit: BoxFit.cover,
opacity: 0.4,
),
),
child: Padding(
padding: EdgeInsets.only(
top: Constants.appBarHeight,
left: Constants.defaultPadding,
right: Constants.defaultPadding,
),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 380,
),
child: AcInterfaceTempUnit(
deviceModel: deviceModel,
),
),
const SizedBox(
height: 10,
),
ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 120,
),
child: AcInterfaceControls(
deviceModel: deviceModel,
),
),
],
);
}
},
builder: (context, state) {
return Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: BodyLarge(
text: deviceModel.name ?? "",
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
),
),
body: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.imagesBackground,
),
fit: BoxFit.cover,
opacity: 0.4,
),
),
child: Padding(
padding: EdgeInsets.only(
top: Constants.appBarHeight,
left: Constants.defaultPadding,
right: Constants.defaultPadding,
),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 380,
),
child: AcInterfaceTempUnit(
acDevice: deviceModel,
),
),
const SizedBox(
height: 10,
),
ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 120,
),
child: AcInterfaceControls(
deviceModel: deviceModel,
),
),
],
),
),
),
),
);
},
),
),
);

View File

@ -1,10 +1,11 @@
import 'package:flutter/material.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/ac_mode_control_unit.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import '../../../../../generated/assets.dart';
import 'package:syncrow_app/generated/assets.dart';
class AcInterfaceControls extends StatelessWidget {
const AcInterfaceControls({
@ -16,38 +17,42 @@ class AcInterfaceControls extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
ACModeControlUnit(model: deviceModel),
const SizedBox(height: 10),
Row(
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
return Column(
children: [
Flexible(
child: InkWell(
onTap: () {},
child: DefaultContainer(
height: 55,
child: Center(
child: SvgPicture.asset(Assets.iconsAutomatedClock),
ACModeControlUnit(acDevice: deviceModel),
const SizedBox(height: 10),
Row(
children: [
Flexible(
child: InkWell(
onTap: () {},
child: DefaultContainer(
height: 55,
child: Center(
child: SvgPicture.asset(Assets.iconsAutomatedClock),
),
),
),
),
),
),
const SizedBox(width: 10),
Flexible(
child: InkWell(
onTap: () {},
child: DefaultContainer(
height: 55,
child: Center(
child: SvgPicture.asset(Assets.iconsLock),
const SizedBox(width: 10),
Flexible(
child: InkWell(
onTap: () {},
child: DefaultContainer(
height: 55,
child: Center(
child: SvgPicture.asset(Assets.iconsLock),
),
),
),
),
),
),
],
)
],
)
],
);
},
);
}
}

View File

@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:sleek_circular_slider/sleek_circular_slider.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
@ -10,20 +11,25 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dar
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.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 AcInterfaceTempUnit extends StatelessWidget {
const AcInterfaceTempUnit({
super.key,
required this.deviceModel,
required this.acDevice,
});
final DeviceModel deviceModel;
final DeviceModel acDevice;
@override
Widget build(BuildContext context) {
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
double setToTemp = acDevice.status
.firstWhere((element) => element.code == 'temp_set')
.value /
10;
return DefaultContainer(
child: Column(
children: [
@ -72,14 +78,24 @@ class AcInterfaceTempUnit extends StatelessWidget {
),
// min: DeviceModel.bounds.min,
// max: DeviceModel.bounds.max,
// initialValue: DeviceModel.temperature,
min: 20,
max: 30,
initialValue: acDevice.status
.firstWhere(
(element) => element.code == 'temp_current')
.value /
10,
onChange: (value) {
String valueAsString = value.toStringAsFixed(1);
if (valueAsString.endsWith(".0") ||
valueAsString.endsWith(".5")) {
value = double.parse(valueAsString);
// DevicesCubit.get(context)
// .setACTemp(DeviceModel, value);
DevicesCubit.getInstance().deviceControl(
DeviceControlModel(
deviceId: acDevice.id,
code: 'temp_set',
value: value * 10),
acDevice.id!);
}
},
),
@ -94,9 +110,23 @@ class AcInterfaceTempUnit extends StatelessWidget {
dimension: 24,
child: InkWell(
onTap: () {
// DevicesCubit.get(context)
// .setACTemp(DeviceModel, DeviceModel.coolTo);
// DeviceModel.coolTo -= .5;
//TODO refactor the loading check
if (state is GetDeviceStatusLoading &&
state.code == 'temp_set' ||
state is DeviceControlSuccess &&
state.code == 'temp_set' ||
state is DeviceControlLoading &&
state.code == 'temp_set') {
return;
}
if (setToTemp > 20) {
DevicesCubit.getInstance().deviceControl(
DeviceControlModel(
deviceId: acDevice.id,
code: 'temp_set',
value: (setToTemp - 0.5) * 10),
acDevice.id!);
}
},
child: SvgPicture.asset(
Assets.iconsMinus,
@ -107,10 +137,16 @@ class AcInterfaceTempUnit extends StatelessWidget {
children: [
BodyLarge(
// text: "${DeviceModel.coolTo}° C",
text: '24° C',
text: '$setToTemp° C',
style: context.bodyLarge.copyWith(
color:
ColorsManager.primaryColor.withOpacity(0.6),
color: state is GetDeviceStatusLoading &&
state.code == 'temp_set' ||
state is DeviceControlSuccess &&
state.code == 'temp_set' ||
state is DeviceControlLoading &&
state.code == 'temp_set'
? Colors.grey
: ColorsManager.primaryColor.withOpacity(0.6),
fontWeight: FontsManager.bold,
fontSize: 30,
height: 0),
@ -125,9 +161,22 @@ class AcInterfaceTempUnit extends StatelessWidget {
dimension: 24,
child: InkWell(
onTap: () {
// DevicesCubit.get(context)
// .setACTemp(DeviceModel, DeviceModel.coolTo);
// DeviceModel.coolTo += .5;
if (state is GetDeviceStatusLoading &&
state.code == 'temp_set' ||
state is DeviceControlSuccess &&
state.code == 'temp_set' ||
state is DeviceControlLoading &&
state.code == 'temp_set') {
return;
}
if (setToTemp < 30) {
DevicesCubit.getInstance().deviceControl(
DeviceControlModel(
deviceId: acDevice.id,
code: 'temp_set',
value: (setToTemp + 0.5) * 10),
acDevice.id!);
}
},
child: SvgPicture.asset(
Assets.iconsPlus,

View File

@ -1,75 +1,96 @@
import 'package:flutter/material.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_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import '../../../../../generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class ACModeControlUnit extends StatefulWidget {
const ACModeControlUnit({
super.key,
required this.model,
required this.acDevice,
});
final DeviceModel model;
final DeviceModel acDevice;
@override
State<ACModeControlUnit> createState() => _ACModeControlUnitState();
}
class _ACModeControlUnitState extends State<ACModeControlUnit> {
var fanSpeeds = [
Assets.iconsFan0,
Assets.iconsFan1,
Assets.iconsFan2,
Assets.iconsFan3,
];
var tempModes = [
Assets.iconsSunnyMode,
Assets.iconsColdMode,
Assets.iconsWindyMode,
];
@override
Widget build(BuildContext context) {
//TODO Move the fanSpeeds and tempModes to the Cubit
return Row(
children: [
Flexible(
child: InkWell(
onTap: () {
setState(() {
// widget.model.fanSpeed =
// widget.model.fanSpeed == 3 ? 0 : widget.model.fanSpeed + 1;
});
},
child: const DefaultContainer(
height: 55,
child: Center(
// child: SvgPicture.asset(fanSpeeds[widget.model.fanSpeed]),
),
),
),
),
const SizedBox(width: 10),
Flexible(
child: InkWell(
onTap: () {
setState(() {
// widget.model.tempMode =
// widget.model.tempMode == 2 ? 0 : widget.model.tempMode + 1;
});
},
child: const DefaultContainer(
height: 55,
child: Center(
// child: SvgPicture.asset(tempModes[widget.model.tempMode]),
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
FanSpeeds fanSpeed = fanSpeedsMap[widget.acDevice.status
.firstWhere((element) => element.code == 'level')
.value]!;
TempModes tempMode = tempModesMap[widget.acDevice.status
.firstWhere((element) => element.code == 'mode')
.value]!;
return Row(
children: [
Flexible(
child: InkWell(
onTap: () {
// print(
// '\n\ncurrentFanSpeed:$fanSpeed \nchanged to:\t${fanSpeedsMap[getNextFanSpeedKey(fanSpeed)]!}\nKey:\t\t\"${reversedFanSpeedsMap[fanSpeedsMap[getNextFanSpeedKey(fanSpeed)]!]!}\"');
),
fanSpeed = fanSpeedsMap[getNextFanSpeedKey(fanSpeed)]!;
DevicesCubit.getInstance().deviceControl(
DeviceControlModel(
deviceId: widget.acDevice.id,
code: 'level',
value: reversedFanSpeedsMap[fanSpeed]!),
widget.acDevice.id!);
},
child: DefaultContainer(
height: 55,
child: Center(
child: state is GetDeviceStatusLoading &&
state.code == 'level' ||
state is DeviceControlSuccess &&
state.code == 'level' ||
state is DeviceControlLoading &&
state.code == 'level'
? const CircularProgressIndicator()
: SvgPicture.asset(fanSpeedsIconMap[fanSpeed]!)),
),
),
),
),
),
],
const SizedBox(width: 10),
Flexible(
child: InkWell(
onTap: () {
tempMode = tempModesMap[getNextItem(tempModesMap, tempMode)]!;
DevicesCubit.getInstance().deviceControl(
DeviceControlModel(
deviceId: widget.acDevice.id,
code: 'mode',
value: reversedTempModesMap[tempMode]!),
widget.acDevice.id!);
},
child: DefaultContainer(
height: 55,
child: Center(
child: state is GetDeviceStatusLoading &&
state.code == 'mode' ||
state is DeviceControlSuccess &&
state.code == 'mode' ||
state is DeviceControlLoading &&
state.code == 'mode'
? const CircularProgressIndicator()
: SvgPicture.asset(tempModesIconMap[tempMode]!),
),
),
),
),
],
);
},
);
}
}

View File

@ -8,7 +8,7 @@ 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/resource_manager/color_manager.dart';
import '../../../../../generated/assets.dart';
import 'package:syncrow_app/generated/assets.dart';
class ACTempWidget extends StatelessWidget {
const ACTempWidget(
@ -31,7 +31,7 @@ class ACTempWidget extends StatelessWidget {
dimension: 24,
child: InkWell(
onTap: () {
// DevicesCubit.get(context)
// DevicesCubit.getInstance()
// .setACTemp(DeviceModel, DeviceModel.temperature - 0.5);
},
child: SvgPicture.asset(
@ -51,7 +51,7 @@ class ACTempWidget extends StatelessWidget {
dimension: 24,
child: InkWell(
onTap: () {
// DevicesCubit.get(context)
// DevicesCubit.getInstance()
// .setACTemp(DeviceModel, DeviceModel.temperature + 0.5);
},
child: SvgPicture.asset(

View File

@ -27,7 +27,7 @@ class ACsList extends StatelessWidget {
const BodySmall(text: "All ACs"),
const SizedBox(height: 5),
UniversalSwitch(
category: DevicesCubit.get(context).chosenCategory!,
category: DevicesCubit.getInstance().chosenCategory!,
),
const SizedBox(height: 10),
const UniversalACTemp(),
@ -39,9 +39,9 @@ class ACsList extends StatelessWidget {
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(0),
itemCount:
DevicesCubit.get(context).chosenCategory!.devices!.length,
DevicesCubit.getInstance().chosenCategory!.devices!.length,
itemBuilder: (context, index) {
DeviceModel ac = DevicesCubit.get(context)
DeviceModel ac = DevicesCubit.getInstance()
.chosenCategory!
.devices![index];
return Column(
@ -52,14 +52,14 @@ class ACsList extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
BodySmall(
text: DevicesCubit.get(context)
text: DevicesCubit.getInstance()
.chosenCategory!
.devices![index]
.name ??
""),
IconButton(
onPressed: () {
DevicesCubit.get(context).selectDevice(ac);
DevicesCubit.getInstance().selectDevice(ac);
},
icon: const Icon(
Icons.arrow_forward_ios,
@ -84,7 +84,7 @@ class ACsList extends StatelessWidget {
),
const SizedBox(height: 10),
ACModeControlUnit(
model: ac,
acDevice: ac,
),
const SizedBox(height: 10),
],

View File

@ -6,10 +6,9 @@ import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_list.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/category_view_app_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import '../../../../../generated/assets.dart';
import '../../../../../utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/generated/assets.dart';
class ACsView extends StatelessWidget {
const ACsView({super.key});
@ -21,9 +20,9 @@ class ACsView extends StatelessWidget {
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
DeviceModel? selectedAC;
if (DevicesCubit.get(context).getSelectedDevice() is DeviceModel) {
if (DevicesCubit.getInstance().getSelectedDevice() is DeviceModel) {
selectedAC =
DevicesCubit.get(context).getSelectedDevice() as DeviceModel;
DevicesCubit.getInstance().getSelectedDevice() as DeviceModel;
}
return AnnotatedRegion(
value: SystemUiOverlayStyle(

View File

@ -2,10 +2,9 @@ import 'package:flutter/material.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/display_medium.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import '../../../../../utils/resource_manager/color_manager.dart';
class CategoryViewAppBar extends StatelessWidget
implements PreferredSizeWidget {
const CategoryViewAppBar({
@ -20,7 +19,7 @@ class CategoryViewAppBar extends StatelessWidget
toolbarHeight: Constants.appBarHeight,
centerTitle: true,
title: DisplayMedium(
text: DevicesCubit.get(context).chosenCategory!.name!,
text: DevicesCubit.getInstance().chosenCategory!.name!,
style: context.displayMedium.copyWith(
color: ColorsManager.primaryColor,
fontWeight: FontWeight.bold,
@ -32,7 +31,7 @@ class CategoryViewAppBar extends StatelessWidget
color: ColorsManager.textPrimaryColor,
),
onPressed: () {
DevicesCubit.get(context).clearCategoriesSelection(context);
DevicesCubit.getInstance().clearCategoriesSelection(context);
},
),
);

View File

@ -2,12 +2,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.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 '../../../../../generated/assets.dart';
import '../../../../../utils/resource_manager/color_manager.dart';
import '../../../../shared_widgets/default_container.dart';
import '../../../../shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class UniversalACTemp extends StatelessWidget {
const UniversalACTemp({
@ -27,7 +26,7 @@ class UniversalACTemp extends StatelessWidget {
dimension: 24,
child: InkWell(
onTap: () {
// DevicesCubit.get(context)
// DevicesCubit.getInstance()
// .setTempToAll(DevicesCubit.universalACTemp - .5);
},
child: SvgPicture.asset(
@ -47,7 +46,7 @@ class UniversalACTemp extends StatelessWidget {
dimension: 24,
child: InkWell(
onTap: () {
// DevicesCubit.get(context)
// DevicesCubit.getInstance()
// .setTempToAll(DevicesCubit.universalACTemp + .5);
},
child: SvgPicture.asset(

View File

@ -25,7 +25,7 @@ class CurtainList extends StatelessWidget {
const BodySmall(text: "All Curtains"),
const SizedBox(height: 5),
UniversalSwitch(
category: DevicesCubit.get(context).chosenCategory!,
category: DevicesCubit.getInstance().chosenCategory!,
),
// other ACs controls
@ -34,16 +34,17 @@ class CurtainList extends StatelessWidget {
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(0),
itemCount:
DevicesCubit.get(context).chosenCategory!.devices!.length,
DevicesCubit.getInstance().chosenCategory!.devices!.length,
itemBuilder: (context, index) {
DeviceModel curtain =
DevicesCubit.get(context).chosenCategory!.devices![index];
DeviceModel curtain = DevicesCubit.getInstance()
.chosenCategory!
.devices![index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
BodySmall(
text: DevicesCubit.get(context)
text: DevicesCubit.getInstance()
.chosenCategory!
.devices![index]
.name ??

View File

@ -20,13 +20,13 @@ class CurtainView extends StatelessWidget {
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: SafeArea(
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: const CategoryViewAppBar(),
body: Container(
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: const CategoryViewAppBar(),
body: SafeArea(
child: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
decoration: const BoxDecoration(

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_view_header.dart';
import 'package:syncrow_app/features/devices/view/widgets/room_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/rooms_slider.dart';
@ -9,8 +10,6 @@ import 'package:syncrow_app/features/devices/view/widgets/wizard_page.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import '../../bloc/devices_cubit.dart';
class DevicesViewBody extends StatelessWidget {
const DevicesViewBody({
super.key,
@ -18,73 +17,95 @@ class DevicesViewBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<HomeCubit, HomeState>(
return BlocConsumer<DevicesCubit, DevicesState>(
listener: (context, state) {
if (state is GetDevicesError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.errorMsg),
),
);
} else if (state is DevicesCategoriesError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.errorMsg),
),
);
} else if (state is DeviceControlError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.errorMsg),
),
);
}
},
builder: (context, state) {
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
//TODO : move to NavigationCubit
if (state is DevicesLoading) {
return const Center(child: CircularProgressIndicator());
} else {
return Padding(
padding: EdgeInsets.only(
top: Constants.appBarHeight,
bottom: Constants.bottomNavBarHeight,
if (state is DevicesLoading ||
state is GetDevicesLoading ||
state is DevicesCategoriesLoading) {
return const Center(child: CircularProgressIndicator());
} else {
return Padding(
padding: EdgeInsets.only(
top: Constants.appBarHeight,
bottom: Constants.bottomNavBarHeight,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const DevicesViewHeader(),
const RoomsSlider(),
const SizedBox(
height: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const DevicesViewHeader(),
const RoomsSlider(),
const SizedBox(
height: 10,
),
Expanded(
child: PageView(
controller:
HomeCubit.get(context).devicesPageController,
onPageChanged: (index) {
HomeCubit.get(context).devicesPageChanged(index);
},
children: [
const WizardPage(),
if (HomeCubit.selectedSpace != null)
if (HomeCubit.selectedSpace!.rooms != null)
...HomeCubit.selectedSpace!.rooms!.map(
(room) {
return RoomPage(
room: room,
);
},
)
],
),
),
HomeCubit.selectedSpace != null
? Padding(
padding: const EdgeInsets.symmetric(
vertical: 7,
),
child: SmoothPageIndicator(
controller:
HomeCubit.get(context).devicesPageController,
count: HomeCubit.selectedSpace!.rooms!.length + 1,
effect: const WormEffect(
paintStyle: PaintingStyle.stroke,
dotHeight: 8,
dotWidth: 8,
),
),
Expanded(
child: PageView(
controller: HomeCubit.getInstance().devicesPageController,
onPageChanged: (index) {
HomeCubit.getInstance().devicesPageChanged(index);
},
children: [
const WizardPage(),
if (HomeCubit.getInstance().selectedSpace != null)
if (HomeCubit.getInstance().selectedSpace!.rooms !=
null)
...HomeCubit.getInstance().selectedSpace!.rooms!.map(
(room) {
return RoomPage(
room: room,
);
},
)
: const Center(
child: BodyLarge(text: 'No Home Found'),
),
],
],
),
),
);
}
},
);
HomeCubit.getInstance().selectedSpace != null
? Padding(
padding: const EdgeInsets.symmetric(
vertical: 7,
),
child: SmoothPageIndicator(
controller:
HomeCubit.getInstance().devicesPageController,
count: HomeCubit.getInstance()
.selectedSpace!
.rooms!
.length +
1,
effect: const WormEffect(
paintStyle: PaintingStyle.stroke,
dotHeight: 8,
dotWidth: 8,
),
),
)
: const Center(
child: BodyLarge(text: 'No Home Found'),
),
],
),
);
}
},
);
}

View File

@ -20,7 +20,7 @@ class LightBrightness extends StatelessWidget {
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
return GestureDetector(
// onHorizontalDragUpdate: (details) => DevicesCubit().get(context)
// onHorizontalDragUpdate: (details) => DevicesCubit.getInstance().get(context)
// .onHorizontalDragUpdate(light, details.localPosition.dx,
// MediaQuery.of(context).size.width - 15),
child: Stack(

View File

@ -1,10 +1,14 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.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/lights/light_interface_contols.dart';
import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface_switch.dart';
import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface_timer.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class LightInterface extends StatelessWidget {
const LightInterface({super.key, required this.light});
@ -15,16 +19,36 @@ class LightInterface extends StatelessWidget {
Widget build(BuildContext context) {
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
return Padding(
padding: const EdgeInsets.only(top: 70, right: 20, left: 20),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
LightInterfaceSwitch(light: light),
LightInterfaceContols(light: light),
const LightInterfaceTimer(),
],
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: BodyLarge(
text: light.name ?? "",
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
body: Padding(
padding: const EdgeInsets.only(top: 70, right: 20, left: 20),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
LightInterfaceSwitch(light: light),
LightInterfaceContols(light: light),
const LightInterfaceTimer(),
],
),
),
),
),
);

View File

@ -27,10 +27,10 @@ class LightInterfaceModes extends StatelessWidget {
Wrap(
spacing: 25,
children: List.generate(
DevicesCubit.get(context).lightModes.length,
DevicesCubit.getInstance().lightModes.length,
(index) => InkWell(
// onTap: () => DevicesCubit.get(context).setLightingMode(
// light, DevicesCubit.get(context).lightModes[index]!),
// onTap: () => DevicesCubit.getInstance().setLightingMode(
// light, DevicesCubit.getInstance().lightModes[index]!),
child: Column(
children: [
Container(

View File

@ -1,12 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import '../../../../../generated/assets.dart';
import '../../../../../utils/resource_manager/strings_manager.dart';
import '../../../../shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
class LightInterfaceRecentColor extends StatelessWidget {
const LightInterfaceRecentColor({
@ -34,7 +34,7 @@ class LightInterfaceRecentColor extends StatelessWidget {
4,
(index) => InkWell(
// onTap: () {
// DevicesCubit.get(context)
// DevicesCubit.getInstance()
// .setColor(light, light.recentColors[index]);
// },
child: Container(

View File

@ -60,7 +60,7 @@ class LightInterfaceSlider extends StatelessWidget {
// value: light.brightness,
value: 100,
onChanged: (value) {
// DevicesCubit.get(context).setBrightness(light, value);
// DevicesCubit.getInstance().setBrightness(light, value);
},
min: 0,
max: 100,

View File

@ -1,12 +1,11 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/devices/model/device_model.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/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
import '../../../../shared_widgets/default_container.dart';
class LightInterfaceSwitch extends StatelessWidget {
const LightInterfaceSwitch({
super.key,
@ -28,7 +27,7 @@ class LightInterfaceSwitch extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodyLarge(
text: light.status ?? false
text: light.isOnline ?? false
? StringsManager.on
: StringsManager.off,
style:
@ -37,7 +36,7 @@ class LightInterfaceSwitch extends StatelessWidget {
Container(
width: 35,
decoration: ShapeDecoration(
color: light.status ?? false
color: light.isOnline ?? false
? ColorsManager.primaryColorWithOpacity
: Colors.grey,
shape: const CircleBorder(),
@ -51,7 +50,7 @@ class LightInterfaceSwitch extends StatelessWidget {
iconSize: MaterialStateProperty.all(25),
),
onPressed: () {
// DevicesCubit.get(context).toggleLight(light);
// DevicesCubit.getInstance().toggleLight(light);
},
icon: const Icon(
Icons.power_settings_new,

View File

@ -3,7 +3,7 @@ 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/resource_manager/strings_manager.dart';
import '../../../../shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
class LightInterfaceTimer extends StatelessWidget {
const LightInterfaceTimer({

View File

@ -2,9 +2,8 @@ import 'package:flutter/material.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/lights/light_brightness.dart';
import '../../../../shared_widgets/devices_default_switch.dart';
import '../../../../shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/features/shared_widgets/devices_default_switch.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
class LightsList extends StatelessWidget {
const LightsList({
@ -32,7 +31,7 @@ class LightsList extends StatelessWidget {
BodySmall(text: lights[index].name ?? ""),
IconButton(
onPressed: () {
DevicesCubit.get(context).selectDevice(lights[index]);
DevicesCubit.getInstance().selectDevice(lights[index]);
},
icon: const Icon(
Icons.arrow_forward_ios,

View File

@ -19,9 +19,9 @@ class LightsView extends StatelessWidget {
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
DeviceModel? selectedLight;
if (DevicesCubit.get(context).getSelectedDevice() is DeviceModel) {
if (DevicesCubit.getInstance().getSelectedDevice() is DeviceModel) {
selectedLight =
DevicesCubit.get(context).getSelectedDevice() as DeviceModel;
DevicesCubit.getInstance().getSelectedDevice() as DeviceModel;
}
List<DeviceModel> lights = [];
if (DevicesCubit.allCategories![1].devices != null) {

View File

@ -1,12 +1,11 @@
import 'package:flutter/material.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/lights/lights_list.dart';
import 'package:syncrow_app/features/devices/view/widgets/universal_switch.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import '../../../../shared_widgets/text_widgets/body_small.dart';
import '../../../bloc/devices_cubit.dart';
import '../universal_switch.dart';
class LightsViewList extends StatelessWidget {
const LightsViewList({
super.key,

View File

@ -1,71 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class LightSwitch extends StatelessWidget {
const LightSwitch({
super.key,
required this.control,
});
final DeviceControlModel control;
@override
Widget build(BuildContext context) {
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
return state is DeviceControlLoading
? const CircularProgressIndicator()
: InkWell(
overlayColor: MaterialStateProperty.all(Colors.transparent),
onTap: () {
DevicesCubit.get(context)
.deviceControl(control)
.then((value) {
print('Device control response: $value');
if (control.value ?? true) {
control.value = false;
} else {
control.value = true;
}
});
},
child: Stack(
alignment: !control.value!
? Alignment.topCenter
: Alignment.bottomCenter,
children: [
Container(
decoration: BoxDecoration(
borderRadius:
const BorderRadius.all(Radius.circular(100.0)),
color: !control.value!
? ColorsManager.primaryColorWithOpacity
: ColorsManager.switchOffColor,
),
width: 60,
height: 115,
),
Padding(
padding: const EdgeInsets.all(5.0),
child: SizedBox.square(
dimension: 60,
child: SvgPicture.asset(
!control.value!
? Assets.iconsLightSwitchOn
: Assets.iconsLightSwitchOff,
fit: BoxFit.fill,
),
),
),
],
),
);
},
);
}
}

View File

@ -1,87 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/function_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/category_view_app_bar.dart';
import 'package:syncrow_app/features/devices/view/widgets/lights_switches/light_switches_body.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';
class LightSwitchesView extends StatelessWidget {
const LightSwitchesView({super.key});
@override
Widget build(BuildContext context) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: SafeArea(
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: const CategoryViewAppBar(),
body: BlocBuilder<HomeCubit, HomeState>(
builder: (context, state) {
return Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.imagesBackground,
),
fit: BoxFit.cover,
opacity: 0.4,
),
),
child: Padding(
padding: EdgeInsets.only(
top: Constants.appBarHeight,
left: Constants.defaultPadding,
right: Constants.defaultPadding,
bottom: Constants.bottomNavBarHeight,
),
child: LightSwitchesBody(
device: DeviceModel(
id: 2,
name: 'Bedroom Light',
type: DeviceType.Lights,
status: true,
timer: 0,
image: '',
functions: [
FunctionModel(
code: 'switch_1',
desc: 'switch 1',
name: 'switch 1',
type: 'Boolean',
values: '{}'),
FunctionModel(
code: 'switch_2',
desc: 'switch 2',
name: 'switch 2',
type: 'Boolean',
values: '{}'),
FunctionModel(
code: 'switch_3',
desc: 'switch 3',
name: 'switch 3',
type: 'Boolean',
values: '{}'),
]),
),
),
);
},
)),
),
);
}
}

View File

@ -1,260 +0,0 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/lights_switches/light_switch.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class LightSwitchesBody extends StatelessWidget {
const LightSwitchesBody({
super.key,
required this.device,
});
final DeviceModel device;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Expanded(child: SizedBox.shrink()),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
children: [
LightSwitch(
control: DeviceControlModel(
deviceId: 'bfe10693d4fd263206ocq9',
code: 'switch_1',
value: true,
),
),
const SizedBox(height: 20),
const SizedBox(
width: 70,
child: BodySmall(
text: "Bedside Light",
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
Column(
children: [
LightSwitch(
control: DeviceControlModel(
deviceId: 'bfe10693d4fd263206ocq9',
code: 'switch_2',
value: true,
),
),
const SizedBox(height: 20),
const SizedBox(
width: 70,
child: BodySmall(
text: "Ceiling Light",
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
Column(
children: [
LightSwitch(
control: DeviceControlModel(
deviceId: 'bfe10693d4fd263206ocq9',
code: 'switch_3',
value: true,
),
),
const SizedBox(height: 20),
const SizedBox(
width: 70,
child: BodySmall(
text: "Spotlight",
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
],
),
Expanded(
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
child: InkWell(
onTap: () {},
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(100),
),
),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(100),
),
child: Center(
child: BodySmall(
text: "On",
style: context.bodyMedium.copyWith(
color:
ColorsManager.primaryColorWithOpacity,
fontWeight: FontWeight.bold),
),
),
),
],
),
),
),
const SizedBox(height: 10),
BodySmall(
text: "All On",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
),
),
],
),
const SizedBox(
width: 20,
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
child: InkWell(
onTap: () {},
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(100),
),
),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(100),
),
child: Center(
child: Icon(
Icons.access_time,
color: ColorsManager.primaryColorWithOpacity,
size: 25,
),
),
),
],
),
),
),
const SizedBox(height: 10),
BodySmall(
text: "Timer",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
),
),
],
),
const SizedBox(
width: 20,
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
child: InkWell(
onTap: () {},
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(100),
),
),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(100),
),
child: Center(
child: BodySmall(
text: "Off",
style: context.bodyMedium.copyWith(
color:
ColorsManager.primaryColorWithOpacity,
fontWeight: FontWeight.bold),
),
),
),
],
),
),
),
const SizedBox(height: 10),
BodySmall(
text: "All Off",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
),
),
],
),
],
),
),
),
],
);
}
}

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.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/model/room_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/room_page_switch.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
@ -13,10 +12,6 @@ class RoomPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
List<DeviceModel> devices = [];
for (var category in room.categories ?? []) {
devices.addAll(category.devices);
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: Constants.defaultPadding),
child: SingleChildScrollView(
@ -32,9 +27,9 @@ class RoomPage extends StatelessWidget {
padding: const EdgeInsets.only(top: 10),
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: devices.length,
itemBuilder: (_, index) {
return RoomPageSwitch(device: devices[index]);
itemCount: room.devices!.length,
itemBuilder: (context, index) {
return RoomPageSwitch(device: room.devices![index]);
},
);
},

View File

@ -1,7 +1,11 @@
import 'package:flutter/material.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/ac_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/lights/light_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';
@ -21,25 +25,57 @@ class RoomPageSwitch extends StatelessWidget {
Widget build(BuildContext context) {
return InkWell(
onTap: () {
//Navigate to the chosen category view without animation
// Navigator.push(
// context,
// CustomPageRoute(
// builder: (context) {
// return DevicesCubit.get(context)
// .chosenCategoryView!;
// },
// ),
// );
if (device.type == DeviceType.AC) {
Navigator.push(
context,
CustomPageRoute(
builder: (context) => AcInterface(deviceModel: device),
),
);
switch (device.productType) {
case DeviceType.AC:
{
print("AC");
Navigator.push(
context,
CustomPageRoute(
builder: (context) => BlocProvider(
create: (context) => DevicesCubit.getInstance(),
child: AcInterface(deviceModel: device),
),
),
);
break;
}
case DeviceType.WallSensor:
break;
case DeviceType.CeilingSensor:
break;
case DeviceType.Curtain:
break;
case DeviceType.Blind:
break;
case DeviceType.DoorLock:
break;
case DeviceType.Gateway:
break;
case DeviceType.LightBulb:
Navigator.push(
context,
CustomPageRoute(
builder: (context) => BlocProvider(
create: (context) => DevicesCubit.getInstance(),
child: LightInterface(light: device),
),
),
);
case DeviceType.ThreeGang:
Navigator.push(
context,
CustomPageRoute(
builder: (context) => BlocProvider(
create: (context) => DevicesCubit.getInstance(),
child: ThreeGangInterface(
gangSwitch: device,
),
),
),
);
break;
default:
}
},
child: DefaultContainer(
@ -54,7 +90,7 @@ class RoomPageSwitch extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(
device.icon,
device.icon!,
fit: BoxFit.contain,
),
CustomSwitch(

View File

@ -18,51 +18,55 @@ class RoomsSlider extends StatelessWidget {
return SizedBox(
height: 40,
child: PageView(
controller: HomeCubit.get(context).roomsPageController,
controller: HomeCubit.getInstance().roomsPageController,
onPageChanged: (index) {
HomeCubit.get(context).roomSliderPageChanged(index);
HomeCubit.getInstance().roomSliderPageChanged(index);
},
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: InkWell(
onTap: () {
HomeCubit.get(context).unselectRoom();
HomeCubit.getInstance().unselectRoom();
},
child: TitleMedium(
text: StringsManager.wizard,
style: context.titleMedium.copyWith(
fontSize: 25,
color: HomeCubit.get(context).selectedRoom == null
color: HomeCubit.getInstance().selectedRoom == null
? ColorsManager.textPrimaryColor
: ColorsManager.textPrimaryColor.withOpacity(.2),
),
),
),
),
if (HomeCubit.selectedSpace != null)
if (HomeCubit.selectedSpace!.rooms != null)
...HomeCubit.selectedSpace!.rooms!.map(
(room) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: InkWell(
onTap: () {
HomeCubit.get(context).roomSliderPageChanged(
HomeCubit.selectedSpace!.rooms!.indexOf(room));
},
child: TitleMedium(
text: room.name!,
style: context.titleMedium.copyWith(
fontSize: 25,
color: HomeCubit.get(context).selectedRoom == room
? ColorsManager.textPrimaryColor
: ColorsManager.textPrimaryColor
.withOpacity(.2),
if (HomeCubit.getInstance().selectedSpace != null)
if (HomeCubit.getInstance().selectedSpace!.rooms != null)
...HomeCubit.getInstance().selectedSpace!.rooms!.map(
(room) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: InkWell(
onTap: () {
HomeCubit.getInstance().roomSliderPageChanged(
HomeCubit.getInstance()
.selectedSpace!
.rooms!
.indexOf(room));
},
child: TitleMedium(
text: room.name!,
style: context.titleMedium.copyWith(
fontSize: 25,
color:
HomeCubit.getInstance().selectedRoom == room
? ColorsManager.textPrimaryColor
: ColorsManager.textPrimaryColor
.withOpacity(.2),
),
),
),
),
),
),
)
)
],
),
);

View File

@ -0,0 +1,81 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class GangSwitch extends StatelessWidget {
const GangSwitch({
super.key,
required this.threeGangSwitch,
required this.control,
});
final DeviceModel threeGangSwitch;
final DeviceControlModel control;
@override
Widget build(BuildContext context) {
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
return InkWell(
overlayColor: MaterialStateProperty.all(Colors.transparent),
onTap: () {
var tempControl = DeviceControlModel(
deviceId: control.deviceId,
code: control.code!,
value: !control.value!);
DevicesCubit.getInstance().deviceControl(
tempControl,
control.deviceId!,
);
},
child: Stack(
alignment:
!control.value! ? Alignment.topCenter : Alignment.bottomCenter,
children: [
Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(100.0)),
color: threeGangSwitch.status
.firstWhere((element) => element.code == control.code)
.value!
? ColorsManager.primaryColorWithOpacity
: ColorsManager.switchOffColor,
),
width: 60,
height: 115,
),
Padding(
padding: const EdgeInsets.all(5.0),
child: SizedBox.square(
dimension: 60,
child: state is GetDeviceStatusLoading &&
state.code == control.code ||
state is DeviceControlSuccess &&
state.code == control.code ||
state is DeviceControlLoading &&
state.code == control.code
? const SizedBox(
width: 10,
height: 10,
child: Center(child: CircularProgressIndicator()))
: SvgPicture.asset(
control.value!
? Assets.iconsLightSwitchOn
: Assets.iconsLightSwitchOff,
fit: BoxFit.fill,
),
),
),
],
),
);
},
);
}
}

View File

@ -0,0 +1,65 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface_body.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.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 ThreeGangInterface extends StatelessWidget {
const ThreeGangInterface({super.key, required this.gangSwitch});
final DeviceModel gangSwitch;
@override
Widget build(BuildContext context) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: SafeArea(
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: BodyLarge(
text: gangSwitch.name ?? "",
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
body: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.imagesBackground,
),
fit: BoxFit.cover,
opacity: 0.4,
),
),
child: Padding(
padding: EdgeInsets.only(
top: Constants.appBarHeight,
left: Constants.defaultPadding,
right: Constants.defaultPadding,
bottom: Constants.bottomNavBarHeight,
),
child: ThreeGangInterfaceBody(
device: gangSwitch,
),
),
),
),
),
);
}
}

View File

@ -0,0 +1,328 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_gang/gang_switch.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class ThreeGangInterfaceBody extends StatelessWidget {
const ThreeGangInterfaceBody({
super.key,
required this.device,
});
final DeviceModel device;
@override
Widget build(BuildContext context) {
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Expanded(child: SizedBox.shrink()),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
children: [
GangSwitch(
threeGangSwitch: device,
control: DeviceControlModel(
deviceId: device.id,
// code: 'switch_1',
code: device.status[0].code,
// value: true,
value: device.status[0].value,
),
),
const SizedBox(height: 20),
const SizedBox(
width: 70,
child: BodySmall(
text: "Bedside Light",
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
Column(
children: [
GangSwitch(
threeGangSwitch: device,
control: DeviceControlModel(
// deviceId: 'bfe10693d4fd263206ocq9',
// code: 'switch_2',
// value: true,
deviceId: device.id,
code: device.status[1].code,
value: device.status[1].value,
),
),
const SizedBox(height: 20),
const SizedBox(
width: 70,
child: BodySmall(
text: "Ceiling Light",
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
Column(
children: [
GangSwitch(
threeGangSwitch: device,
control: DeviceControlModel(
// deviceId: 'bfe10693d4fd263206ocq9',
// code: 'switch_3',
// value: true,
deviceId: device.id,
code: device.status[2].code,
value: device.status[2].value,
),
),
const SizedBox(height: 20),
const SizedBox(
width: 70,
child: BodySmall(
text: "Spotlight",
fontColor: ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
],
),
Expanded(
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
child: InkWell(
onTap: () {
DevicesCubit.getInstance().deviceControl(
DeviceControlModel(
deviceId: device.id,
code: 'switch_1',
value: true,
),
device.id!,
);
DevicesCubit.getInstance().deviceControl(
DeviceControlModel(
deviceId: device.id,
code: 'switch_2',
value: true,
),
device.id!,
);
DevicesCubit.getInstance().deviceControl(
DeviceControlModel(
deviceId: device.id,
code: 'switch_3',
value: true,
),
device.id!,
);
},
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(100),
),
),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(100),
),
child: Center(
child: BodySmall(
text: "On",
style: context.bodyMedium.copyWith(
color: ColorsManager
.primaryColorWithOpacity,
fontWeight: FontWeight.bold),
),
),
),
],
),
),
),
const SizedBox(height: 10),
BodySmall(
text: "All On",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
),
),
],
),
const SizedBox(
width: 20,
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
child: InkWell(
onTap: () {},
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(100),
),
),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(100),
),
child: Center(
child: Icon(
Icons.access_time,
color:
ColorsManager.primaryColorWithOpacity,
size: 25,
),
),
),
],
),
),
),
const SizedBox(height: 10),
BodySmall(
text: "Timer",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
),
),
],
),
const SizedBox(
width: 20,
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
),
child: InkWell(
onTap: () {
DevicesCubit.getInstance().deviceControl(
DeviceControlModel(
deviceId: device.id,
code: 'switch_1',
value: false,
),
device.id!,
);
DevicesCubit.getInstance().deviceControl(
DeviceControlModel(
deviceId: device.id,
code: 'switch_2',
value: false,
),
device.id!,
);
DevicesCubit.getInstance().deviceControl(
DeviceControlModel(
deviceId: device.id,
code: 'switch_3',
value: false,
),
device.id!,
);
},
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(100),
),
),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(100),
),
child: Center(
child: BodySmall(
text: "Off",
style: context.bodyMedium.copyWith(
color: ColorsManager
.primaryColorWithOpacity,
fontWeight: FontWeight.bold),
),
),
),
],
),
),
),
const SizedBox(height: 10),
BodySmall(
text: "All Off",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
),
),
],
),
],
),
),
),
],
);
},
);
}
}

View File

@ -2,11 +2,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
import '../../../../utils/resource_manager/color_manager.dart';
import '../../../shared_widgets/text_widgets/body_medium.dart';
class UniversalSwitch extends StatelessWidget {
const UniversalSwitch({
super.key,
@ -25,7 +24,7 @@ class UniversalSwitch extends StatelessWidget {
Expanded(
child: InkWell(
onTap: () {
DevicesCubit.get(context).turnAllDevicesOn(category);
DevicesCubit.getInstance().turnAllDevicesOn(category);
},
child: Container(
height: 60,
@ -57,7 +56,7 @@ class UniversalSwitch extends StatelessWidget {
Expanded(
child: InkWell(
onTap: () {
DevicesCubit.get(context).turnAllDevicesOff(category);
DevicesCubit.getInstance().turnAllDevicesOff(category);
},
child: Container(
height: 60,

View File

@ -1,14 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/shared_widgets/custom_switch.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.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 '../../bloc/devices_cubit.dart';
class WizartSwitches extends StatelessWidget {
const WizartSwitches({
super.key,
@ -35,12 +33,12 @@ class WizartSwitches extends StatelessWidget {
itemBuilder: (_, index) {
return InkWell(
onTap: () {
DevicesCubit.get(context).selectCategory(index);
// DevicesCubit.getInstance().selectCategory(index);
//Navigate to the chosen category view without animation
Navigator.push(context,
CustomPageRoute(builder: (context) {
return DevicesCubit.get(context)
return DevicesCubit.getInstance()
.chosenCategoryView!;
}));
},
@ -61,10 +59,7 @@ class WizartSwitches extends StatelessWidget {
DevicesCubit.allCategories![index].icon!,
fit: BoxFit.contain,
),
CustomSwitch(
category:
DevicesCubit.allCategories![index],
),
// CustomSwitch(
],
),
Expanded(

View File

@ -1,7 +1,6 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import '../model/list_item_model.dart';
import '../model/menu_list_model.dart';
import 'package:syncrow_app/features/menu/model/list_item_model.dart';
import 'package:syncrow_app/features/menu/model/menu_list_model.dart';
part 'menu_state.dart';

View File

@ -1,10 +1,9 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/syncrow_logo.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import '../../../shared_widgets/syncrow_logo.dart';
class ProfileTab extends StatelessWidget {
const ProfileTab({
super.key,

View File

@ -2,80 +2,87 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:collection/collection.dart';
class CustomSwitch extends StatelessWidget {
const CustomSwitch({super.key, this.category, this.device})
: assert(category != null || device != null);
final DevicesCategoryModel? category;
final DeviceModel? device;
const CustomSwitch({super.key, required this.device});
final DeviceModel device;
@override
Widget build(BuildContext context) {
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
bool? status;
if (device != null) {
status = device!.status;
} else if (category != null) {
status = category!.devicesStatus;
if (device.status.isNotEmpty) {
status = device.status
.firstWhereOrNull((status) => status.code == "switch")
?.value;
}
return GestureDetector(
onTap: () {
if (device != null) {
DevicesCubit.get(context).turnOnOffDevice(device!);
} else if (category != null) {
DevicesCubit.get(context).changeCategorySwitchValue(category!);
}
},
child: Container(
width: 45.0,
height: 28.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24.0),
color: status != null
? status
? ColorsManager.primaryColor
: const Color(0xFFD9D9D9)
: const Color(0xFFD9D9D9),
),
child: Center(
child: Container(
width: 40.0,
height: 23.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24.0),
color: Colors.white,
),
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Container(
alignment: status != null
return status == null
? const SizedBox()
: GestureDetector(
onTap: () {
DevicesCubit.getInstance().deviceControl(
DeviceControlModel(
deviceId: device.id,
code: device.status
.firstWhere((status) => status.code == "switch")
.code,
value: !device.status
.firstWhere((status) => status.code == "switch")
.value!,
),
device.id!,
);
},
child: Container(
width: 45.0,
height: 28.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24.0),
color: status != null
? status
? Alignment.centerRight
: Alignment.centerLeft
: Alignment.centerLeft,
? ColorsManager.primaryColor
: const Color(0xFFD9D9D9)
: const Color(0xFFD9D9D9),
),
child: Center(
child: Container(
width: 20.0,
height: 20.0,
width: 40.0,
height: 23.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: status != null
? status
? ColorsManager.primaryColor
: Colors.grey
: Colors.grey,
borderRadius: BorderRadius.circular(24.0),
color: Colors.white,
),
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Container(
alignment: status != null
? status
? Alignment.centerRight
: Alignment.centerLeft
: Alignment.centerLeft,
child: Container(
width: 20.0,
height: 20.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: status != null
? status
? ColorsManager.primaryColor
: Colors.grey
: Colors.grey,
),
),
),
),
),
),
),
),
),
),
);
);
},
);
}

View File

@ -1,11 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.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/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import '../devices/bloc/devices_cubit.dart';
class DevicesDefaultSwitch extends StatelessWidget {
const DevicesDefaultSwitch({
super.key,
@ -23,12 +22,12 @@ class DevicesDefaultSwitch extends StatelessWidget {
Expanded(
child: InkWell(
onTap: () {
DevicesCubit.get(context).turnOnOffDevice(model);
DevicesCubit.getInstance().turnOnOffDevice(model);
},
child: Container(
height: 60,
decoration: BoxDecoration(
color: model.status ?? false
color: model.isOnline ?? false
? ColorsManager.primaryColor
: Colors.white,
borderRadius: const BorderRadius.only(
@ -39,7 +38,7 @@ class DevicesDefaultSwitch extends StatelessWidget {
child: Center(
child: BodyMedium(
text: "ON",
fontColor: model.status ?? false ? Colors.white : null,
fontColor: model.isOnline ?? false ? Colors.white : null,
fontWeight: FontWeight.bold,
),
),
@ -49,12 +48,12 @@ class DevicesDefaultSwitch extends StatelessWidget {
Expanded(
child: InkWell(
onTap: () {
DevicesCubit.get(context).turnOnOffDevice(model);
DevicesCubit.getInstance().turnOnOffDevice(model);
},
child: Container(
height: 60,
decoration: BoxDecoration(
color: model.status ?? false
color: model.isOnline ?? false
? Colors.white
: ColorsManager.primaryColor,
borderRadius: const BorderRadius.only(
@ -65,7 +64,7 @@ class DevicesDefaultSwitch extends StatelessWidget {
child: Center(
child: BodyMedium(
text: "OFF",
fontColor: model.status ?? false ? null : Colors.white,
fontColor: model.isOnline ?? false ? null : Colors.white,
fontWeight: FontWeight.bold,
),
),

View File

@ -18,12 +18,8 @@ class MyApp extends StatelessWidget {
MediaQuery.sizeOf(context).height * Constants.appBarHeightPercentage;
Constants.bottomNavBarHeight = MediaQuery.sizeOf(context).height *
Constants.bottomNavBarHeightPercentage;
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => AuthCubit(),
),
],
return BlocProvider(
create: (context) => AuthCubit(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
color: ColorsManager.primaryColor,

View File

@ -7,7 +7,6 @@ import 'package:syncrow_app/features/auth/view/widgets/privacy_policy/privacy_po
import 'package:syncrow_app/features/auth/view/widgets/sign_up/sign_up_view.dart';
import 'package:syncrow_app/features/auth/view/widgets/user_agreement/user_agreement_view.dart';
import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart';
import 'package:syncrow_app/features/devices/view/devices_view.dart';
import 'package:syncrow_app/features/layout/view/layout_view.dart';
import 'package:syncrow_app/features/menu/view/menu_view.dart';
import 'package:syncrow_app/features/profile/view/profile_view.dart';
@ -23,9 +22,9 @@ class Router {
return MaterialPageRoute(
builder: (_) => const SplashView(), settings: settings);
case Routes.devicesRoute:
return MaterialPageRoute(
builder: (_) => const DevicesView(), settings: settings);
// case Routes.devicesRoute:
// return MaterialPageRoute(
// builder: (_) => const DevicesView(), settings: settings);
case Routes.profileRoute:
return MaterialPageRoute(

View File

@ -16,6 +16,9 @@ abstract class ApiEndpoints {
// Devices
static const String control = '$baseUrl/device/control';
static const String devicesByRoom = '$baseUrl/device/room';
// static const String deviceStatus = '$baseUrl/device/status/';
static const String deviceStatus = '$baseUrl/device/';
//groups
static const String groups = '$baseUrl/group';

View File

@ -8,6 +8,8 @@ class DevicesAPI {
static Future<Map<String, dynamic>> controlDevice(
DeviceControlModel controlModel) async {
// print(
// 'contoling [${controlModel.deviceId}] with code [${controlModel.code}] and value [${controlModel.value}');
final response = await _httpService.post(
path: ApiEndpoints.control,
body: controlModel.toJson(),
@ -34,4 +36,15 @@ class DevicesAPI {
);
return response;
}
static Future<Map<String, dynamic>> getDeviceStatus(String deviceId) async {
final response = await _httpService.get(
path: '${ApiEndpoints.deviceStatus}/$deviceId/functions/status',
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
}
}

View File

@ -37,9 +37,6 @@ class HTTPService {
path,
queryParameters: queryParameters,
);
// debugPrint("status code is ${response.statusCode}");
// debugPrint("response data is ${response.data}");
return expectedResponseModel(response.data);
} catch (error) {
debugPrint("******* Error");

View File

@ -28,8 +28,14 @@ class ServerFailure extends Failure {
return ServerFailure("Bad certificate!");
case DioExceptionType.badResponse:
return ServerFailure.fromResponse(dioError.response!.statusCode!,
dioError.response!.data!["message"]);
{
// var document = parser.parse(dioError.response!.data.toString());
// var message = document.body!.text;
return ServerFailure.fromResponse(dioError.response!.statusCode!,
dioError.response!.data['message'].toString()
// message
);
}
case DioExceptionType.cancel:
return ServerFailure("The request to ApiServer was canceled");
@ -45,8 +51,15 @@ class ServerFailure extends Failure {
}
factory ServerFailure.fromResponse(int statusCode, dynamic response) {
if (statusCode == 400 || statusCode == 401 || statusCode == 403) {
if (statusCode == 401 || statusCode == 403) {
return ServerFailure(response);
} else if (statusCode == 400) {
//response is list of errors
List<String> errors = [];
response.forEach((element) {
errors.add(element);
});
return ServerFailure(errors.join('\n'));
} else if (statusCode == 404) {
return ServerFailure("Your request not found, Please try later!");
} else if (statusCode == 500) {

View File

@ -1,6 +1,7 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/auth/model/user_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/room_model.dart';
import 'package:syncrow_app/services/api/api_links_endpoints.dart';
import 'package:syncrow_app/services/api/http_service.dart';
@ -23,7 +24,7 @@ class SpacesAPI {
}
//get rooms by space id
static Future<List<RoomModel>> getRooms(int spaceId) async {
static Future<List<RoomModel>> getRoomsBySpaceId(int spaceId) async {
final response = await _httpService.get(
path: ApiEndpoints.rooms,
queryParameters: {"homeId": spaceId},
@ -38,4 +39,20 @@ class SpacesAPI {
);
return response;
}
static Future<List<DeviceModel>> getDevicesByRoomId(int roomId) async {
final response = await _httpService.get(
path: ApiEndpoints.devicesByRoom,
queryParameters: {"roomId": roomId, "pageSize": 10},
showServerMessage: false,
expectedResponseModel: (json) {
List<DeviceModel> devices = [];
for (var device in json['devices']) {
devices.add(DeviceModel.fromJson(device));
}
return devices;
},
);
return response;
}
}

View File

@ -23,7 +23,7 @@ class MyBlocObserver extends BlocObserver {
@override
void onClose(BlocBase bloc) {
super.onClose(bloc);
print('onClose -- ${bloc.runtimeType}');
super.onClose(bloc);
}
}

View File

@ -1,4 +1,7 @@
//ignore_for_file: constant_identifier_names
import 'package:syncrow_app/features/devices/model/function_model.dart';
import 'package:syncrow_app/generated/assets.dart';
abstract class Constants {
static const String languageCode = "en";
@ -16,12 +19,182 @@ abstract class Constants {
enum DeviceType {
AC,
Lights,
LightBulb,
DoorLock,
Curtain,
Blind,
ThreeGang,
Gateway,
Sensors,
Gang,
CeilingSensor,
WallSensor,
Other,
}
// Map<String, DeviceType> devicesTypesMap = {
// "AC": DeviceType.AC,
// "LB": DeviceType.LightBulb,
// "DL": DeviceType.DoorLock,
// "WC": DeviceType.Curtain,
// "WB": DeviceType.Blind,
// "3G": DeviceType.ThreeGang,
// "GW": DeviceType.Gateway,
// "CPS": DeviceType.CeilingSensor,
// "WPS": DeviceType.WallSensor,
// "Other": DeviceType.Other,
// };
//AC wzdcrqh0
// GW wp8ticoo2bhumwgb
// CPS d3ci7gcn
// DL awu7anehyu5q1iu8
// WPS awarhusb
// 3G 1a6vgvyi
Map<String, DeviceType> devicesTypesMap = {
"wzdcrqh0": DeviceType.AC,
"wp8ticoo2bhumwgb": DeviceType.Gateway,
"d3ci7gcn": DeviceType.CeilingSensor,
"awu7anehyu5q1iu8": DeviceType.DoorLock,
"awarhusb": DeviceType.WallSensor,
"1a6vgvyi": DeviceType.ThreeGang,
};
Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
DeviceType.AC: [
FunctionModel(code: 'switch', type: 'Boolean', values: '{}'),
FunctionModel(
code: 'mode', type: 'Enum', values: '{"range":["cold","hot","wind"]}'),
FunctionModel(
code: 'temp_set',
type: 'Integer',
values: '{"unit":"℃","min":200,"max":300,"scale":1,"step":5}'),
FunctionModel(
code: 'level',
type: 'Enum',
values: '{"range":["low","middle","high","auto"]}'),
FunctionModel(code: 'child_lock', type: 'Boolean', values: '{}'),
],
DeviceType.Gateway: [
FunctionModel(code: 'switch_alarm_sound', type: 'Boolean', values: '{}'),
FunctionModel(
code: 'master_state',
type: 'Enum',
values: '{"range":["normal","alarm"]}'),
FunctionModel(code: 'factory_reset', type: 'Boolean', values: '{}'),
FunctionModel(
code: 'alarm_active', type: 'String', values: '{"maxlen":255}'),
],
DeviceType.CeilingSensor: [
FunctionModel(
code: 'sensitivity',
type: 'Integer',
values: '{"unit":"","min":1,"max":10,"scale":0,"step":1}'),
],
DeviceType.DoorLock: [
FunctionModel(code: 'remote_no_pd_setkey', type: 'Raw', values: '{}'),
FunctionModel(code: 'remote_no_dp_key', type: 'Raw', values: '{}'),
FunctionModel(code: 'normal_open_switch', type: 'Boolean', values: '{}'),
],
DeviceType.WallSensor: [
FunctionModel(
code: 'far_detection',
type: 'Integer',
values: '{"unit":"cm","min":75,"max":600,"scale":0,"step":75}'),
FunctionModel(
code: 'presence_time',
type: 'Integer',
values: '{"unit":"Min","min":0,"max":65535,"scale":0,"step":1}'),
FunctionModel(
code: 'motion_sensitivity_value',
type: 'Integer',
values: '{"unit":"","min":1,"max":5,"scale":0,"step":1}'),
FunctionModel(
code: 'motionless_sensitivity',
type: 'Integer',
values: '{"unit":"","min":1,"max":5,"scale":0,"step":1}'),
FunctionModel(code: 'indicator', type: 'Boolean', values: '{}'),
],
DeviceType.ThreeGang: [
FunctionModel(code: 'switch_1', type: 'Boolean', values: '{}'),
FunctionModel(code: 'switch_2', type: 'Boolean', values: '{}'),
FunctionModel(code: 'switch_3', type: 'Boolean', values: '{}'),
FunctionModel(
code: 'countdown_1',
type: 'Integer',
values: '{"unit":"s","min":0,"max":43200,"scale":0,"step":1}'),
FunctionModel(
code: 'countdown_2',
type: 'Integer',
values: '{"unit":"s","min":0,"max":43200,"scale":0,"step":1}'),
FunctionModel(
code: 'countdown_3',
type: 'Integer',
values: '{"unit":"s","min":0,"max":43200,"scale":0,"step":1}'),
],
};
enum TempModes { hot, cold, wind }
enum FanSpeeds { auto, low, middle, high }
final Map<FanSpeeds, String> fanSpeedsIconMap = {
FanSpeeds.auto: Assets.iconsFan0,
FanSpeeds.low: Assets.iconsFan1,
FanSpeeds.middle: Assets.iconsFan2,
FanSpeeds.high: Assets.iconsFan3,
};
final Map<TempModes, String> tempModesIconMap = {
TempModes.hot: Assets.iconsSunnyMode,
TempModes.cold: Assets.iconsColdMode,
TempModes.wind: Assets.iconsWindyMode,
};
final Map<String, FanSpeeds> fanSpeedsMap = {
'auto': FanSpeeds.auto,
'low': FanSpeeds.low,
'middle': FanSpeeds.middle,
'high': FanSpeeds.high,
};
final Map<String, TempModes> tempModesMap = {
'hot': TempModes.hot,
'cold': TempModes.cold,
'wind': TempModes.wind,
};
final Map<FanSpeeds, String> reversedFanSpeedsMap =
fanSpeedsMap.map((key, value) => MapEntry(value, key));
final Map<TempModes, String> reversedTempModesMap =
tempModesMap.map((key, value) => MapEntry(value, key));
String getNextFanSpeedKey(FanSpeeds currentFanSpeed) {
const List<FanSpeeds> speeds = FanSpeeds.values;
final int currentIndex = speeds.indexOf(currentFanSpeed);
// Return null if currentFanSpeed is the last value
if (currentIndex == speeds.length - 1) {
return reversedFanSpeedsMap[FanSpeeds.auto]!;
}
final FanSpeeds nextSpeed = speeds[currentIndex + 1];
return reversedFanSpeedsMap[nextSpeed]!;
}
K? getNextItem<K, V>(Map<K, V> map, V value) {
// Iterate over the map entries
for (var entry in map.entries) {
// If the current value matches the provided value
if (entry.value == value) {
// Get the index of the current entry
final index = map.keys.toList().indexOf(entry.key);
// If the index is not the last item, return the next item
if (index < map.length - 1) {
return map.keys.elementAt(index + 1);
}
// If it's the last item, return null
return map.keys.elementAt(0);
}
}
// If the value is not found, return null
return null;
}

View File

@ -97,6 +97,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.3"
csslib:
dependency: transitive
description:
name: csslib
sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
cupertino_icons:
dependency: "direct main"
description:
@ -357,6 +365,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.6.7"
html:
dependency: "direct main"
description:
name: html
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
url: "https://pub.dev"
source: hosted
version: "0.15.4"
http:
dependency: transitive
description:

View File

@ -36,6 +36,7 @@ dependencies:
firebase_analytics: ^10.8.7
firebase_crashlytics: ^3.4.16
smooth_page_indicator: ^1.1.0
html: ^0.15.4
dev_dependencies:
flutter_test: