mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-07-15 17:47:28 +00:00
push scene devices body with blocs. need to drop the future builder - enhancment
This commit is contained in:
@ -291,8 +291,10 @@ class DevicesCubit extends Cubit<DevicesState> {
|
|||||||
if (roomId == null) return;
|
if (roomId == null) return;
|
||||||
|
|
||||||
emitSafe(GetDevicesLoading());
|
emitSafe(GetDevicesLoading());
|
||||||
int roomIndex =
|
int roomIndex = HomeCubit.getInstance()
|
||||||
HomeCubit.getInstance().selectedSpace!.rooms!.indexWhere((element) => element.id == roomId);
|
.selectedSpace!
|
||||||
|
.rooms!
|
||||||
|
.indexWhere((element) => element.id == roomId);
|
||||||
try {
|
try {
|
||||||
HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices =
|
HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices =
|
||||||
await DevicesAPI.getDevicesByRoomId(roomId);
|
await DevicesAPI.getDevicesByRoomId(roomId);
|
||||||
@ -300,7 +302,9 @@ class DevicesCubit extends Cubit<DevicesState> {
|
|||||||
emitSafe(GetDevicesError(e.toString()));
|
emitSafe(GetDevicesError(e.toString()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emitSafe(GetDevicesSuccess());
|
final devices =
|
||||||
|
HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices;
|
||||||
|
emitSafe(GetDevicesSuccess(devices));
|
||||||
|
|
||||||
//get status for each device
|
//get status for each device
|
||||||
//TODO get devices status per page via page controller instead of getting all devices status at once
|
//TODO get devices status per page via page controller instead of getting all devices status at once
|
||||||
@ -329,8 +333,11 @@ class DevicesCubit extends Cubit<DevicesState> {
|
|||||||
emitSafe(GetDeviceStatusError(e.toString()));
|
emitSafe(GetDeviceStatusError(e.toString()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices![deviceIndex].status =
|
HomeCubit.getInstance()
|
||||||
statuses;
|
.selectedSpace!
|
||||||
|
.rooms![roomIndex]
|
||||||
|
.devices![deviceIndex]
|
||||||
|
.status = statuses;
|
||||||
emitSafe(GetDeviceStatusSuccess(code: code));
|
emitSafe(GetDeviceStatusSuccess(code: code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,10 @@ class GetDeviceStatusError extends DevicesState {
|
|||||||
|
|
||||||
class GetDevicesLoading extends DevicesState {}
|
class GetDevicesLoading extends DevicesState {}
|
||||||
|
|
||||||
class GetDevicesSuccess extends DevicesState {}
|
class GetDevicesSuccess extends DevicesState {
|
||||||
|
GetDevicesSuccess(this.devices);
|
||||||
|
final List<DeviceModel>? devices;
|
||||||
|
}
|
||||||
|
|
||||||
class GetDevicesError extends DevicesState {
|
class GetDevicesError extends DevicesState {
|
||||||
final String errorMsg;
|
final String errorMsg;
|
||||||
|
11
lib/features/scene/bloc/tab_change/tab_change_bloc.dart
Normal file
11
lib/features/scene/bloc/tab_change/tab_change_bloc.dart
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_event.dart';
|
||||||
|
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_state.dart';
|
||||||
|
|
||||||
|
class TabBarBloc extends Bloc<TabBarEvent, TabBarState> {
|
||||||
|
TabBarBloc() : super(const Initial()) {
|
||||||
|
on<TabChanged>((event, emit) {
|
||||||
|
emit(TabSelected(event.tabIndex));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
8
lib/features/scene/bloc/tab_change/tab_change_event.dart
Normal file
8
lib/features/scene/bloc/tab_change/tab_change_event.dart
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
abstract class TabBarEvent {
|
||||||
|
const TabBarEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TabChanged extends TabBarEvent {
|
||||||
|
final int tabIndex;
|
||||||
|
const TabChanged(this.tabIndex);
|
||||||
|
}
|
12
lib/features/scene/bloc/tab_change/tab_change_state.dart
Normal file
12
lib/features/scene/bloc/tab_change/tab_change_state.dart
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
abstract class TabBarState {
|
||||||
|
const TabBarState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Initial extends TabBarState {
|
||||||
|
const Initial();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TabSelected extends TabBarState {
|
||||||
|
final int selectedTabIndex;
|
||||||
|
const TabSelected(this.selectedTabIndex);
|
||||||
|
}
|
@ -12,6 +12,7 @@ import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
|
|||||||
class CreateSceneView extends StatelessWidget {
|
class CreateSceneView extends StatelessWidget {
|
||||||
const CreateSceneView({super.key});
|
const CreateSceneView({super.key});
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DefaultScaffold(
|
return DefaultScaffold(
|
||||||
|
180
lib/features/scene/view/scene_control_devices.dart
Normal file
180
lib/features/scene/view/scene_control_devices.dart
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
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/devices/bloc/devices_cubit.dart';
|
||||||
|
import 'package:syncrow_app/features/devices/model/room_model.dart';
|
||||||
|
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_event.dart';
|
||||||
|
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_state.dart';
|
||||||
|
import 'package:syncrow_app/features/scene/view/widgets/scene_list_tile.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||||
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||||
|
|
||||||
|
import 'package:syncrow_app/generated/assets.dart';
|
||||||
|
import 'package:syncrow_app/utils/context_extension.dart';
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||||
|
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
|
||||||
|
|
||||||
|
class SceneControlDevicesView extends StatefulWidget {
|
||||||
|
const SceneControlDevicesView({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SceneControlDevicesView> createState() =>
|
||||||
|
_SceneControlDevicesViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SceneControlDevicesViewState extends State<SceneControlDevicesView>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late final TabController _tabController;
|
||||||
|
List<RoomModel>? rooms = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
rooms = HomeCubit.getInstance().selectedSpace!.rooms!;
|
||||||
|
|
||||||
|
_tabController =
|
||||||
|
TabController(length: rooms!.length, vsync: this, initialIndex: 0);
|
||||||
|
_tabController.addListener(_handleTabSelection);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleTabSelection() {
|
||||||
|
if (_tabController.indexIsChanging) {
|
||||||
|
context.read<TabBarBloc>().add(TabChanged(_tabController.index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
_tabController.dispose();
|
||||||
|
_tabController.removeListener(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return DefaultScaffold(
|
||||||
|
title: StringsManager.createScene,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
child: BlocProvider(
|
||||||
|
create: (context) => DevicesCubit.getInstance(),
|
||||||
|
child: FutureBuilder(
|
||||||
|
future: DevicesCubit.getInstance()
|
||||||
|
.fetchDevicesByRoomId(rooms![0].id!),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return Text(snapshot.error.toString());
|
||||||
|
} else {
|
||||||
|
return SceneDevicesBody(
|
||||||
|
tabController: _tabController, rooms: rooms);
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SceneDevicesBody extends StatelessWidget {
|
||||||
|
const SceneDevicesBody({
|
||||||
|
super.key,
|
||||||
|
required TabController tabController,
|
||||||
|
required this.rooms,
|
||||||
|
}) : _tabController = tabController;
|
||||||
|
|
||||||
|
final TabController _tabController;
|
||||||
|
final List<RoomModel>? rooms;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocBuilder<TabBarBloc, TabBarState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
TabBar(
|
||||||
|
controller: _tabController,
|
||||||
|
dividerColor: Colors.transparent,
|
||||||
|
indicatorColor: Colors.transparent,
|
||||||
|
tabs: List.generate(rooms!.length, (index) {
|
||||||
|
return Tab(
|
||||||
|
child: BodyLarge(
|
||||||
|
text: rooms![index].name ?? '',
|
||||||
|
style: context.bodyLarge.copyWith(
|
||||||
|
color: (state is TabSelected) &&
|
||||||
|
state.selectedTabIndex == index
|
||||||
|
? ColorsManager.textPrimaryColor
|
||||||
|
: ColorsManager.textPrimaryColor.withOpacity(0.2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
isScrollable: true,
|
||||||
|
onTap: (value) {
|
||||||
|
DevicesCubit.getInstance()
|
||||||
|
.fetchDevicesByRoomId(rooms![value].id!);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: TabBarView(
|
||||||
|
controller: _tabController,
|
||||||
|
children: rooms!
|
||||||
|
.map((e) => BlocBuilder<DevicesCubit, DevicesState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
if (state is GetDevicesLoading) {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator());
|
||||||
|
} else if (state is GetDevicesSuccess) {
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: state.devices!.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final device = state.devices![index];
|
||||||
|
return DefaultContainer(
|
||||||
|
child: SceneListTile(
|
||||||
|
minLeadingWidth: 40,
|
||||||
|
leadingWidget: Image.network(
|
||||||
|
device.icon ?? '',
|
||||||
|
errorBuilder:
|
||||||
|
(context, error, stackTrace) =>
|
||||||
|
Image.asset(
|
||||||
|
Assets.assetsIconsLogo,
|
||||||
|
width: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
titleWidget: BodyMedium(
|
||||||
|
text: device.name ?? '',
|
||||||
|
style: context.titleSmall.copyWith(
|
||||||
|
color:
|
||||||
|
ColorsManager.secondaryTextColor,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
trailingWidget: const Icon(
|
||||||
|
Icons.arrow_forward_ios_rounded,
|
||||||
|
size: 16,
|
||||||
|
weight: 0.2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else if (state is GetDevicesError) {
|
||||||
|
return Center(child: Text(state.errorMsg));
|
||||||
|
}
|
||||||
|
return const SizedBox();
|
||||||
|
},
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import 'package:syncrow_app/features/shared_widgets/light_divider.dart';
|
|||||||
|
|
||||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||||
import 'package:syncrow_app/generated/assets.dart';
|
import 'package:syncrow_app/generated/assets.dart';
|
||||||
|
import 'package:syncrow_app/navigation/routing_constants.dart';
|
||||||
import 'package:syncrow_app/utils/context_extension.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/color_manager.dart';
|
||||||
|
|
||||||
@ -46,7 +47,9 @@ class CustomBottomSheetWidget extends StatelessWidget {
|
|||||||
size: 16,
|
size: 16,
|
||||||
color: ColorsManager.greyColor,
|
color: ColorsManager.greyColor,
|
||||||
),
|
),
|
||||||
onPressed: () {},
|
onPressed: () {
|
||||||
|
Navigator.pushNamed(context, Routes.sceneControlDevicesRoute);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
SceneListTile(
|
SceneListTile(
|
||||||
assetPath: Assets.player,
|
assetPath: Assets.player,
|
||||||
|
@ -19,6 +19,7 @@ class SceneListTile extends StatelessWidget {
|
|||||||
this.onPressed,
|
this.onPressed,
|
||||||
this.assetHeight,
|
this.assetHeight,
|
||||||
this.minLeadingWidth,
|
this.minLeadingWidth,
|
||||||
|
this.titleWidget,
|
||||||
});
|
});
|
||||||
final String? assetPath;
|
final String? assetPath;
|
||||||
final String? titleString;
|
final String? titleString;
|
||||||
@ -30,6 +31,7 @@ class SceneListTile extends StatelessWidget {
|
|||||||
final void Function()? onPressed;
|
final void Function()? onPressed;
|
||||||
final double? assetHeight;
|
final double? assetHeight;
|
||||||
final double? minLeadingWidth;
|
final double? minLeadingWidth;
|
||||||
|
final Widget? titleWidget;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -46,11 +48,12 @@ class SceneListTile extends StatelessWidget {
|
|||||||
: null),
|
: null),
|
||||||
trailing: trailingWidget,
|
trailing: trailingWidget,
|
||||||
contentPadding: padding,
|
contentPadding: padding,
|
||||||
title: BodyMedium(
|
title: titleWidget ??
|
||||||
text: titleString ?? '',
|
BodyMedium(
|
||||||
textAlign: textAlign,
|
text: titleString ?? '',
|
||||||
style: context.bodyMedium.copyWith(fontSize: 15),
|
textAlign: textAlign,
|
||||||
),
|
style: context.bodyMedium.copyWith(fontSize: 15),
|
||||||
|
),
|
||||||
subtitle: subtitle == null
|
subtitle: subtitle == null
|
||||||
? null
|
? null
|
||||||
: BodySmall(
|
: BodySmall(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_app/features/app_layout/view/app_layout.dart';
|
import 'package:syncrow_app/features/app_layout/view/app_layout.dart';
|
||||||
import 'package:syncrow_app/features/auth/view/otp_view.dart';
|
import 'package:syncrow_app/features/auth/view/otp_view.dart';
|
||||||
import 'package:syncrow_app/features/auth/view/login_view.dart';
|
import 'package:syncrow_app/features/auth/view/login_view.dart';
|
||||||
@ -8,7 +9,10 @@ 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/menu/view/menu_view.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/widgets/create_home/create_home_view.dart';
|
import 'package:syncrow_app/features/menu/view/widgets/create_home/create_home_view.dart';
|
||||||
import 'package:syncrow_app/features/menu/view/widgets/profile/profile_view.dart';
|
import 'package:syncrow_app/features/menu/view/widgets/profile/profile_view.dart';
|
||||||
|
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_bloc.dart';
|
||||||
|
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_event.dart';
|
||||||
import 'package:syncrow_app/features/scene/view/scene_add_tasks.dart';
|
import 'package:syncrow_app/features/scene/view/scene_add_tasks.dart';
|
||||||
|
import 'package:syncrow_app/features/scene/view/scene_control_devices.dart';
|
||||||
import 'package:syncrow_app/features/scene/view/scene_view.dart';
|
import 'package:syncrow_app/features/scene/view/scene_view.dart';
|
||||||
import 'package:syncrow_app/features/splash/view/splash_view.dart';
|
import 'package:syncrow_app/features/splash/view/splash_view.dart';
|
||||||
import 'routing_constants.dart';
|
import 'routing_constants.dart';
|
||||||
@ -66,6 +70,13 @@ class Router {
|
|||||||
case Routes.sceneTasksRoute:
|
case Routes.sceneTasksRoute:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(
|
||||||
builder: (_) => const SceneAddTasksView(), settings: settings);
|
builder: (_) => const SceneAddTasksView(), settings: settings);
|
||||||
|
case Routes.sceneControlDevicesRoute:
|
||||||
|
return MaterialPageRoute(
|
||||||
|
builder: (_) => BlocProvider(
|
||||||
|
create: (context) => TabBarBloc()..add(const TabChanged(0)),
|
||||||
|
child: const SceneControlDevicesView(),
|
||||||
|
),
|
||||||
|
settings: settings);
|
||||||
default:
|
default:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(
|
||||||
builder: (_) => Scaffold(
|
builder: (_) => Scaffold(
|
||||||
|
@ -18,4 +18,5 @@ class Routes {
|
|||||||
static const String otpRoute = '/otp';
|
static const String otpRoute = '/otp';
|
||||||
static const String createUnit = '/create-unit';
|
static const String createUnit = '/create-unit';
|
||||||
static const String sceneTasksRoute = '/scene-tasks';
|
static const String sceneTasksRoute = '/scene-tasks';
|
||||||
|
static const String sceneControlDevicesRoute = '/scene-control-devices';
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ abstract class ColorsManager {
|
|||||||
static const Color primaryColor = Color(0xFF0030CB);
|
static const Color primaryColor = Color(0xFF0030CB);
|
||||||
static Color primaryColorWithOpacity =
|
static Color primaryColorWithOpacity =
|
||||||
const Color(0xFF023DFE).withOpacity(0.6);
|
const Color(0xFF023DFE).withOpacity(0.6);
|
||||||
|
static const Color secondaryTextColor = Color(0xFF848484);
|
||||||
static const Color onPrimaryColor = Colors.white;
|
static const Color onPrimaryColor = Colors.white;
|
||||||
static const Color secondaryColor = Color(0xFF023DFE);
|
static const Color secondaryColor = Color(0xFF023DFE);
|
||||||
static const Color onSecondaryColor = Color(0xFF023DFE);
|
static const Color onSecondaryColor = Color(0xFF023DFE);
|
||||||
|
Reference in New Issue
Block a user