mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 22:57:21 +00:00
Add factory method empty
to SpaceModel
for default instance creation. Refactor SpaceDetailsDialog and related widgets to utilize SpaceModel, enhancing parameter handling and state management in space creation and editing flows.
This commit is contained in:
@ -19,6 +19,16 @@ class SpaceModel extends Equatable {
|
||||
required this.parent,
|
||||
});
|
||||
|
||||
factory SpaceModel.empty() => const SpaceModel(
|
||||
uuid: '',
|
||||
createdAt: null,
|
||||
updatedAt: null,
|
||||
spaceName: '',
|
||||
icon: '',
|
||||
children: [],
|
||||
parent: null,
|
||||
);
|
||||
|
||||
factory SpaceModel.fromJson(Map<String, dynamic> json) {
|
||||
return SpaceModel(
|
||||
uuid: json['uuid'] as String? ?? '',
|
||||
|
@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.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/presentation/widgets/space_details_dialog.dart';
|
||||
|
||||
abstract final class SpaceDetailsDialogHelper {
|
||||
@ -9,8 +8,8 @@ abstract final class SpaceDetailsDialogHelper {
|
||||
context: context,
|
||||
builder: (_) => SpaceDetailsDialog(
|
||||
title: const Text('Create Space'),
|
||||
space: SpaceDetailsModel.empty(),
|
||||
onSave: (space) {},
|
||||
spaceModel: SpaceModel.empty(),
|
||||
onSave: (space) => print(space),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -23,13 +22,7 @@ abstract final class SpaceDetailsDialogHelper {
|
||||
context: context,
|
||||
builder: (_) => SpaceDetailsDialog(
|
||||
title: const Text('Edit Space'),
|
||||
space: SpaceDetailsModel(
|
||||
uuid: spaceModel.uuid,
|
||||
spaceName: spaceModel.spaceName,
|
||||
icon: spaceModel.icon,
|
||||
productAllocations: const [],
|
||||
subspaces: const [],
|
||||
),
|
||||
spaceModel: spaceModel,
|
||||
onSave: (space) {},
|
||||
),
|
||||
);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.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/params/load_space_details_param.dart';
|
||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/bloc/space_details_bloc.dart';
|
||||
@ -10,13 +11,13 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
class SpaceDetailsDialog extends StatefulWidget {
|
||||
const SpaceDetailsDialog({
|
||||
required this.title,
|
||||
required this.space,
|
||||
required this.spaceModel,
|
||||
required this.onSave,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Widget title;
|
||||
final SpaceDetailsModel space;
|
||||
final SpaceModel spaceModel;
|
||||
final void Function(SpaceDetailsModel space) onSave;
|
||||
|
||||
@override
|
||||
@ -26,10 +27,10 @@ class SpaceDetailsDialog extends StatefulWidget {
|
||||
class _SpaceDetailsDialogState extends State<SpaceDetailsDialog> {
|
||||
@override
|
||||
void initState() {
|
||||
final isCreateMode = widget.space.uuid.isEmpty;
|
||||
final isCreateMode = widget.spaceModel.uuid.isEmpty;
|
||||
|
||||
if (!isCreateMode) {
|
||||
final param = LoadSpaceDetailsParam(spaceUuid: widget.space.uuid);
|
||||
final param = LoadSpaceDetailsParam(spaceUuid: widget.spaceModel.uuid);
|
||||
context.read<SpaceDetailsBloc>().add(LoadSpaceDetails(param));
|
||||
}
|
||||
super.initState();
|
||||
@ -37,11 +38,11 @@ class _SpaceDetailsDialogState extends State<SpaceDetailsDialog> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isCreateMode = widget.space.uuid.isEmpty;
|
||||
final isCreateMode = widget.spaceModel.uuid.isEmpty;
|
||||
if (isCreateMode) {
|
||||
return SpaceDetailsForm(
|
||||
title: widget.title,
|
||||
space: widget.space,
|
||||
space: SpaceDetailsModel.empty(),
|
||||
onSave: widget.onSave,
|
||||
);
|
||||
}
|
||||
|
@ -26,51 +26,51 @@ class SpaceDetailsForm extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => SpaceDetailsModelBloc(initialState: space),
|
||||
child: AlertDialog(
|
||||
title: title,
|
||||
backgroundColor: ColorsManager.whiteColors,
|
||||
content: SizedBox(
|
||||
height: context.screenHeight * 0.25,
|
||||
child: Row(
|
||||
spacing: 20,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(child: SpaceIconPicker(iconPath: space.icon)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
child: BlocBuilder<SpaceDetailsModelBloc, SpaceDetailsModel>(
|
||||
buildWhen: (previous, current) => previous != current,
|
||||
builder: (context, state) {
|
||||
return AlertDialog(
|
||||
title: title,
|
||||
backgroundColor: ColorsManager.whiteColors,
|
||||
content: SizedBox(
|
||||
height: context.screenHeight * 0.3,
|
||||
child: Row(
|
||||
spacing: 20,
|
||||
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,
|
||||
);
|
||||
},
|
||||
Expanded(child: SpaceIconPicker(iconPath: state.icon)),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SpaceNameTextField(
|
||||
initialValue: state.spaceName,
|
||||
isNameFieldExist: (value) => state.subspaces.any(
|
||||
(subspace) => subspace.name == value,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
SpaceSubSpacesBox(
|
||||
subspaces: state.subspaces,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SpaceDetailsDevicesBox(space: state),
|
||||
],
|
||||
),
|
||||
),
|
||||
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(state),
|
||||
onCancel: Navigator.of(context).pop,
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/common/edit_chip.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/presentation/widgets/button_content_widget.dart';
|
||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_sub_spaces_dialog.dart';
|
||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/subspace_name_display_widget.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';
|
||||
@ -23,10 +25,7 @@ class SpaceSubSpacesBox extends StatelessWidget {
|
||||
padding: EdgeInsets.zero,
|
||||
overlayColor: ColorsManager.transparentColor,
|
||||
),
|
||||
onPressed: () => showDialog<void>(
|
||||
context: context,
|
||||
builder: (_) => SpaceSubSpacesDialog(subspaces: subspaces),
|
||||
),
|
||||
onPressed: () => _showSubSpacesDialog(context),
|
||||
child: const ButtonContentWidget(
|
||||
svgAssets: Assets.addIcon,
|
||||
label: 'Create Sub Spaces',
|
||||
@ -54,10 +53,7 @@ class SpaceSubSpacesBox extends StatelessWidget {
|
||||
(e) => SubspaceNameDisplayWidget(subSpace: e),
|
||||
),
|
||||
EditChip(
|
||||
onTap: () => showDialog<void>(
|
||||
context: context,
|
||||
builder: (_) => const SpaceSubSpacesDialog(subspaces: []),
|
||||
),
|
||||
onTap: () => _showSubSpacesDialog(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -66,4 +62,19 @@ class SpaceSubSpacesBox extends StatelessWidget {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _showSubSpacesDialog(BuildContext context) {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => SpaceSubSpacesDialog(
|
||||
subspaces: subspaces,
|
||||
onSave: (subspaces) {
|
||||
context.read<SpaceDetailsModelBloc>().add(
|
||||
UpdateSpaceDetailsSubspaces(subspaces),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,12 @@ import 'package:uuid/uuid.dart';
|
||||
class SpaceSubSpacesDialog extends StatefulWidget {
|
||||
const SpaceSubSpacesDialog({
|
||||
required this.subspaces,
|
||||
required this.onSave,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final List<Subspace> subspaces;
|
||||
final void Function(List<Subspace> subspaces) onSave;
|
||||
|
||||
@override
|
||||
State<SpaceSubSpacesDialog> createState() => _SpaceSubSpacesDialogState();
|
||||
@ -46,7 +48,10 @@ class _SpaceSubSpacesDialogState extends State<SpaceSubSpacesDialog> {
|
||||
() => _subspaces = _subspaces.where((s) => s.uuid != uuid).toList(),
|
||||
);
|
||||
|
||||
void _handleSave() => Navigator.of(context).pop(_subspaces);
|
||||
void _handleSave() {
|
||||
widget.onSave(_subspaces);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -17,16 +17,19 @@ class SubspaceNameDisplayWidget extends StatefulWidget {
|
||||
|
||||
class _SubspaceNameDisplayWidgetState extends State<SubspaceNameDisplayWidget> {
|
||||
late final TextEditingController _controller;
|
||||
late final FocusNode _focusNode;
|
||||
bool isEditing = false;
|
||||
@override
|
||||
void initState() {
|
||||
_controller = TextEditingController(text: widget.subSpace.name);
|
||||
_focusNode = FocusNode();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -36,38 +39,54 @@ class _SubspaceNameDisplayWidgetState extends State<SubspaceNameDisplayWidget> {
|
||||
color: ColorsManager.spaceColor,
|
||||
);
|
||||
return InkWell(
|
||||
onTap: () => setState(() => isEditing = true),
|
||||
child: Visibility(
|
||||
visible: isEditing,
|
||||
replacement: Text(
|
||||
widget.subSpace.name,
|
||||
style: textStyle,
|
||||
onTap: () {
|
||||
setState(() => isEditing = true);
|
||||
_focusNode.requestFocus();
|
||||
},
|
||||
child: Chip(
|
||||
backgroundColor: ColorsManager.whiteColors,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: TextField(
|
||||
controller: _controller,
|
||||
style: textStyle,
|
||||
decoration: const InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsetsDirectional.symmetric(
|
||||
horizontal: 8,
|
||||
label: Visibility(
|
||||
visible: isEditing,
|
||||
replacement: Text(
|
||||
widget.subSpace.name,
|
||||
style: textStyle,
|
||||
),
|
||||
child: SizedBox(
|
||||
width: context.screenWidth * 0.065,
|
||||
height: context.screenHeight * 0.025,
|
||||
child: TextField(
|
||||
focusNode: _focusNode,
|
||||
controller: _controller,
|
||||
style: textStyle,
|
||||
decoration: const InputDecoration.collapsed(hintText: ''),
|
||||
onTapOutside: (_) => _onFinishEditing(),
|
||||
onSubmitted: (value) {
|
||||
final bloc = context.read<SpaceDetailsModelBloc>();
|
||||
bloc.add(
|
||||
UpdateSpaceDetailsSubspaces(
|
||||
bloc.state.subspaces
|
||||
.map(
|
||||
(e) => e.uuid == widget.subSpace.uuid
|
||||
? e.copyWith(name: value)
|
||||
: e,
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
_onFinishEditing();
|
||||
},
|
||||
),
|
||||
),
|
||||
onSubmitted: (value) {
|
||||
final bloc = context.read<SpaceDetailsModelBloc>();
|
||||
bloc.add(
|
||||
UpdateSpaceDetailsSubspaces(
|
||||
bloc.state.subspaces
|
||||
.map(
|
||||
(e) => e.uuid == widget.subSpace.uuid
|
||||
? e.copyWith(name: value)
|
||||
: e,
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onFinishEditing() {
|
||||
setState(() => isEditing = false);
|
||||
_focusNode.unfocus();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user