mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-07-15 09:45:22 +00:00

Added try-catch blocks for error handling in API's files to rethrow the errors to the cubit so cubits can update the UI based on them. Refactored error handling in HTTPInterceptor and HTTPService classes.
298 lines
7.5 KiB
Dart
298 lines
7.5 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
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';
|
|
import 'package:syncrow_app/features/scene/view/scene_view.dart';
|
|
import 'package:syncrow_app/generated/assets.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/color_manager.dart';
|
|
|
|
part 'home_state.dart';
|
|
|
|
class HomeCubit extends Cubit<HomeState> {
|
|
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);
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<void> close() {
|
|
_instance = null;
|
|
selectedSpace = null;
|
|
selectedRoom = null;
|
|
return super.close();
|
|
}
|
|
|
|
static HomeCubit get(context) => BlocProvider.of(context);
|
|
|
|
List<SpaceModel>? spaces;
|
|
|
|
SpaceModel? selectedSpace;
|
|
|
|
RoomModel? selectedRoom;
|
|
|
|
PageController devicesPageController = PageController();
|
|
|
|
PageController roomsPageController = PageController();
|
|
|
|
var duration = const Duration(milliseconds: 300);
|
|
|
|
// selectSpace(SpaceModel space) async {
|
|
// selectedSpace = space;
|
|
// emit(SpaceSelected(space));
|
|
// }
|
|
|
|
changeSelectedSpace(SpaceModel space) {
|
|
selectedSpace = space;
|
|
emitSafe(SpaceSelected(space));
|
|
}
|
|
|
|
roomSliderPageChanged(int index) {
|
|
devicesPageController.animateToPage(
|
|
index,
|
|
duration: duration,
|
|
curve: Curves.linear,
|
|
);
|
|
|
|
if (index == 0) {
|
|
unselectRoom();
|
|
} else {
|
|
selectedRoom = selectedSpace!.rooms![index - 1];
|
|
emitSafe(RoomSelected(selectedRoom!));
|
|
}
|
|
}
|
|
|
|
devicesPageChanged(int index) {
|
|
roomsPageController.animateToPage(
|
|
index,
|
|
duration: const Duration(milliseconds: 300),
|
|
curve: Curves.linear,
|
|
);
|
|
|
|
if (index <= 0) {
|
|
unselectRoom();
|
|
} else {
|
|
selectedRoom = selectedSpace!.rooms![index - 1];
|
|
emitSafe(RoomSelected(selectedRoom!));
|
|
}
|
|
}
|
|
|
|
unselectRoom() {
|
|
// selectedRoom = null;
|
|
devicesPageController.animateToPage(
|
|
0,
|
|
duration: duration,
|
|
curve: Curves.linear,
|
|
);
|
|
|
|
roomsPageController.animateToPage(
|
|
0,
|
|
duration: duration,
|
|
curve: Curves.linear,
|
|
);
|
|
|
|
emitSafe(RoomUnSelected());
|
|
}
|
|
|
|
//////////////////////////////////////// API ////////////////////////////////////////
|
|
fetchSpaces() async {
|
|
emitSafe(GetSpacesLoading());
|
|
try {
|
|
spaces = await SpacesAPI.getSpaces();
|
|
} catch (failure) {
|
|
emitSafe(GetSpacesError(failure.toString()));
|
|
return;
|
|
}
|
|
|
|
if (spaces != null && spaces!.isNotEmpty) {
|
|
selectedSpace = spaces!.first;
|
|
emitSafe(GetSpacesSuccess(spaces!));
|
|
fetchRooms(selectedSpace!);
|
|
} else {
|
|
emitSafe(GetSpacesError("No spaces found"));
|
|
}
|
|
}
|
|
|
|
fetchRooms(SpaceModel space) async {
|
|
emitSafe(GetSpaceRoomsLoading());
|
|
try {
|
|
space.rooms = await SpacesAPI.getRoomsBySpaceId(space.id!);
|
|
} catch (failure) {
|
|
emitSafe(GetSpaceRoomsError(failure.toString()));
|
|
return;
|
|
}
|
|
if (space.rooms != null) {
|
|
emitSafe(GetSpaceRoomsSuccess(space.rooms!));
|
|
} else {
|
|
emitSafe(GetSpaceRoomsError("No rooms found"));
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////// Nav ///////////////////////////////////////
|
|
|
|
static int pageIndex = 0;
|
|
|
|
static Map<String, List<Widget>> appBarActions = {
|
|
'Dashboard': [
|
|
IconButton(
|
|
icon: const Icon(
|
|
Icons.add,
|
|
size: 25,
|
|
),
|
|
style: ButtonStyle(
|
|
foregroundColor:
|
|
MaterialStateProperty.all(ColorsManager.textPrimaryColor),
|
|
),
|
|
onPressed: () {},
|
|
),
|
|
],
|
|
'Devices': [
|
|
IconButton(
|
|
icon: const Icon(
|
|
Icons.add,
|
|
size: 25,
|
|
),
|
|
style: ButtonStyle(
|
|
foregroundColor:
|
|
MaterialStateProperty.all(ColorsManager.textPrimaryColor),
|
|
),
|
|
onPressed: () {},
|
|
),
|
|
IconButton(
|
|
icon: const Icon(
|
|
Icons.more_vert,
|
|
size: 25,
|
|
),
|
|
style: ButtonStyle(
|
|
foregroundColor:
|
|
MaterialStateProperty.all(ColorsManager.textPrimaryColor),
|
|
),
|
|
onPressed: () {},
|
|
),
|
|
],
|
|
'Routine': [
|
|
// IconButton(
|
|
// icon: Image.asset(
|
|
// Assets.iconsFilter,
|
|
// height: 20,
|
|
// width: 20,
|
|
// ),
|
|
// onPressed: () {},
|
|
// ),
|
|
IconButton(
|
|
icon: const Icon(
|
|
Icons.add,
|
|
size: 25,
|
|
),
|
|
style: ButtonStyle(
|
|
foregroundColor:
|
|
MaterialStateProperty.all(ColorsManager.textPrimaryColor),
|
|
),
|
|
onPressed: () {},
|
|
),
|
|
IconButton(
|
|
icon: const Icon(
|
|
Icons.more_vert,
|
|
size: 25,
|
|
),
|
|
style: ButtonStyle(
|
|
foregroundColor:
|
|
MaterialStateProperty.all(ColorsManager.textPrimaryColor),
|
|
),
|
|
onPressed: () {},
|
|
),
|
|
],
|
|
'Menu': [
|
|
IconButton(
|
|
icon: SvgPicture.asset(
|
|
Assets.iconsScan,
|
|
height: 20,
|
|
width: 20,
|
|
),
|
|
onPressed: () {},
|
|
),
|
|
],
|
|
};
|
|
|
|
static Map<String, Widget?> appBarLeading = {
|
|
'Dashboard': const AppBarHomeDropdown(),
|
|
'Devices': const AppBarHomeDropdown(),
|
|
'Routine': const AppBarHomeDropdown(),
|
|
'Menu': Padding(
|
|
padding: const EdgeInsets.only(left: 15),
|
|
child: Image.asset(
|
|
Assets.imagesLogoHorizontal,
|
|
height: 15,
|
|
width: 100,
|
|
fit: BoxFit.scaleDown,
|
|
),
|
|
),
|
|
};
|
|
|
|
static var bottomNavItems = [
|
|
defaultBottomNavBarItem(icon: Assets.iconsDashboard, label: 'Dashboard'),
|
|
// defaultBottomNavBarItem(icon: Assets.iconslayout, label: 'Layout'),
|
|
defaultBottomNavBarItem(icon: Assets.iconsDevices, label: 'Devices'),
|
|
defaultBottomNavBarItem(icon: Assets.iconsRoutines, label: 'Routine'),
|
|
defaultBottomNavBarItem(icon: Assets.iconsMenu, label: 'Menu'),
|
|
];
|
|
|
|
final List<Widget> pages = [
|
|
const DashboardView(),
|
|
// const LayoutPage(),
|
|
BlocProvider(
|
|
create: (context) => DevicesCubit.getInstance(),
|
|
child: const DevicesViewBody(),
|
|
),
|
|
const SceneView(),
|
|
const MenuView(),
|
|
];
|
|
|
|
void updatePageIndex(int index) {
|
|
pageIndex = index;
|
|
|
|
emitSafe(NavChangePage());
|
|
}
|
|
}
|
|
|
|
BottomNavigationBarItem defaultBottomNavBarItem(
|
|
{required String icon, required String label}) {
|
|
return BottomNavigationBarItem(
|
|
icon: SvgPicture.asset(icon),
|
|
activeIcon: SvgPicture.asset(
|
|
icon.replaceAll('.svg', '-fill.svg'),
|
|
colorFilter: const ColorFilter.mode(
|
|
ColorsManager.primaryColor,
|
|
BlendMode.srcIn,
|
|
),
|
|
),
|
|
label: label,
|
|
);
|
|
}
|