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