Merge pull request #148 from SyncrowIOT/SP-1435-FE-On-routines-page-when-the-screen-height-is-decreased-or-is-small-the-scroll-area-for-routine-cards-is-not-fitting-the-whole-screen-width

Sp 1435 fe on routines page when the screen height is decreased or is small the scroll area for routine cards is not fitting the whole screen width
This commit is contained in:
Faris Armoush
2025-04-21 09:49:08 +03:00
committed by GitHub
4 changed files with 261 additions and 284 deletions

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_event.dart';
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_bloc.dart';
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_event.dart';
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routines/create_new_routines/create_new_routines.dart';
import 'package:syncrow_web/pages/routines/view/create_new_routine_view.dart';
@ -9,6 +9,7 @@ import 'package:syncrow_web/pages/routines/widgets/main_routine_view/fetch_routi
import 'package:syncrow_web/pages/routines/widgets/main_routine_view/routine_view_card.dart';
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
class RoutinesView extends StatefulWidget {
const RoutinesView({super.key});
@ -27,9 +28,10 @@ class _RoutinesViewState extends State<RoutinesView> {
if (result == null) return;
final communityId = result['community'];
final spaceId = result['space'];
final _bloc = BlocProvider.of<CreateRoutineBloc>(context);
final bloc = BlocProvider.of<CreateRoutineBloc>(context);
final routineBloc = context.read<RoutineBloc>();
_bloc.add(SaveCommunityIdAndSpaceIdEvent(communityID: communityId, spaceID: spaceId));
bloc.add(
SaveCommunityIdAndSpaceIdEvent(communityID: communityId, spaceID: spaceId));
await Future.delayed(const Duration(seconds: 1));
routineBloc.add(const CreateNewRoutineViewEvent(createRoutineView: true));
}
@ -54,13 +56,15 @@ class _RoutinesViewState extends State<RoutinesView> {
),
Expanded(
flex: 4,
child: ListView(
children: [
Container(
padding: const EdgeInsets.all(16),
height: MediaQuery.sizeOf(context).height,
child: SizedBox(
height: context.screenHeight,
width: context.screenWidth,
child: SingleChildScrollView(
padding: const EdgeInsetsDirectional.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
spacing: 16,
children: [
Text(
"Create New Routines",
@ -69,7 +73,6 @@ class _RoutinesViewState extends State<RoutinesView> {
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
RoutineViewCard(
isLoading: false,
onChanged: (v) {},
@ -84,13 +87,10 @@ class _RoutinesViewState extends State<RoutinesView> {
icon: Icons.add,
textString: '',
),
const SizedBox(height: 15),
const Expanded(child: FetchRoutineScenesAutomation()),
const FetchRoutineScenesAutomation(),
],
),
),
const SizedBox(height: 50),
],
),
)
],

View File

@ -8,67 +8,121 @@ import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class FetchRoutineScenesAutomation extends StatefulWidget {
const FetchRoutineScenesAutomation({super.key});
@override
State<FetchRoutineScenesAutomation> createState() =>
_FetchRoutineScenesState();
}
class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
class FetchRoutineScenesAutomation extends StatelessWidget
with HelperResponsiveLayout {
@override
void initState() {
super.initState();
}
const FetchRoutineScenesAutomation({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<RoutineBloc, RoutineState>(
builder: (context, state) {
return state.isLoading
? const Center(
child: CircularProgressIndicator(),
)
: SingleChildScrollView(
if (state.isLoading) return const Center(child: CircularProgressIndicator());
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Scenes (Tab to Run)",
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.bold,
_buildListTitle(context, "Scenes (Tab to Run)"),
const SizedBox(height: 10),
Visibility(
visible: state.scenes.isNotEmpty,
replacement: _buildEmptyState(context, "No scenes found"),
child: SizedBox(
height: 200,
child: _buildScenes(state),
),
),
const SizedBox(height: 10),
if (state.scenes.isEmpty)
Text(
"No scenes found",
style: context.textTheme.bodyMedium?.copyWith(
color: ColorsManager.grayColor,
),
),
if (state.scenes.isNotEmpty)
SizedBox(
_buildListTitle(context, "Automations"),
const SizedBox(height: 3),
Visibility(
visible: state.automations.isNotEmpty,
replacement: _buildEmptyState(context, "No automations found"),
child: SizedBox(
height: 200,
child: ListView.builder(
shrinkWrap: true,
child: _buildAutomations(state),
),
)
],
),
),
);
},
);
}
Widget _buildAutomations(RoutineState state) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: state.automations.length,
itemBuilder: (context, index) {
final isLoading = state.automations.contains(state.automations[index].id);
return Column(
children: [
Padding(
padding: EdgeInsets.only(
right: isSmallScreenSize(context) ? 4.0 : 8.0,
),
child: RoutineViewCard(
isLoading: isLoading,
onChanged: (v) {
context.read<RoutineBloc>().add(
UpdateAutomationStatus(
automationId: state.automations[index].id,
automationStatusUpdate: AutomationStatusUpdate(
spaceUuid: state.automations[index].spaceId,
isEnable: v,
),
communityId: state.automations[index].communityId,
),
);
},
status: state.automations[index].status,
communityId: '',
spaceId: state.automations[index].spaceId,
sceneId: '',
automationId: state.automations[index].id,
cardType: 'automations',
spaceName: state.automations[index].spaceName,
onTap: () {
BlocProvider.of<RoutineBloc>(context).add(
const CreateNewRoutineViewEvent(
createRoutineView: true,
),
);
context.read<RoutineBloc>().add(
GetAutomationDetails(
automationId: state.automations[index].id,
isAutomation: true,
isUpdate: true,
),
);
},
textString: state.automations[index].name,
icon: state.automations[index].icon ?? Assets.automation,
),
),
],
);
},
);
}
Widget _buildScenes(RoutineState state) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: state.scenes.length,
itemBuilder: (context, index) {
final scene = state.scenes[index];
final isLoading =
state.loadingSceneId == scene.id;
final isLoading = state.loadingSceneId == scene.id;
return Padding(
padding: EdgeInsets.only(
right:
isSmallScreenSize(context) ? 4.0 : 8.0,
right: isSmallScreenSize(context) ? 4.0 : 8.0,
),
child: Column(
children: [
@ -78,141 +132,58 @@ class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
context.read<RoutineBloc>().add(
SceneTrigger(
sceneId: scene.id,
name: scene.name));
name: scene.name,
),
);
},
status: state.scenes[index].status,
communityId:
state.scenes[index].communityId ??
'',
communityId: state.scenes[index].communityId,
spaceId: state.scenes[index].spaceId,
sceneId:
state.scenes[index].sceneTuyaId!,
sceneId: state.scenes[index].sceneTuyaId!,
automationId: state.scenes[index].id,
cardType: 'scenes',
spaceName:
state.scenes[index].spaceName,
spaceName: state.scenes[index].spaceName,
onTap: () {
BlocProvider.of<RoutineBloc>(context)
.add(
BlocProvider.of<RoutineBloc>(context).add(
const CreateNewRoutineViewEvent(
createRoutineView: true),
createRoutineView: true,
),
);
context.read<RoutineBloc>().add(
GetSceneDetails(
sceneId:
state.scenes[index].id,
sceneId: state.scenes[index].id,
isTabToRun: true,
isUpdate: true,
),
);
},
textString: state.scenes[index].name,
icon: state.scenes[index].icon ??
Assets.logoHorizontal,
icon: state.scenes[index].icon ?? Assets.logoHorizontal,
isFromScenes: true,
iconInBytes:
state.scenes[index].iconInBytes,
iconInBytes: state.scenes[index].iconInBytes,
),
],
),
);
}),
),
const SizedBox(height: 10),
Text(
"Automations",
});
}
Widget _buildListTitle(BuildContext context, String title) {
return Text(
title,
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 3),
if (state.automations.isEmpty)
Text(
"No automations found",
);
}
Widget _buildEmptyState(BuildContext context, String title) {
return Text(
title,
style: context.textTheme.bodyMedium?.copyWith(
color: ColorsManager.grayColor,
),
),
if (state.automations.isNotEmpty)
SizedBox(
height: 200,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: state.automations.length,
itemBuilder: (context, index) {
final isLoading = state.automations!
.contains(state.automations[index].id);
return Column(
children: [
Padding(
padding: EdgeInsets.only(
right: isSmallScreenSize(context)
? 4.0
: 8.0,
),
child: RoutineViewCard(
isLoading: isLoading,
onChanged: (v) {
context.read<RoutineBloc>().add(
UpdateAutomationStatus(
automationId: state
.automations[index].id,
automationStatusUpdate:
AutomationStatusUpdate(
spaceUuid: state
.automations[
index]
.spaceId,
isEnable: v),
communityId: state
.automations[index]
.communityId,
),
);
},
status: state.automations[index].status,
communityId: '',
spaceId:
state.automations[index].spaceId,
sceneId: '',
automationId:
state.automations[index].id,
cardType: 'automations',
spaceName:
state.automations[index].spaceName,
onTap: () {
BlocProvider.of<RoutineBloc>(context)
.add(
const CreateNewRoutineViewEvent(
createRoutineView: true),
);
context.read<RoutineBloc>().add(
GetAutomationDetails(
automationId: state
.automations[index].id,
isAutomation: true,
isUpdate: true),
);
},
textString:
state.automations[index].name,
icon: state.automations[index].icon ??
Assets.automation,
),
),
],
);
}),
),
],
),
),
);
},
);
}
}

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -66,7 +67,6 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
@override
Widget build(BuildContext context) {
// Use widget.<mixinMethod> instead of just <mixinMethod>
final double cardWidth = widget.isSmallScreenSize(context)
? 120
: widget.isMediumScreenSize(context)
@ -127,22 +127,23 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
)
else
CupertinoSwitch(
activeColor: ColorsManager.primaryColor,
activeTrackColor: ColorsManager.primaryColor,
value: widget.status == 'enable',
onChanged: widget.onChanged,
)
],
)
: const SizedBox(),
InkWell(
onTap: widget.onTap,
child: Column(
Column(
children: [
Center(
child: InkWell(
customBorder: const CircleBorder(),
onTap: widget.onTap,
child: Container(
decoration: BoxDecoration(
color: ColorsManager.graysColor,
borderRadius: BorderRadius.circular(120),
shape: BoxShape.circle,
border: Border.all(
color: ColorsManager.greyColor,
width: 2.0,
@ -158,7 +159,8 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
height: iconSize,
width: iconSize,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) => Image.asset(
errorBuilder: (context, error, stackTrace) =>
Image.asset(
Assets.logo,
height: iconSize,
width: iconSize,
@ -171,7 +173,8 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
width: iconSize,
fit: BoxFit.contain,
)
: (widget.icon is String && widget.icon.endsWith('.svg'))
: (widget.icon is String &&
widget.icon.endsWith('.svg'))
? SvgPicture.asset(
height: iconSize,
width: iconSize,
@ -181,7 +184,10 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
: Icon(
widget.icon,
color: ColorsManager.dialogBlueTitle,
size: widget.isSmallScreenSize(context) ? 30 : 40,
size: widget.isSmallScreenSize(context)
? 30
: 40,
),
),
),
),
@ -216,7 +222,8 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
maxLines: 1,
style: context.textTheme.bodySmall?.copyWith(
color: ColorsManager.blackColor,
fontSize: widget.isSmallScreenSize(context) ? 10 : 12,
fontSize:
widget.isSmallScreenSize(context) ? 10 : 12,
),
),
],
@ -226,7 +233,6 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
),
],
),
),
],
),
),

View File

@ -31,7 +31,7 @@ class CustomExpansionTileSpaceTree extends StatelessWidget {
children: [
Checkbox(
value: isSoldCheck ? null : isSelected,
onChanged: (value) => onItemSelected ?? () {},
onChanged: (value) => onItemSelected?.call(),
tristate: true,
side: WidgetStateBorderSide.resolveWith(
(states) => const BorderSide(color: ColorsManager.grayBorder),