fix routine popup

This commit is contained in:
mohammad
2025-04-07 12:53:12 +03:00
parent 9949a0a0bf
commit ca44f3bf55
6 changed files with 290 additions and 236 deletions

View File

@ -2,6 +2,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_manager.dart'; import 'package:syncrow_web/pages/common/bloc/project_manager.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_event.dart';
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_state.dart'; import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_state.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
import 'package:syncrow_web/services/space_mana_api.dart'; import 'package:syncrow_web/services/space_mana_api.dart';
@ -10,11 +11,12 @@ class CreateRoutineBloc extends Bloc<CreateRoutineEvent, CreateRoutineState> {
on<SpaceOnlyWithDevicesEvent>(_fetchSpaceOnlyWithDevices); on<SpaceOnlyWithDevicesEvent>(_fetchSpaceOnlyWithDevices);
on<SaveCommunityIdAndSpaceIdEvent>(saveSpaceIdCommunityId); on<SaveCommunityIdAndSpaceIdEvent>(saveSpaceIdCommunityId);
on<ResetSelectedEvent>(resetSelected); on<ResetSelectedEvent>(resetSelected);
on<FetchCommunityEvent>(_fetchCommunity);
} }
String selectedSpaceId = ''; String selectedSpaceId = '';
String selectedCommunityId = ''; String selectedCommunityId = '';
List<CommunityModel> communities = [];
List<SpaceModel> spacesOnlyWithDevices = []; List<SpaceModel> spacesOnlyWithDevices = [];
Future<void> _fetchSpaceOnlyWithDevices( Future<void> _fetchSpaceOnlyWithDevices(
@ -30,7 +32,7 @@ class CreateRoutineBloc extends Bloc<CreateRoutineEvent, CreateRoutineState> {
emit(SpaceWithDeviceLoadedState(spacesOnlyWithDevices)); emit(SpaceWithDeviceLoadedState(spacesOnlyWithDevices));
} catch (e) { } catch (e) {
emit(SpaceTreeErrorState('Error loading communities and spaces: $e')); emit(SpaceTreeErrorState('Error loading spaces: $e'));
} }
} }
@ -48,4 +50,18 @@ class CreateRoutineBloc extends Bloc<CreateRoutineEvent, CreateRoutineState> {
selectedCommunityId = ''; selectedCommunityId = '';
emit(const ResetSelectedState()); emit(const ResetSelectedState());
} }
Future<void> _fetchCommunity(
FetchCommunityEvent event, Emitter<CreateRoutineState> emit) async {
emit(const CommunitiesLoadingState());
try {
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
communities =
await CommunitySpaceManagementApi().fetchCommunities(projectUuid);
emit(const CommunityLoadedState());
} catch (e) {
emit(SpaceTreeErrorState('Error loading communities $e'));
}
}
} }

View File

@ -41,3 +41,11 @@ class ResetSelectedEvent extends CreateRoutineEvent {
@override @override
List<Object> get props => []; List<Object> get props => [];
} }
class FetchCommunityEvent extends CreateRoutineEvent {
const FetchCommunityEvent();
@override
List<Object> get props => [];
}

View File

@ -44,3 +44,10 @@ class ResetSelectedState extends CreateRoutineState {
const ResetSelectedState(); const ResetSelectedState();
} }
class CommunityLoadedState extends CreateRoutineState {
const CommunityLoadedState();
}
class CommunitiesLoadingState extends CreateRoutineState {
const CommunitiesLoadingState();
}

View File

@ -1,12 +1,11 @@
import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
class CommunityDropdown extends StatelessWidget { class CommunityDropdown extends StatelessWidget {
final String? selectedValue; final String? selectedValue;
final List<CommunityModel> communities;
final Function(String?) onChanged; final Function(String?) onChanged;
final TextEditingController _searchController = TextEditingController(); final TextEditingController _searchController = TextEditingController();
@ -14,6 +13,7 @@ class CommunityDropdown extends StatelessWidget {
Key? key, Key? key,
required this.selectedValue, required this.selectedValue,
required this.onChanged, required this.onChanged,
required this.communities,
}) : super(key: key); }) : super(key: key);
@override @override
@ -32,17 +32,15 @@ class CommunityDropdown extends StatelessWidget {
), ),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
BlocBuilder<SpaceTreeBloc, SpaceTreeState>( SizedBox(
builder: (context, state) {
return SizedBox(
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
child: DropdownButton2<String>( child: DropdownButton2<String>(
underline: SizedBox(), underline: const SizedBox(),
value: selectedValue, value: selectedValue,
items: state.communityList.map((community) { items: communities.map((community) {
return DropdownMenuItem<String>( return DropdownMenuItem<String>(
value: community.uuid, value: community.uuid,
child: Text( child: Text(
@ -53,9 +51,9 @@ class CommunityDropdown extends StatelessWidget {
); );
}).toList(), }).toList(),
onChanged: onChanged, onChanged: onChanged,
style: TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
hint: Padding( hint: Padding(
padding: EdgeInsets.only(left: 10), padding: const EdgeInsets.only(left: 10),
child: Text( child: Text(
" Please Select", " Please Select",
style: Theme.of(context).textTheme.bodySmall!.copyWith( style: Theme.of(context).textTheme.bodySmall!.copyWith(
@ -76,11 +74,12 @@ class CommunityDropdown extends StatelessWidget {
flex: 5, flex: 5,
child: Text( child: Text(
selectedValue != null selectedValue != null
? " ${state.communityList.firstWhere((element) => element.uuid == selectedValue).name}" ? " ${communities.firstWhere((element) => element.uuid == selectedValue).name}"
: ' Please Select', : ' Please Select',
style: Theme.of(context).textTheme.bodySmall!.copyWith( style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: color: selectedValue != null
selectedValue != null ? Colors.black : ColorsManager.textGray, ? Colors.black
: ColorsManager.textGray,
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@ -115,7 +114,8 @@ class CommunityDropdown extends StatelessWidget {
searchInnerWidgetHeight: 50, searchInnerWidgetHeight: 50,
searchInnerWidget: Container( searchInnerWidget: Container(
height: 50, height: 50,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: TextFormField( child: TextFormField(
style: const TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
controller: _searchController, controller: _searchController,
@ -133,8 +133,10 @@ class CommunityDropdown extends StatelessWidget {
), ),
), ),
searchMatchFn: (item, searchValue) { searchMatchFn: (item, searchValue) {
final communityName = (item.child as Text).data?.toLowerCase() ?? ''; final communityName =
return communityName.contains(searchValue.toLowerCase().trim()); (item.child as Text).data?.toLowerCase() ?? '';
return communityName
.contains(searchValue.toLowerCase().trim());
}, },
), ),
onMenuStateChange: (isOpen) { onMenuStateChange: (isOpen) {
@ -146,9 +148,7 @@ class CommunityDropdown extends StatelessWidget {
height: 40, height: 40,
), ),
), ),
)); ))
},
),
], ],
), ),
); );

View File

@ -5,11 +5,10 @@ import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routi
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_bloc.dart';
import 'package:syncrow_web/pages/routines/create_new_routines/commu_dropdown.dart'; import 'package:syncrow_web/pages/routines/create_new_routines/commu_dropdown.dart';
import 'package:syncrow_web/pages/routines/create_new_routines/space_dropdown.dart'; import 'package:syncrow_web/pages/routines/create_new_routines/space_dropdown.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
class CreateNewRoutinesDialog extends StatefulWidget { class CreateNewRoutinesDialog extends StatefulWidget {
const CreateNewRoutinesDialog({Key? key}) : super(key: key); const CreateNewRoutinesDialog({super.key});
@override @override
State<CreateNewRoutinesDialog> createState() => State<CreateNewRoutinesDialog> createState() =>
@ -19,24 +18,21 @@ class CreateNewRoutinesDialog extends StatefulWidget {
class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> { class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
String? _selectedCommunity; String? _selectedCommunity;
String? _selectedSpace; String? _selectedSpace;
void _fetchSpaces(String communityId) {
context
.read<CreateRoutineBloc>()
.add(SpaceOnlyWithDevicesEvent(communityId));
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<CreateRoutineBloc, CreateRoutineState>( return BlocProvider(
create: (BuildContext context) =>
CreateRoutineBloc()..add(const FetchCommunityEvent()),
child: BlocBuilder<CreateRoutineBloc, CreateRoutineState>(
builder: (context, state) { builder: (context, state) {
final _bloc = BlocProvider.of<CreateRoutineBloc>(context); final _bloc = BlocProvider.of<CreateRoutineBloc>(context);
final spaces = _bloc.spacesOnlyWithDevices; final spaces = _bloc.spacesOnlyWithDevices;
final isLoading = state is SpaceWithDeviceLoadingState; final isLoadingCommunities = state is CommunitiesLoadingState;
final isLoadingSpaces = state is SpaceWithDeviceLoadingState;
String spaceHint = 'Select a community first'; String spaceHint = 'Select a community first';
if (_selectedCommunity != null) { if (_selectedCommunity != null) {
if (isLoading) { if (isLoadingSpaces) {
spaceHint = 'Loading spaces...'; spaceHint = 'Loading spaces...';
} else if (spaces.isEmpty) { } else if (spaces.isEmpty) {
spaceHint = 'No spaces available'; spaceHint = 'No spaces available';
@ -49,8 +45,8 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
backgroundColor: Colors.white, backgroundColor: Colors.white,
insetPadding: EdgeInsets.zero, insetPadding: EdgeInsets.zero,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
shape: shape: RoundedRectangleBorder(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), borderRadius: BorderRadius.circular(12)),
title: Text( title: Text(
'Create New Routines', 'Create New Routines',
textAlign: TextAlign.center, textAlign: TextAlign.center,
@ -58,13 +54,16 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
color: ColorsManager.primaryColor, color: ColorsManager.primaryColor,
), ),
), ),
content: Column( content: Stack(
children: [
Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Divider(), const Divider(),
Padding( Padding(
padding: const EdgeInsets.only(left: 15, right: 15), padding: const EdgeInsets.only(left: 15, right: 15),
child: CommunityDropdown( child: CommunityDropdown(
communities: _bloc.communities,
selectedValue: _selectedCommunity, selectedValue: _selectedCommunity,
onChanged: (String? newValue) { onChanged: (String? newValue) {
setState(() { setState(() {
@ -72,7 +71,7 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
_selectedSpace = null; _selectedSpace = null;
}); });
if (newValue != null) { if (newValue != null) {
_fetchSpaces(newValue); _bloc.add(SpaceOnlyWithDevicesEvent(newValue));
} }
}, },
), ),
@ -106,7 +105,10 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
}, },
child: Text( child: Text(
'Cancel', 'Cancel',
style: Theme.of(context).textTheme.bodyMedium!.copyWith( style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
fontSize: 14, fontSize: 14,
color: ColorsManager.blackColor, color: ColorsManager.blackColor,
@ -120,8 +122,8 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
right: 20, right: 20,
), ),
child: TextButton( child: TextButton(
onPressed: onPressed: _selectedCommunity != null &&
_selectedCommunity != null && _selectedSpace != null _selectedSpace != null
? () { ? () {
Navigator.of(context).pop({ Navigator.of(context).pop({
'community': _selectedCommunity, 'community': _selectedCommunity,
@ -131,7 +133,10 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
: null, : null,
child: Text( child: Text(
'Next', 'Next',
style: Theme.of(context).textTheme.bodyMedium!.copyWith( style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
fontSize: 14, fontSize: 14,
color: _selectedCommunity != null && color: _selectedCommunity != null &&
@ -144,11 +149,31 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
), ),
], ],
), ),
SizedBox(height: 10), const SizedBox(height: 10),
],
),
if (isLoadingCommunities)
const SizedBox(
height: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Center(
child: Center(
child: CircularProgressIndicator(
color: ColorsManager.primaryColor,
),
),
),
],
),
),
], ],
), ),
); );
}, },
); ));
} }
} }

View File

@ -105,9 +105,7 @@ class IfContainer extends StatelessWidget {
); );
}, },
onAcceptWithDetails: (data) async { onAcceptWithDetails: (data) async {
print('data.data=${data.data}');
final uniqueCustomId = const Uuid().v4(); final uniqueCustomId = const Uuid().v4();
final mutableData = Map<String, dynamic>.from(data.data); final mutableData = Map<String, dynamic>.from(data.data);
mutableData['uniqueCustomId'] = uniqueCustomId; mutableData['uniqueCustomId'] = uniqueCustomId;