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/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/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/services/space_mana_api.dart';
@ -10,11 +11,12 @@ class CreateRoutineBloc extends Bloc<CreateRoutineEvent, CreateRoutineState> {
on<SpaceOnlyWithDevicesEvent>(_fetchSpaceOnlyWithDevices);
on<SaveCommunityIdAndSpaceIdEvent>(saveSpaceIdCommunityId);
on<ResetSelectedEvent>(resetSelected);
on<FetchCommunityEvent>(_fetchCommunity);
}
String selectedSpaceId = '';
String selectedCommunityId = '';
List<CommunityModel> communities = [];
List<SpaceModel> spacesOnlyWithDevices = [];
Future<void> _fetchSpaceOnlyWithDevices(
@ -30,7 +32,7 @@ class CreateRoutineBloc extends Bloc<CreateRoutineEvent, CreateRoutineState> {
emit(SpaceWithDeviceLoadedState(spacesOnlyWithDevices));
} 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 = '';
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
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();
}
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:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.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/pages/spaces_management/all_spaces/model/community_model.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class CommunityDropdown extends StatelessWidget {
final String? selectedValue;
final List<CommunityModel> communities;
final Function(String?) onChanged;
final TextEditingController _searchController = TextEditingController();
@ -14,6 +13,7 @@ class CommunityDropdown extends StatelessWidget {
Key? key,
required this.selectedValue,
required this.onChanged,
required this.communities,
}) : super(key: key);
@override
@ -32,123 +32,123 @@ class CommunityDropdown extends StatelessWidget {
),
),
const SizedBox(height: 8),
BlocBuilder<SpaceTreeBloc, SpaceTreeState>(
builder: (context, state) {
return SizedBox(
child: Container(
SizedBox(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
child: DropdownButton2<String>(
underline: const SizedBox(),
value: selectedValue,
items: communities.map((community) {
return DropdownMenuItem<String>(
value: community.uuid,
child: Text(
' ${community.name}',
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
);
}).toList(),
onChanged: onChanged,
style: const TextStyle(color: Colors.black),
hint: Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
" Please Select",
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.textGray,
),
),
),
customButton: Container(
height: 45,
decoration: BoxDecoration(
border: Border.all(color: ColorsManager.textGray, width: 1.0),
borderRadius: BorderRadius.circular(10),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 5,
child: Text(
selectedValue != null
? " ${communities.firstWhere((element) => element.uuid == selectedValue).name}"
: ' Please Select',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: selectedValue != null
? Colors.black
: ColorsManager.textGray,
),
overflow: TextOverflow.ellipsis,
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: const BorderRadius.only(
topRight: Radius.circular(10),
bottomRight: Radius.circular(10),
),
),
height: 45,
child: const Icon(
Icons.keyboard_arrow_down,
color: ColorsManager.textGray,
),
),
),
],
),
),
dropdownStyleData: DropdownStyleData(
maxHeight: MediaQuery.of(context).size.height * 0.4,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
child: DropdownButton2<String>(
underline: SizedBox(),
value: selectedValue,
items: state.communityList.map((community) {
return DropdownMenuItem<String>(
value: community.uuid,
child: Text(
' ${community.name}',
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
dropdownSearchData: DropdownSearchData(
searchController: _searchController,
searchInnerWidgetHeight: 50,
searchInnerWidget: Container(
height: 50,
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: TextFormField(
style: const TextStyle(color: Colors.black),
controller: _searchController,
decoration: InputDecoration(
isDense: true,
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 12,
),
);
}).toList(),
onChanged: onChanged,
style: TextStyle(color: Colors.black),
hint: Padding(
padding: EdgeInsets.only(left: 10),
child: Text(
" Please Select",
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.textGray,
),
),
),
customButton: Container(
height: 45,
decoration: BoxDecoration(
border: Border.all(color: ColorsManager.textGray, width: 1.0),
borderRadius: BorderRadius.circular(10),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 5,
child: Text(
selectedValue != null
? " ${state.communityList.firstWhere((element) => element.uuid == selectedValue).name}"
: ' Please Select',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color:
selectedValue != null ? Colors.black : ColorsManager.textGray,
),
overflow: TextOverflow.ellipsis,
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: const BorderRadius.only(
topRight: Radius.circular(10),
bottomRight: Radius.circular(10),
),
),
height: 45,
child: const Icon(
Icons.keyboard_arrow_down,
color: ColorsManager.textGray,
),
),
),
],
),
),
dropdownStyleData: DropdownStyleData(
maxHeight: MediaQuery.of(context).size.height * 0.4,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
),
dropdownSearchData: DropdownSearchData(
searchController: _searchController,
searchInnerWidgetHeight: 50,
searchInnerWidget: Container(
height: 50,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: TextFormField(
style: const TextStyle(color: Colors.black),
controller: _searchController,
decoration: InputDecoration(
isDense: true,
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 12,
),
hintText: 'Search for community...',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
hintText: 'Search for community...',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
searchMatchFn: (item, searchValue) {
final communityName = (item.child as Text).data?.toLowerCase() ?? '';
return communityName.contains(searchValue.toLowerCase().trim());
},
),
onMenuStateChange: (isOpen) {
if (!isOpen) {
_searchController.clear();
}
},
menuItemStyleData: const MenuItemStyleData(
height: 40,
),
),
));
},
),
searchMatchFn: (item, searchValue) {
final communityName =
(item.child as Text).data?.toLowerCase() ?? '';
return communityName
.contains(searchValue.toLowerCase().trim());
},
),
onMenuStateChange: (isOpen) {
if (!isOpen) {
_searchController.clear();
}
},
menuItemStyleData: const MenuItemStyleData(
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/create_new_routines/commu_dropdown.dart';
import 'package:syncrow_web/pages/routines/create_new_routines/space_dropdown.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class CreateNewRoutinesDialog extends StatefulWidget {
const CreateNewRoutinesDialog({Key? key}) : super(key: key);
const CreateNewRoutinesDialog({super.key});
@override
State<CreateNewRoutinesDialog> createState() =>
@ -19,136 +18,162 @@ class CreateNewRoutinesDialog extends StatefulWidget {
class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
String? _selectedCommunity;
String? _selectedSpace;
void _fetchSpaces(String communityId) {
context
.read<CreateRoutineBloc>()
.add(SpaceOnlyWithDevicesEvent(communityId));
}
@override
Widget build(BuildContext context) {
return BlocBuilder<CreateRoutineBloc, CreateRoutineState>(
builder: (context, state) {
final _bloc = BlocProvider.of<CreateRoutineBloc>(context);
final spaces = _bloc.spacesOnlyWithDevices;
final isLoading = state is SpaceWithDeviceLoadingState;
return BlocProvider(
create: (BuildContext context) =>
CreateRoutineBloc()..add(const FetchCommunityEvent()),
child: BlocBuilder<CreateRoutineBloc, CreateRoutineState>(
builder: (context, state) {
final _bloc = BlocProvider.of<CreateRoutineBloc>(context);
final spaces = _bloc.spacesOnlyWithDevices;
final isLoadingCommunities = state is CommunitiesLoadingState;
final isLoadingSpaces = state is SpaceWithDeviceLoadingState;
String spaceHint = 'Select a community first';
if (_selectedCommunity != null) {
if (isLoadingSpaces) {
spaceHint = 'Loading spaces...';
} else if (spaces.isEmpty) {
spaceHint = 'No spaces available';
} else {
spaceHint = 'Select Space';
}
}
String spaceHint = 'Select a community first';
if (_selectedCommunity != null) {
if (isLoading) {
spaceHint = 'Loading spaces...';
} else if (spaces.isEmpty) {
spaceHint = 'No spaces available';
} else {
spaceHint = 'Select Space';
}
}
return AlertDialog(
backgroundColor: Colors.white,
insetPadding: EdgeInsets.zero,
contentPadding: EdgeInsets.zero,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
title: Text(
'Create New Routines',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: ColorsManager.primaryColor,
),
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Divider(),
Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: CommunityDropdown(
selectedValue: _selectedCommunity,
onChanged: (String? newValue) {
setState(() {
_selectedCommunity = newValue;
_selectedSpace = null;
});
if (newValue != null) {
_fetchSpaces(newValue);
}
},
),
return AlertDialog(
backgroundColor: Colors.white,
insetPadding: EdgeInsets.zero,
contentPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
title: Text(
'Create New Routines',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: ColorsManager.primaryColor,
),
),
const SizedBox(height: 5),
Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: SpaceDropdown(
hintMessage: spaceHint,
spaces: spaces,
selectedValue: _selectedSpace,
onChanged: (String? newValue) {
setState(() {
_selectedSpace = newValue;
});
},
),
),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
content: Stack(
children: [
Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
),
child: TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
'Cancel',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
fontWeight: FontWeight.w400,
fontSize: 14,
color: ColorsManager.blackColor,
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
const Divider(),
Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: CommunityDropdown(
communities: _bloc.communities,
selectedValue: _selectedCommunity,
onChanged: (String? newValue) {
setState(() {
_selectedCommunity = newValue;
_selectedSpace = null;
});
if (newValue != null) {
_bloc.add(SpaceOnlyWithDevicesEvent(newValue));
}
},
),
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
),
child: TextButton(
onPressed:
_selectedCommunity != null && _selectedSpace != null
? () {
Navigator.of(context).pop({
'community': _selectedCommunity,
'space': _selectedSpace,
});
}
: null,
child: Text(
'Next',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
fontWeight: FontWeight.w400,
fontSize: 14,
color: _selectedCommunity != null &&
const SizedBox(height: 5),
Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: SpaceDropdown(
hintMessage: spaceHint,
spaces: spaces,
selectedValue: _selectedSpace,
onChanged: (String? newValue) {
setState(() {
_selectedSpace = newValue;
});
},
),
),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
),
child: TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
'Cancel',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
fontWeight: FontWeight.w400,
fontSize: 14,
color: ColorsManager.blackColor,
),
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
),
child: TextButton(
onPressed: _selectedCommunity != null &&
_selectedSpace != null
? ColorsManager.blueColor
: Colors.blue.shade100,
? () {
Navigator.of(context).pop({
'community': _selectedCommunity,
'space': _selectedSpace,
});
}
: null,
child: Text(
'Next',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
fontWeight: FontWeight.w400,
fontSize: 14,
color: _selectedCommunity != null &&
_selectedSpace != null
? ColorsManager.blueColor
: Colors.blue.shade100,
),
),
),
),
],
),
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,
),
),
),
],
),
),
),
],
),
SizedBox(height: 10),
],
),
);
},
);
);
},
));
}
}

View File

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