Refactor SpaceDetailsDialog and SpaceIconPicker to integrate Bloc for state management, enhancing icon selection and dialog functionality.

This commit is contained in:
Faris Armoush
2025-07-02 15:20:52 +03:00
parent 63353af38b
commit 9dfb3ed369
6 changed files with 99 additions and 65 deletions

View File

@ -7,7 +7,6 @@ import 'package:syncrow_web/pages/space_management_v2/modules/communities/data/s
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/params/load_communities_param.dart'; import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/params/load_communities_param.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart'; import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart'; import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/presentation/bloc/space_details_model_bloc/space_details_model_bloc.dart';
import 'package:syncrow_web/services/api/http_service.dart'; import 'package:syncrow_web/services/api/http_service.dart';
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart'; import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
import 'package:syncrow_web/web_layout/web_scaffold.dart'; import 'package:syncrow_web/web_layout/web_scaffold.dart';
@ -19,7 +18,6 @@ class SpaceManagementPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [
BlocProvider(create: (context) => SpaceDetailsModelBloc()),
BlocProvider( BlocProvider(
create: (context) => CommunitiesBloc( create: (context) => CommunitiesBloc(
communitiesService: DebouncedCommunitiesService( communitiesService: DebouncedCommunitiesService(

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart' import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart'
show SpaceDetailsModel; show SpaceDetailsModel;
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_action_buttons.dart'; import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_action_buttons.dart';
@ -6,6 +7,7 @@ import 'package:syncrow_web/pages/space_management_v2/modules/space_details/pres
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_icon_picker.dart'; import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_icon_picker.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_name_text_field.dart'; import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_name_text_field.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_sub_spaces_box.dart'; import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_sub_spaces_box.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/presentation/bloc/space_details_model_bloc/space_details_model_bloc.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart';
@ -23,56 +25,59 @@ class SpaceDetailsDialog extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AlertDialog( return BlocProvider(
title: title, create: (context) => SpaceDetailsModelBloc(initialState: space),
backgroundColor: ColorsManager.whiteColors, child: Builder(builder: (context) {
content: SizedBox( final space = context.watch<SpaceDetailsModelBloc>().state;
height: context.screenHeight * 0.25, return AlertDialog(
child: Row( title: title,
spacing: 20, backgroundColor: ColorsManager.whiteColors,
crossAxisAlignment: CrossAxisAlignment.start, content: SizedBox(
children: [ height: context.screenHeight * 0.25,
Expanded( child: Row(
flex: 1, spacing: 20,
child: SpaceIconPicker( crossAxisAlignment: CrossAxisAlignment.start,
iconPath: space.icon, children: [
), Expanded(
flex: 1,
child: SpaceIconPicker(iconPath: space.icon)
),
Expanded(
flex: 2,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SpaceNameTextField(
initialValue: space.spaceName,
isNameFieldExist: (value) {
final subspaces = space.subspaces;
if (subspaces.isEmpty) return false;
return subspaces.any(
(subspace) => subspace.name == value,
);
},
),
const Spacer(),
SpaceSubSpacesBox(
subspaces: space.subspaces,
),
const SizedBox(height: 16),
SpaceDetailsDevicesBox(space: space),
],
),
),
],
), ),
Expanded( ),
flex: 2, actions: [
child: Column( SpaceDetailsActionButtons(
mainAxisSize: MainAxisSize.min, onSave: () => onSave(space),
crossAxisAlignment: CrossAxisAlignment.start, onCancel: Navigator.of(context).pop,
children: [
// Text(context.watch<SpaceDetailsModelBloc>().state.toString()),
SpaceNameTextField(
initialValue: space.spaceName,
isNameFieldExist: (value) {
final subspaces = space.subspaces;
if (subspaces.isEmpty) return false;
return subspaces.any(
(subspace) => subspace.name == value,
);
},
),
const Spacer(),
SpaceSubSpacesBox(
subspaces: space.subspaces,
),
const SizedBox(height: 16),
SpaceDetailsDevicesBox(space: space),
],
),
), ),
], ],
), );
), }),
actions: [
SpaceDetailsActionButtons(
onSave: () => onSave(space),
onCancel: Navigator.of(context).pop,
),
],
); );
} }
} }

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_icon_selection_dialog.dart'; import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_icon_selection_dialog.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/update_space/presentation/bloc/space_details_model_bloc/space_details_model_bloc.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart';
@ -39,10 +41,22 @@ class SpaceIconPicker extends StatelessWidget {
top: 20, top: 20,
right: 20, right: 20,
child: InkWell( child: InkWell(
onTap: () => showDialog<void>( onTap: () {
context: context, showDialog<String?>(
builder: (context) => const SpaceIconSelectionDialog(), context: context,
), builder: (context) => SpaceIconSelectionDialog(
selectedIcon: iconPath,
),
).then((value) {
if (value != null) {
if (context.mounted) {
context.read<SpaceDetailsModelBloc>().add(
UpdateSpaceDetailsIcon(value),
);
}
}
});
},
child: Container( child: Container(
width: 24, width: 24,
height: 24, height: 24,

View File

@ -5,7 +5,8 @@ import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart';
class SpaceIconSelectionDialog extends StatelessWidget { class SpaceIconSelectionDialog extends StatelessWidget {
const SpaceIconSelectionDialog({super.key}); const SpaceIconSelectionDialog({super.key, required this.selectedIcon});
final String selectedIcon;
static const List<String> _icons = [ static const List<String> _icons = [
Assets.location, Assets.location,
@ -47,14 +48,26 @@ class SpaceIconSelectionDialog extends StatelessWidget {
mainAxisSpacing: 16, mainAxisSpacing: 16,
), ),
itemCount: _icons.length, itemCount: _icons.length,
itemBuilder: (context, index) => IconButton( itemBuilder: (context, index) {
onPressed: Navigator.of(context).pop, final isSelected = selectedIcon == _icons[index];
icon: SvgPicture.asset( return Container(
_icons[index], padding: const EdgeInsetsDirectional.all(2),
width: context.screenWidth * 0.03, decoration: BoxDecoration(
height: context.screenHeight * 0.08, shape: BoxShape.circle,
), border: isSelected
), ? Border.all(color: ColorsManager.vividBlue, width: 2)
: null,
),
child: IconButton(
onPressed: () => Navigator.of(context).pop(_icons[index]),
icon: SvgPicture.asset(
_icons[index],
width: context.screenWidth * 0.03,
height: context.screenHeight * 0.08,
),
),
);
},
), ),
), ),
); );

View File

@ -30,7 +30,6 @@ class SpaceSubSpacesBox extends StatelessWidget {
child: const ButtonContentWidget( child: const ButtonContentWidget(
svgAssets: Assets.addIcon, svgAssets: Assets.addIcon,
label: 'Create Sub Spaces', label: 'Create Sub Spaces',
// disabled: widget.isTagsAndSubspaceModelDisabled,
disabled: false, disabled: false,
), ),
) )
@ -55,7 +54,10 @@ class SpaceSubSpacesBox extends StatelessWidget {
(e) => SubspaceNameDisplayWidget(subSpace: e), (e) => SubspaceNameDisplayWidget(subSpace: e),
), ),
EditChip( EditChip(
onTap: () {}, onTap: () => showDialog<void>(
context: context,
builder: (_) => const SpaceSubSpacesDialog(subspaces: []),
),
), ),
], ],
), ),

View File

@ -5,7 +5,9 @@ import 'package:syncrow_web/pages/space_management_v2/modules/space_details/doma
part 'space_details_model_event.dart'; part 'space_details_model_event.dart';
class SpaceDetailsModelBloc extends Bloc<SpaceDetailsModelEvent, SpaceDetailsModel> { class SpaceDetailsModelBloc extends Bloc<SpaceDetailsModelEvent, SpaceDetailsModel> {
SpaceDetailsModelBloc() : super(SpaceDetailsModel.empty()) { SpaceDetailsModelBloc({
required SpaceDetailsModel initialState,
}) : super(initialState) {
on<UpdateSpaceDetailsIcon>(_onUpdateSpaceDetailsIcon); on<UpdateSpaceDetailsIcon>(_onUpdateSpaceDetailsIcon);
on<UpdateSpaceDetailsName>(_onUpdateSpaceDetailsName); on<UpdateSpaceDetailsName>(_onUpdateSpaceDetailsName);
on<UpdateSpaceDetailsSubspaces>(_onUpdateSpaceDetailsSubspaces); on<UpdateSpaceDetailsSubspaces>(_onUpdateSpaceDetailsSubspaces);