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/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/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/utils/theme/responsive_text_theme.dart';
import 'package:syncrow_web/web_layout/web_scaffold.dart';
@ -19,7 +18,6 @@ class SpaceManagementPage extends StatelessWidget {
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(create: (context) => SpaceDetailsModelBloc()),
BlocProvider(
create: (context) => CommunitiesBloc(
communitiesService: DebouncedCommunitiesService(

View File

@ -1,4 +1,5 @@
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'
show SpaceDetailsModel;
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_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/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/extension/build_context_x.dart';
@ -23,56 +25,59 @@ class SpaceDetailsDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AlertDialog(
title: title,
backgroundColor: ColorsManager.whiteColors,
content: SizedBox(
height: context.screenHeight * 0.25,
child: Row(
spacing: 20,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 1,
child: SpaceIconPicker(
iconPath: space.icon,
),
return BlocProvider(
create: (context) => SpaceDetailsModelBloc(initialState: space),
child: Builder(builder: (context) {
final space = context.watch<SpaceDetailsModelBloc>().state;
return AlertDialog(
title: title,
backgroundColor: ColorsManager.whiteColors,
content: SizedBox(
height: context.screenHeight * 0.25,
child: Row(
spacing: 20,
crossAxisAlignment: CrossAxisAlignment.start,
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,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
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,
),
],
),
),
actions: [
SpaceDetailsActionButtons(
onSave: () => onSave(space),
onCancel: Navigator.of(context).pop,
),
],
);
}),
);
}
}

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.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/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/constants/assets.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
@ -39,10 +41,22 @@ class SpaceIconPicker extends StatelessWidget {
top: 20,
right: 20,
child: InkWell(
onTap: () => showDialog<void>(
context: context,
builder: (context) => const SpaceIconSelectionDialog(),
),
onTap: () {
showDialog<String?>(
context: context,
builder: (context) => SpaceIconSelectionDialog(
selectedIcon: iconPath,
),
).then((value) {
if (value != null) {
if (context.mounted) {
context.read<SpaceDetailsModelBloc>().add(
UpdateSpaceDetailsIcon(value),
);
}
}
});
},
child: Container(
width: 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';
class SpaceIconSelectionDialog extends StatelessWidget {
const SpaceIconSelectionDialog({super.key});
const SpaceIconSelectionDialog({super.key, required this.selectedIcon});
final String selectedIcon;
static const List<String> _icons = [
Assets.location,
@ -47,14 +48,26 @@ class SpaceIconSelectionDialog extends StatelessWidget {
mainAxisSpacing: 16,
),
itemCount: _icons.length,
itemBuilder: (context, index) => IconButton(
onPressed: Navigator.of(context).pop,
icon: SvgPicture.asset(
_icons[index],
width: context.screenWidth * 0.03,
height: context.screenHeight * 0.08,
),
),
itemBuilder: (context, index) {
final isSelected = selectedIcon == _icons[index];
return Container(
padding: const EdgeInsetsDirectional.all(2),
decoration: BoxDecoration(
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(
svgAssets: Assets.addIcon,
label: 'Create Sub Spaces',
// disabled: widget.isTagsAndSubspaceModelDisabled,
disabled: false,
),
)
@ -55,7 +54,10 @@ class SpaceSubSpacesBox extends StatelessWidget {
(e) => SubspaceNameDisplayWidget(subSpace: e),
),
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';
class SpaceDetailsModelBloc extends Bloc<SpaceDetailsModelEvent, SpaceDetailsModel> {
SpaceDetailsModelBloc() : super(SpaceDetailsModel.empty()) {
SpaceDetailsModelBloc({
required SpaceDetailsModel initialState,
}) : super(initialState) {
on<UpdateSpaceDetailsIcon>(_onUpdateSpaceDetailsIcon);
on<UpdateSpaceDetailsName>(_onUpdateSpaceDetailsName);
on<UpdateSpaceDetailsSubspaces>(_onUpdateSpaceDetailsSubspaces);