push scene devices body with blocs. need to drop the future builder - enhancment

This commit is contained in:
ashrafzarkanisala
2024-06-13 02:13:44 +03:00
parent 4a93bc2892
commit a8132c37db
12 changed files with 253 additions and 13 deletions

View File

@ -291,8 +291,10 @@ class DevicesCubit extends Cubit<DevicesState> {
if (roomId == null) return;
emitSafe(GetDevicesLoading());
int roomIndex =
HomeCubit.getInstance().selectedSpace!.rooms!.indexWhere((element) => element.id == roomId);
int roomIndex = HomeCubit.getInstance()
.selectedSpace!
.rooms!
.indexWhere((element) => element.id == roomId);
try {
HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices =
await DevicesAPI.getDevicesByRoomId(roomId);
@ -300,7 +302,9 @@ class DevicesCubit extends Cubit<DevicesState> {
emitSafe(GetDevicesError(e.toString()));
return;
}
emitSafe(GetDevicesSuccess());
final devices =
HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices;
emitSafe(GetDevicesSuccess(devices));
//get status for each device
//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()));
return;
}
HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices![deviceIndex].status =
statuses;
HomeCubit.getInstance()
.selectedSpace!
.rooms![roomIndex]
.devices![deviceIndex]
.status = statuses;
emitSafe(GetDeviceStatusSuccess(code: code));
}

View File

@ -35,7 +35,10 @@ class GetDeviceStatusError 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 {
final String errorMsg;

View 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));
});
}
}

View File

@ -0,0 +1,8 @@
abstract class TabBarEvent {
const TabBarEvent();
}
class TabChanged extends TabBarEvent {
final int tabIndex;
const TabChanged(this.tabIndex);
}

View 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);
}

View File

@ -12,6 +12,7 @@ import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
class CreateSceneView extends StatelessWidget {
const CreateSceneView({super.key});
@override
Widget build(BuildContext context) {
return DefaultScaffold(

View 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(),
),
),
],
);
},
);
}
}

View File

@ -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/generated/assets.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@ -46,7 +47,9 @@ class CustomBottomSheetWidget extends StatelessWidget {
size: 16,
color: ColorsManager.greyColor,
),
onPressed: () {},
onPressed: () {
Navigator.pushNamed(context, Routes.sceneControlDevicesRoute);
},
),
SceneListTile(
assetPath: Assets.player,

View File

@ -19,6 +19,7 @@ class SceneListTile extends StatelessWidget {
this.onPressed,
this.assetHeight,
this.minLeadingWidth,
this.titleWidget,
});
final String? assetPath;
final String? titleString;
@ -30,6 +31,7 @@ class SceneListTile extends StatelessWidget {
final void Function()? onPressed;
final double? assetHeight;
final double? minLeadingWidth;
final Widget? titleWidget;
@override
Widget build(BuildContext context) {
@ -46,7 +48,8 @@ class SceneListTile extends StatelessWidget {
: null),
trailing: trailingWidget,
contentPadding: padding,
title: BodyMedium(
title: titleWidget ??
BodyMedium(
text: titleString ?? '',
textAlign: textAlign,
style: context.bodyMedium.copyWith(fontSize: 15),

View File

@ -1,4 +1,5 @@
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/auth/view/otp_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/widgets/create_home/create_home_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_control_devices.dart';
import 'package:syncrow_app/features/scene/view/scene_view.dart';
import 'package:syncrow_app/features/splash/view/splash_view.dart';
import 'routing_constants.dart';
@ -66,6 +70,13 @@ class Router {
case Routes.sceneTasksRoute:
return MaterialPageRoute(
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:
return MaterialPageRoute(
builder: (_) => Scaffold(

View File

@ -18,4 +18,5 @@ class Routes {
static const String otpRoute = '/otp';
static const String createUnit = '/create-unit';
static const String sceneTasksRoute = '/scene-tasks';
static const String sceneControlDevicesRoute = '/scene-control-devices';
}

View File

@ -6,7 +6,7 @@ abstract class ColorsManager {
static const Color primaryColor = Color(0xFF0030CB);
static Color primaryColorWithOpacity =
const Color(0xFF023DFE).withOpacity(0.6);
static const Color secondaryTextColor = Color(0xFF848484);
static const Color onPrimaryColor = Colors.white;
static const Color secondaryColor = Color(0xFF023DFE);
static const Color onSecondaryColor = Color(0xFF023DFE);