mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-08-25 14:29:41 +00:00
Compare commits
7 Commits
0f9cbd22a2
...
9a4fdb2f88
Author | SHA1 | Date | |
---|---|---|---|
9a4fdb2f88 | |||
1558806cc3 | |||
a4391aa73e | |||
2d69e3c72f | |||
cd8ffc99ea | |||
83895d3dda | |||
f1cf8d88d3 |
@ -68,4 +68,20 @@ abstract final class SpacesRecursiveHelper {
|
|||||||
return space;
|
return space;
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SpaceModel? findParent(
|
||||||
|
List<SpaceModel> spaces,
|
||||||
|
String targetUuid,
|
||||||
|
) {
|
||||||
|
for (final space in spaces) {
|
||||||
|
if (space.children.any((child) => child.uuid == targetUuid)) {
|
||||||
|
return space;
|
||||||
|
}
|
||||||
|
final parent = findParent(space.children, targetUuid);
|
||||||
|
if (parent != null) {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,8 +49,8 @@ class CommunityStructureHeaderActionButtonsComposer extends StatelessWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
builder: (_) => DuplicateSpaceDialog(
|
builder: (_) => DuplicateSpaceDialog(
|
||||||
initialName: space.spaceName,
|
initialName: space.spaceName,
|
||||||
selectedSpaceUuid: space.uuid,
|
selectedSpace: space,
|
||||||
selectedCommunityUuid: selectedCommunity.uuid,
|
selectedCommunity: selectedCommunity,
|
||||||
onSuccess: (spaces) {
|
onSuccess: (spaces) {
|
||||||
final updatedCommunity = selectedCommunity.copyWith(
|
final updatedCommunity = selectedCommunity.copyWith(
|
||||||
spaces: spaces,
|
spaces: spaces,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
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/common/widgets/app_loading_indicator.dart';
|
import 'package:syncrow_web/common/widgets/app_loading_indicator.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_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/communities/domain/models/space_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/duplicate_space/data/services/remote_duplicate_space_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/duplicate_space/data/services/remote_duplicate_space_service.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/duplicate_space/presentation/bloc/duplicate_space_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/duplicate_space/presentation/bloc/duplicate_space_bloc.dart';
|
||||||
@ -12,15 +13,15 @@ class DuplicateSpaceDialog extends StatelessWidget {
|
|||||||
const DuplicateSpaceDialog({
|
const DuplicateSpaceDialog({
|
||||||
required this.initialName,
|
required this.initialName,
|
||||||
required this.onSuccess,
|
required this.onSuccess,
|
||||||
required this.selectedSpaceUuid,
|
required this.selectedSpace,
|
||||||
required this.selectedCommunityUuid,
|
required this.selectedCommunity,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String initialName;
|
final String initialName;
|
||||||
final void Function(List<SpaceModel> spaces) onSuccess;
|
final void Function(List<SpaceModel> spaces) onSuccess;
|
||||||
final String selectedSpaceUuid;
|
final SpaceModel selectedSpace;
|
||||||
final String selectedCommunityUuid;
|
final CommunityModel selectedCommunity;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -31,9 +32,10 @@ class DuplicateSpaceDialog extends StatelessWidget {
|
|||||||
child: BlocListener<DuplicateSpaceBloc, DuplicateSpaceState>(
|
child: BlocListener<DuplicateSpaceBloc, DuplicateSpaceState>(
|
||||||
listener: _listener,
|
listener: _listener,
|
||||||
child: DuplicateSpaceDialogForm(
|
child: DuplicateSpaceDialogForm(
|
||||||
initialName: initialName,
|
initialName: _getInitialName(),
|
||||||
selectedSpaceUuid: selectedSpaceUuid,
|
selectedSpaceUuid: selectedSpace.uuid,
|
||||||
selectedCommunityUuid: selectedCommunityUuid,
|
selectedCommunityUuid: selectedCommunity.uuid,
|
||||||
|
siblingNames: _getSiblingNames(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -66,4 +68,69 @@ class DuplicateSpaceDialog extends StatelessWidget {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<SpaceModel> _findSiblings(
|
||||||
|
List<SpaceModel> spaces,
|
||||||
|
String targetUuid,
|
||||||
|
) {
|
||||||
|
final parent = _findParent(spaces, targetUuid);
|
||||||
|
|
||||||
|
if (parent != null) {
|
||||||
|
return parent.children.where((s) => s.uuid != targetUuid).toList();
|
||||||
|
} else {
|
||||||
|
if (spaces.any((s) => s.uuid == targetUuid)) {
|
||||||
|
return spaces.where((s) => s.uuid != targetUuid).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
SpaceModel? _findParent(List<SpaceModel> allSpaces, String childUuid) {
|
||||||
|
for (final space in allSpaces) {
|
||||||
|
if (space.children.any((child) => child.uuid == childUuid)) {
|
||||||
|
return space;
|
||||||
|
}
|
||||||
|
final parent = _findParent(space.children, childUuid);
|
||||||
|
if (parent != null) {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> _getSiblingNames() {
|
||||||
|
final siblings = _findSiblings(selectedCommunity.spaces, selectedSpace.uuid);
|
||||||
|
final names = siblings.map((s) => s.spaceName).toList();
|
||||||
|
names.add(initialName);
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
String _getInitialName() {
|
||||||
|
final allRelevantNames = _getSiblingNames();
|
||||||
|
final nameRegex = RegExp(r'^(.*?) ?\((\d+)\)$');
|
||||||
|
|
||||||
|
final baseNameMatch = nameRegex.firstMatch(initialName);
|
||||||
|
final baseName = baseNameMatch?.group(1)?.trim() ?? initialName;
|
||||||
|
|
||||||
|
var maxSuffix = 0;
|
||||||
|
|
||||||
|
for (final name in allRelevantNames) {
|
||||||
|
if (name == baseName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final match = nameRegex.firstMatch(name);
|
||||||
|
if (match != null) {
|
||||||
|
final currentBaseName = match.group(1)!.trim();
|
||||||
|
if (currentBaseName == baseName) {
|
||||||
|
final suffix = int.parse(match.group(2)!);
|
||||||
|
if (suffix > maxSuffix) {
|
||||||
|
maxSuffix = suffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '$baseName(${maxSuffix + 1})';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,22 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/space_management_v2/modules/duplicate_space/domain/params/duplicate_space_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/duplicate_space/domain/params/duplicate_space_param.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/duplicate_space/presentation/bloc/duplicate_space_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/duplicate_space/presentation/bloc/duplicate_space_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/duplicate_space/presentation/widgets/duplicate_space_text_field.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/duplicate_space/presentation/widgets/duplicate_space_text_field.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_action_buttons.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class DuplicateSpaceDialogForm extends StatefulWidget {
|
class DuplicateSpaceDialogForm extends StatefulWidget {
|
||||||
const DuplicateSpaceDialogForm({
|
const DuplicateSpaceDialogForm({
|
||||||
required this.initialName,
|
required this.initialName,
|
||||||
required this.selectedSpaceUuid,
|
required this.selectedSpaceUuid,
|
||||||
required this.selectedCommunityUuid,
|
required this.selectedCommunityUuid,
|
||||||
|
required this.siblingNames,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String initialName;
|
final String initialName;
|
||||||
final String selectedSpaceUuid;
|
final String selectedSpaceUuid;
|
||||||
final String selectedCommunityUuid;
|
final String selectedCommunityUuid;
|
||||||
|
final List<String> siblingNames;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DuplicateSpaceDialogForm> createState() => _DuplicateSpaceDialogFormState();
|
State<DuplicateSpaceDialogForm> createState() => _DuplicateSpaceDialogFormState();
|
||||||
@ -22,18 +26,33 @@ class DuplicateSpaceDialogForm extends StatefulWidget {
|
|||||||
|
|
||||||
class _DuplicateSpaceDialogFormState extends State<DuplicateSpaceDialogForm> {
|
class _DuplicateSpaceDialogFormState extends State<DuplicateSpaceDialogForm> {
|
||||||
late final TextEditingController _nameController;
|
late final TextEditingController _nameController;
|
||||||
bool _isNameValid = true;
|
String? _errorText;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_nameController = TextEditingController(text: '${widget.initialName}(1)');
|
_nameController = TextEditingController(
|
||||||
|
text: widget.initialName,
|
||||||
|
);
|
||||||
_nameController.addListener(_validateName);
|
_nameController.addListener(_validateName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _validateName() => setState(
|
void _validateName() {
|
||||||
() => _isNameValid = _nameController.text.trim() != widget.initialName,
|
final name = _nameController.text.trim();
|
||||||
);
|
if (name.isEmpty) {
|
||||||
|
setState(() {
|
||||||
|
_errorText = 'Name cannot be empty';
|
||||||
|
});
|
||||||
|
} else if (widget.siblingNames.contains(name)) {
|
||||||
|
setState(() {
|
||||||
|
_errorText = 'Name must be unique';
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
_errorText = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
@ -44,27 +63,32 @@ class _DuplicateSpaceDialogFormState extends State<DuplicateSpaceDialogForm> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: const SelectableText('Duplicate Space'),
|
title: const SelectableText(
|
||||||
|
'Duplicate Space',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 30,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
content: Column(
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
spacing: 16,
|
spacing: 16,
|
||||||
children: [
|
children: [
|
||||||
const SelectableText('Enter a new name for the duplicated space:'),
|
const SelectableText('Enter a new name for the duplicated space:'),
|
||||||
DuplicateSpaceTextField(
|
DuplicateSpaceTextField(
|
||||||
nameController: _nameController,
|
nameController: _nameController,
|
||||||
isNameValid: _isNameValid,
|
errorText: _errorText,
|
||||||
initialName: widget.initialName,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
SpaceDetailsActionButtons(
|
||||||
onPressed: Navigator.of(context).pop,
|
spacerFlex: 2,
|
||||||
child: const Text('Cancel'),
|
onSave: _errorText == null ? () => _submit(context) : null,
|
||||||
),
|
onCancel: Navigator.of(context).pop,
|
||||||
TextButton(
|
saveButtonLabel: 'Duplicate',
|
||||||
onPressed: _isNameValid ? () => _submit(context) : null,
|
|
||||||
child: const Text('Duplicate'),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -5,16 +5,12 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|||||||
class DuplicateSpaceTextField extends StatelessWidget {
|
class DuplicateSpaceTextField extends StatelessWidget {
|
||||||
const DuplicateSpaceTextField({
|
const DuplicateSpaceTextField({
|
||||||
required this.nameController,
|
required this.nameController,
|
||||||
required this.isNameValid,
|
required this.errorText,
|
||||||
required this.initialName,
|
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
final TextEditingController nameController;
|
final TextEditingController nameController;
|
||||||
final bool isNameValid;
|
final String? errorText;
|
||||||
final String initialName;
|
|
||||||
|
|
||||||
String get _errorText => 'Name must be different from "$initialName"';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -24,9 +20,10 @@ class DuplicateSpaceTextField extends StatelessWidget {
|
|||||||
color: ColorsManager.blackColor,
|
color: ColorsManager.blackColor,
|
||||||
),
|
),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
label: const Text('Space Name'),
|
filled: true,
|
||||||
border: _border(),
|
fillColor: ColorsManager.boxColor,
|
||||||
enabledBorder: _border(),
|
border: _border(ColorsManager.transparentColor),
|
||||||
|
enabledBorder: _border(ColorsManager.transparentColor),
|
||||||
focusedBorder: _border(ColorsManager.primaryColor),
|
focusedBorder: _border(ColorsManager.primaryColor),
|
||||||
errorBorder: _border(context.theme.colorScheme.error),
|
errorBorder: _border(context.theme.colorScheme.error),
|
||||||
focusedErrorBorder: _border(context.theme.colorScheme.error),
|
focusedErrorBorder: _border(context.theme.colorScheme.error),
|
||||||
@ -34,14 +31,14 @@ class DuplicateSpaceTextField extends StatelessWidget {
|
|||||||
color: context.theme.colorScheme.error,
|
color: context.theme.colorScheme.error,
|
||||||
fontSize: 8,
|
fontSize: 8,
|
||||||
),
|
),
|
||||||
errorText: isNameValid ? null : _errorText,
|
errorText: errorText,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
OutlineInputBorder _border([Color? color]) {
|
OutlineInputBorder _border([Color? color]) {
|
||||||
return OutlineInputBorder(
|
return OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: color ?? ColorsManager.blackColor,
|
color: color ?? ColorsManager.blackColor,
|
||||||
width: 0.5,
|
width: 0.5,
|
||||||
|
@ -10,7 +10,7 @@ import 'package:syncrow_web/pages/space_management_v2/modules/update_space/prese
|
|||||||
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';
|
||||||
|
|
||||||
class SpaceDetailsForm extends StatelessWidget {
|
class SpaceDetailsForm extends StatefulWidget {
|
||||||
const SpaceDetailsForm({
|
const SpaceDetailsForm({
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.space,
|
required this.space,
|
||||||
@ -22,24 +22,52 @@ class SpaceDetailsForm extends StatelessWidget {
|
|||||||
final SpaceDetailsModel space;
|
final SpaceDetailsModel space;
|
||||||
final void Function(SpaceDetailsModel space) onSave;
|
final void Function(SpaceDetailsModel space) onSave;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SpaceDetailsForm> createState() => _SpaceDetailsFormState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SpaceDetailsFormState extends State<SpaceDetailsForm> {
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
bool _isFormValid = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
final initialName = widget.space.spaceName;
|
||||||
|
_isFormValid = initialName.isNotEmpty &&
|
||||||
|
initialName.length <= 50 &&
|
||||||
|
!widget.space.subspaces.any((subspace) => subspace.name == initialName);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => SpaceDetailsModelBloc(initialState: space),
|
create: (context) => SpaceDetailsModelBloc(initialState: widget.space),
|
||||||
child: BlocBuilder<SpaceDetailsModelBloc, SpaceDetailsModel>(
|
child: BlocBuilder<SpaceDetailsModelBloc, SpaceDetailsModel>(
|
||||||
buildWhen: (previous, current) => previous != current,
|
buildWhen: (previous, current) => previous != current,
|
||||||
builder: (context, space) {
|
builder: (context, space) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: DefaultTextStyle(
|
title: DefaultTextStyle(
|
||||||
style: context.textTheme.titleLarge!.copyWith(
|
style: context.textTheme.titleLarge!.copyWith(
|
||||||
fontSize: 30,
|
fontSize: 30,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color: ColorsManager.blackColor,
|
color: ColorsManager.blackColor,
|
||||||
),
|
|
||||||
child: title,
|
|
||||||
),
|
),
|
||||||
backgroundColor: ColorsManager.white,
|
child: widget.title,
|
||||||
content: SizedBox(
|
),
|
||||||
|
backgroundColor: ColorsManager.white,
|
||||||
|
content: Form(
|
||||||
|
key: _formKey,
|
||||||
|
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||||
|
onChanged: () {
|
||||||
|
final isValid = _formKey.currentState?.validate() ?? false;
|
||||||
|
if (_isFormValid != isValid) {
|
||||||
|
setState(() {
|
||||||
|
_isFormValid = isValid;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: SizedBox(
|
||||||
height: context.screenHeight * 0.3,
|
height: context.screenHeight * 0.3,
|
||||||
width: context.screenWidth * 0.4,
|
width: context.screenWidth * 0.4,
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -70,14 +98,16 @@ class SpaceDetailsForm extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
),
|
||||||
SpaceDetailsActionButtons(
|
actions: [
|
||||||
onSave: () => onSave(space),
|
SpaceDetailsActionButtons(
|
||||||
onCancel: Navigator.of(context).pop,
|
onSave: _isFormValid ? () => widget.onSave(space) : null,
|
||||||
),
|
onCancel: Navigator.of(context).pop,
|
||||||
],
|
),
|
||||||
);
|
],
|
||||||
}),
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,13 @@ class _SpaceNameTextFieldState extends State<SpaceNameTextField> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
|
||||||
|
|
||||||
String? _validateName(String? value) {
|
String? _validateName(String? value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return '*Space name should not be empty.';
|
return '*Space name should not be empty.';
|
||||||
}
|
}
|
||||||
|
if (value.length > 50) {
|
||||||
|
return '*Space name cannot be longer than 50 characters.';
|
||||||
|
}
|
||||||
if (widget.isNameFieldExist(value)) {
|
if (widget.isNameFieldExist(value)) {
|
||||||
return '*Name already exists';
|
return '*Name already exists';
|
||||||
}
|
}
|
||||||
@ -47,30 +48,26 @@ class _SpaceNameTextFieldState extends State<SpaceNameTextField> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Form(
|
return TextFormField(
|
||||||
key: _formKey,
|
controller: _controller,
|
||||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
onChanged: (value) => context.read<SpaceDetailsModelBloc>().add(
|
||||||
child: TextFormField(
|
UpdateSpaceDetailsName(value),
|
||||||
controller: _controller,
|
|
||||||
onChanged: (value) => context.read<SpaceDetailsModelBloc>().add(
|
|
||||||
UpdateSpaceDetailsName(value),
|
|
||||||
),
|
|
||||||
validator: _validateName,
|
|
||||||
style: context.textTheme.bodyMedium,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Please enter the name',
|
|
||||||
hintStyle: context.textTheme.bodyMedium!.copyWith(
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
),
|
|
||||||
filled: true,
|
|
||||||
fillColor: ColorsManager.boxColor,
|
|
||||||
enabledBorder: _buildBorder(context, ColorsManager.vividBlue),
|
|
||||||
focusedBorder: _buildBorder(context, ColorsManager.primaryColor),
|
|
||||||
errorBorder: _buildBorder(context, context.theme.colorScheme.error),
|
|
||||||
focusedErrorBorder: _buildBorder(context, context.theme.colorScheme.error),
|
|
||||||
errorStyle: context.textTheme.bodySmall?.copyWith(
|
|
||||||
color: context.theme.colorScheme.error,
|
|
||||||
),
|
),
|
||||||
|
validator: _validateName,
|
||||||
|
style: context.textTheme.bodyMedium,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Please enter the name',
|
||||||
|
hintStyle: context.textTheme.bodyMedium!.copyWith(
|
||||||
|
color: ColorsManager.lightGrayColor,
|
||||||
|
),
|
||||||
|
filled: true,
|
||||||
|
fillColor: ColorsManager.boxColor,
|
||||||
|
enabledBorder: _buildBorder(context, ColorsManager.vividBlue),
|
||||||
|
focusedBorder: _buildBorder(context, ColorsManager.primaryColor),
|
||||||
|
errorBorder: _buildBorder(context, context.theme.colorScheme.error),
|
||||||
|
focusedErrorBorder: _buildBorder(context, context.theme.colorScheme.error),
|
||||||
|
errorStyle: context.textTheme.bodySmall?.copyWith(
|
||||||
|
color: context.theme.colorScheme.error,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -89,28 +89,35 @@ class _SpaceSubSpacesDialogState extends State<SpaceSubSpacesDialog> {
|
|||||||
),
|
),
|
||||||
child: const SelectableText('Create Sub-Space'),
|
child: const SelectableText('Create Sub-Space'),
|
||||||
),
|
),
|
||||||
content: Column(
|
content: ConstrainedBox(
|
||||||
spacing: 12,
|
constraints: BoxConstraints(
|
||||||
mainAxisSize: MainAxisSize.min,
|
maxHeight: context.screenHeight * 0.4,
|
||||||
children: [
|
),
|
||||||
SubSpacesInput(
|
child: SingleChildScrollView(
|
||||||
subSpaces: _subspaces,
|
child: Column(
|
||||||
onSubspaceAdded: _handleSubspaceAdded,
|
spacing: 12,
|
||||||
onSubspaceDeleted: _handleSubspaceDeleted,
|
mainAxisSize: MainAxisSize.min,
|
||||||
controller: _subspaceNameController,
|
children: [
|
||||||
),
|
SubSpacesInput(
|
||||||
AnimatedSwitcher(
|
subSpaces: _subspaces,
|
||||||
duration: const Duration(milliseconds: 100),
|
onSubspaceAdded: _handleSubspaceAdded,
|
||||||
child: Visibility(
|
onSubspaceDeleted: _handleSubspaceDeleted,
|
||||||
key: ValueKey(_hasDuplicateNames),
|
controller: _subspaceNameController,
|
||||||
visible: _hasDuplicateNames,
|
|
||||||
child: const SelectableText(
|
|
||||||
'Error: Duplicate subspace names are not allowed.',
|
|
||||||
style: TextStyle(color: Colors.red),
|
|
||||||
),
|
),
|
||||||
),
|
AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 100),
|
||||||
|
child: Visibility(
|
||||||
|
key: ValueKey(_hasDuplicateNames),
|
||||||
|
visible: _hasDuplicateNames,
|
||||||
|
child: const SelectableText(
|
||||||
|
'Error: Duplicate subspace names are not allowed.',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
SpaceDetailsActionButtons(
|
SpaceDetailsActionButtons(
|
||||||
|
@ -182,15 +182,20 @@ class _AssignTagsDialogState extends State<AssignTagsDialog> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
ConstrainedBox(
|
||||||
width: double.infinity,
|
constraints: BoxConstraints(
|
||||||
child: AssignTagsTable(
|
minWidth: double.infinity,
|
||||||
productAllocations: allProductAllocations,
|
maxHeight: context.screenHeight * 0.6,
|
||||||
subspaces: _space.subspaces,
|
),
|
||||||
productLocations: productLocations,
|
child: SingleChildScrollView(
|
||||||
onTagSelected: _handleTagChange,
|
child: AssignTagsTable(
|
||||||
onLocationSelected: _handleLocationChange,
|
productAllocations: allProductAllocations,
|
||||||
onProductDeleted: _handleProductDelete,
|
subspaces: _space.subspaces,
|
||||||
|
productLocations: productLocations,
|
||||||
|
onTagSelected: _handleTagChange,
|
||||||
|
onLocationSelected: _handleLocationChange,
|
||||||
|
onProductDeleted: _handleProductDelete,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (hasErrors)
|
if (hasErrors)
|
||||||
|
Reference in New Issue
Block a user