added project tags to all dialogs

This commit is contained in:
hannathkadher
2025-03-05 21:26:36 +04:00
parent 213ec329c0
commit 5cea8eddb3
7 changed files with 134 additions and 200 deletions

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart';
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';

View File

@ -6,8 +6,9 @@ import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assig
class AssignTagModelBloc
extends Bloc<AssignTagModelEvent, AssignTagModelState> {
final List<String> allTags;
final List<Tag> projectTags;
AssignTagModelBloc(this.allTags) : super(AssignTagModelInitial()) {
AssignTagModelBloc(this.allTags, this.projectTags) : super(AssignTagModelInitial()) {
on<InitializeTagModels>((event, emit) {
final initialTags = event.initialTags ?? [];

View File

@ -32,6 +32,7 @@ class AssignTagModelsDialog extends StatelessWidget {
final BuildContext? pageContext;
final List<String>? otherSpaceModels;
final List<SpaceTemplateModel>? allSpaceModels;
final List<Tag> projectTags;
const AssignTagModelsDialog(
{Key? key,
@ -46,18 +47,18 @@ class AssignTagModelsDialog extends StatelessWidget {
this.pageContext,
this.otherSpaceModels,
this.spaceModel,
this.allSpaceModels})
this.allSpaceModels,
required this.projectTags})
: super(key: key);
@override
Widget build(BuildContext context) {
final List<String> locations = (subspaces ?? [])
.map((subspace) => subspace.subspaceName)
.toList()
..add('Main Space');
print(projectTags);
final List<String> locations =
(subspaces ?? []).map((subspace) => subspace.subspaceName).toList()..add('Main Space');
return BlocProvider(
create: (_) => AssignTagModelBloc(allTags ?? [])
create: (_) => AssignTagModelBloc(allTags ?? [], projectTags)
..add(InitializeTagModels(
initialTags: initialTags,
addedProducts: addedProducts,
@ -81,8 +82,7 @@ class AssignTagModelsDialog extends StatelessWidget {
ClipRRect(
borderRadius: BorderRadius.circular(20),
child: DataTable(
headingRowColor: WidgetStateProperty.all(
ColorsManager.dataHeaderGrey),
headingRowColor: WidgetStateProperty.all(ColorsManager.dataHeaderGrey),
key: ValueKey(state.tags.length),
border: TableBorder.all(
color: ColorsManager.dataHeaderGrey,
@ -91,26 +91,17 @@ class AssignTagModelsDialog extends StatelessWidget {
),
columns: [
DataColumn(
label: Text('#',
style: Theme.of(context)
.textTheme
.bodyMedium)),
label: Text('#', style: Theme.of(context).textTheme.bodyMedium)),
DataColumn(
label: Text('Device',
style: Theme.of(context)
.textTheme
.bodyMedium)),
style: Theme.of(context).textTheme.bodyMedium)),
DataColumn(
numeric: false,
label: Text('Tag',
style: Theme.of(context)
.textTheme
.bodyMedium)),
label:
Text('Tag', style: Theme.of(context).textTheme.bodyMedium)),
DataColumn(
label: Text('Location',
style: Theme.of(context)
.textTheme
.bodyMedium)),
style: Theme.of(context).textTheme.bodyMedium)),
],
rows: state.tags.isEmpty
? [
@ -118,13 +109,10 @@ class AssignTagModelsDialog extends StatelessWidget {
DataCell(
Center(
child: Text('No Devices Available',
style: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(
color: ColorsManager
.lightGrayColor,
)),
style:
Theme.of(context).textTheme.bodyMedium?.copyWith(
color: ColorsManager.lightGrayColor,
)),
),
),
const DataCell(SizedBox()),
@ -141,8 +129,7 @@ class AssignTagModelsDialog extends StatelessWidget {
DataCell(Text((index + 1).toString())),
DataCell(
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
@ -156,31 +143,25 @@ class AssignTagModelsDialog extends StatelessWidget {
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: ColorsManager
.lightGrayColor,
color: ColorsManager.lightGrayColor,
width: 1.0,
),
),
child: IconButton(
icon: const Icon(
Icons.close,
color: ColorsManager
.lightGreyColor,
color: ColorsManager.lightGreyColor,
size: 16,
),
onPressed: () {
context
.read<
AssignTagModelBloc>()
.add(DeleteTagModel(
tagToDelete: tag,
tags: state.tags));
context.read<AssignTagModelBloc>().add(
DeleteTagModel(
tagToDelete: tag, tags: state.tags));
controllers.removeAt(index);
},
tooltip: 'Delete Tag',
padding: EdgeInsets.zero,
constraints:
const BoxConstraints(),
constraints: const BoxConstraints(),
),
),
],
@ -191,19 +172,15 @@ class AssignTagModelsDialog extends StatelessWidget {
alignment: Alignment
.centerLeft, // Align cell content to the left
child: SizedBox(
width: double
.infinity, // Ensure full width for dropdown
width:
double.infinity, // Ensure full width for dropdown
child: DialogTextfieldDropdown(
key: ValueKey(
'dropdown_${Uuid().v4()}_$index'),
key: ValueKey('dropdown_${Uuid().v4()}_$index'),
items: state.updatedTags,
initialValue: tag.tag,
onSelected: (value) {
controller.text = value;
context
.read<
AssignTagModelBloc>()
.add(UpdateTag(
context.read<AssignTagModelBloc>().add(UpdateTag(
index: index,
tag: value,
));
@ -217,12 +194,10 @@ class AssignTagModelsDialog extends StatelessWidget {
width: double.infinity,
child: DialogDropdown(
items: locations,
selectedValue: tag.location ??
'Main Space',
selectedValue: tag.location ?? 'Main Space',
onSelected: (value) {
context
.read<
AssignTagModelBloc>()
.read<AssignTagModelBloc>()
.add(UpdateLocation(
index: index,
location: value,
@ -254,17 +229,13 @@ class AssignTagModelsDialog extends StatelessWidget {
builder: (buttonContext) => CancelButton(
label: 'Add New Device',
onPressed: () async {
final updatedTags =
List<Tag>.from(state.tags);
final updatedTags = List<Tag>.from(state.tags);
final result =
TagHelper.updateSubspaceTagModels(
updatedTags, subspaces);
TagHelper.updateSubspaceTagModels(updatedTags, subspaces);
final processedTags =
result['updatedTags'] as List<Tag>;
final processedSubspaces =
List<SubspaceTemplateModel>.from(
result['subspaces'] as List<dynamic>);
final processedTags = result['updatedTags'] as List<Tag>;
final processedSubspaces = List<SubspaceTemplateModel>.from(
result['subspaces'] as List<dynamic>);
if (context.mounted) {
Navigator.of(context).pop();
@ -272,28 +243,25 @@ class AssignTagModelsDialog extends StatelessWidget {
await showDialog<bool>(
barrierDismissible: false,
context: context,
builder: (dialogContext) =>
AddDeviceTypeModelWidget(
products: products,
subspaces: processedSubspaces,
isCreate: false,
initialSelectedProducts: TagHelper
.createInitialSelectedProducts(
processedTags,
processedSubspaces),
allTags: allTags,
spaceName: spaceName,
otherSpaceModels: otherSpaceModels,
spaceTagModels: processedTags,
pageContext: pageContext,
spaceModel: SpaceTemplateModel(
modelName: spaceName,
tags: updatedTags,
uuid: spaceModel?.uuid,
internalId:
spaceModel?.internalId,
subspaceModels:
processedSubspaces)),
builder: (dialogContext) => AddDeviceTypeModelWidget(
products: products,
subspaces: processedSubspaces,
isCreate: false,
initialSelectedProducts:
TagHelper.createInitialSelectedProducts(
processedTags, processedSubspaces),
allTags: allTags,
spaceName: spaceName,
otherSpaceModels: otherSpaceModels,
spaceTagModels: processedTags,
pageContext: pageContext,
projectTags: projectTags,
spaceModel: SpaceTemplateModel(
modelName: spaceName,
tags: updatedTags,
uuid: spaceModel?.uuid,
internalId: spaceModel?.internalId,
subspaceModels: processedSubspaces)),
);
}
},
@ -310,22 +278,16 @@ class AssignTagModelsDialog extends StatelessWidget {
: ColorsManager.whiteColorsWithOpacity,
onPressed: state.isSaveEnabled
? () async {
final updatedTags =
List<Tag>.from(state.tags);
final updatedTags = List<Tag>.from(state.tags);
final result =
TagHelper.updateSubspaceTagModels(
updatedTags, subspaces);
TagHelper.updateSubspaceTagModels(updatedTags, subspaces);
final processedTags =
result['updatedTags'] as List<Tag>;
final processedSubspaces =
List<SubspaceTemplateModel>.from(
result['subspaces']
as List<dynamic>);
final processedTags = result['updatedTags'] as List<Tag>;
final processedSubspaces = List<SubspaceTemplateModel>.from(
result['subspaces'] as List<dynamic>);
Navigator.of(context)
.popUntil((route) => route.isFirst);
Navigator.of(context).popUntil((route) => route.isFirst);
await showDialog(
context: context,
@ -334,16 +296,15 @@ class AssignTagModelsDialog extends StatelessWidget {
products: products,
allSpaceModels: allSpaceModels,
allTags: allTags,
projectTags: projectTags,
pageContext: pageContext,
otherSpaceModels: otherSpaceModels,
spaceModel: SpaceTemplateModel(
modelName: spaceName,
tags: processedTags,
uuid: spaceModel?.uuid,
internalId:
spaceModel?.internalId,
subspaceModels:
processedSubspaces),
internalId: spaceModel?.internalId,
subspaceModels: processedSubspaces),
);
},
);

View File

@ -15,7 +15,8 @@ class SpaceModelPage extends StatelessWidget {
final Function(List<SpaceTemplateModel>)? onSpaceModelsUpdated;
final List<Tag> projectTags;
const SpaceModelPage({Key? key, this.products, this.onSpaceModelsUpdated, required this.projectTags})
const SpaceModelPage(
{Key? key, this.products, this.onSpaceModelsUpdated, required this.projectTags})
: super(key: key);
@override
@ -62,6 +63,7 @@ class SpaceModelPage extends StatelessWidget {
allTags: allTagValues,
pageContext: context,
otherSpaceModels: allSpaceModelNames,
projectTags: projectTags,
);
},
);
@ -85,6 +87,7 @@ class SpaceModelPage extends StatelessWidget {
otherSpaceModels: otherModel,
pageContext: context,
allSpaceModels: spaceModels,
projectTags: projectTags,
);
},
);

View File

@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_event.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_state.dart';
@ -25,6 +26,7 @@ class CreateSpaceModelDialog extends StatelessWidget {
final BuildContext? pageContext;
final List<String>? otherSpaceModels;
final List<SpaceTemplateModel>? allSpaceModels;
final List<Tag> projectTags;
const CreateSpaceModelDialog(
{Key? key,
@ -33,7 +35,8 @@ class CreateSpaceModelDialog extends StatelessWidget {
this.spaceModel,
this.pageContext,
this.otherSpaceModels,
this.allSpaceModels})
this.allSpaceModels,
required this.projectTags})
: super(key: key);
@override
@ -68,8 +71,7 @@ class CreateSpaceModelDialog extends StatelessWidget {
spaceNameController.addListener(() {
bloc.add(UpdateSpaceTemplateName(
name: spaceNameController.text,
allModels: otherSpaceModels ?? []));
name: spaceNameController.text, allModels: otherSpaceModels ?? []));
});
return bloc;
@ -87,9 +89,7 @@ class CreateSpaceModelDialog extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
Text(
spaceModel?.uuid == null
? 'Create New Space Model'
: 'Edit Space Model',
spaceModel?.uuid == null ? 'Create New Space Model' : 'Edit Space Model',
style: Theme.of(context)
.textTheme
.headlineLarge
@ -101,10 +101,8 @@ class CreateSpaceModelDialog extends StatelessWidget {
child: TextField(
controller: spaceNameController,
onChanged: (value) {
context.read<CreateSpaceModelBloc>().add(
UpdateSpaceTemplateName(
name: value,
allModels: otherSpaceModels ?? []));
context.read<CreateSpaceModelBloc>().add(UpdateSpaceTemplateName(
name: value, allModels: otherSpaceModels ?? []));
},
style: Theme.of(context)
.textTheme
@ -157,6 +155,7 @@ class CreateSpaceModelDialog extends StatelessWidget {
pageContext: pageContext,
otherSpaceModels: otherSpaceModels,
allSpaceModels: allSpaceModels,
projectTags: projectTags,
),
const SizedBox(height: 20),
SizedBox(
@ -179,84 +178,55 @@ class CreateSpaceModelDialog extends StatelessWidget {
!isNameValid)
? null
: () {
final updatedSpaceTemplate =
updatedSpaceModel.copyWith(
modelName:
spaceNameController.text.trim(),
final updatedSpaceTemplate = updatedSpaceModel.copyWith(
modelName: spaceNameController.text.trim(),
);
if (updatedSpaceModel.uuid == null) {
context
.read<CreateSpaceModelBloc>()
.add(
context.read<CreateSpaceModelBloc>().add(
CreateSpaceTemplate(
spaceTemplate:
updatedSpaceTemplate,
spaceTemplate: updatedSpaceTemplate,
onCreate: (newModel) {
if (pageContext != null) {
pageContext!.read<SpaceModelBloc>().add(
CreateSpaceModel(newSpaceModel: newModel));
pageContext!
.read<SpaceModelBloc>()
.add(CreateSpaceModel(
newSpaceModel:
newModel));
pageContext!
.read<
SpaceManagementBloc>()
.add(
UpdateSpaceModelCache(
newModel));
.read<SpaceManagementBloc>()
.add(UpdateSpaceModelCache(newModel));
}
Navigator.of(context)
.pop(); // Close the dialog
Navigator.of(context).pop(); // Close the dialog
},
),
);
} else {
if (pageContext != null) {
final currentState = pageContext!
.read<SpaceModelBloc>()
.state;
if (currentState
is SpaceModelLoaded) {
final spaceModels =
List<SpaceTemplateModel>.from(
currentState.spaceModels);
final currentState =
pageContext!.read<SpaceModelBloc>().state;
if (currentState is SpaceModelLoaded) {
final spaceModels = List<SpaceTemplateModel>.from(
currentState.spaceModels);
final SpaceTemplateModel?
currentSpaceModel = spaceModels
.cast<SpaceTemplateModel?>()
.firstWhere(
(sm) =>
sm?.uuid ==
updatedSpaceModel
.uuid,
final SpaceTemplateModel? currentSpaceModel =
spaceModels.cast<SpaceTemplateModel?>().firstWhere(
(sm) => sm?.uuid == updatedSpaceModel.uuid,
orElse: () => null,
);
if (currentSpaceModel != null) {
context
.read<CreateSpaceModelBloc>()
.add(ModifySpaceTemplate(
spaceTemplate:
currentSpaceModel,
updatedSpaceTemplate:
updatedSpaceTemplate,
spaceTemplate: currentSpaceModel,
updatedSpaceTemplate: updatedSpaceTemplate,
onUpdate: (newModel) {
if (pageContext !=
null) {
pageContext!
.read<
SpaceModelBloc>()
.add(UpdateSpaceModel(
if (pageContext != null) {
pageContext!.read<SpaceModelBloc>().add(
UpdateSpaceModel(
spaceModelUuid:
newModel.uuid ??
''));
newModel.uuid ?? ''));
pageContext!
.read<
SpaceManagementBloc>()
.add(UpdateSpaceModelCache(
newModel));
.read<SpaceManagementBloc>()
.add(UpdateSpaceModelCache(newModel));
}
Navigator.of(context)
.pop();
Navigator.of(context).pop();
}));
}
}
@ -265,11 +235,11 @@ class CreateSpaceModelDialog extends StatelessWidget {
},
backgroundColor: ColorsManager.secondaryColor,
borderRadius: 10,
foregroundColor: ((state.errorMessage != null &&
state.errorMessage != '') ||
!isNameValid)
? ColorsManager.whiteColorsWithOpacity
: ColorsManager.whiteColors,
foregroundColor:
((state.errorMessage != null && state.errorMessage != '') ||
!isNameValid)
? ColorsManager.whiteColorsWithOpacity
: ColorsManager.whiteColors,
child: const Text('OK'),
),
),

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_web/common/edit_chip.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
@ -20,6 +21,7 @@ class TagChipDisplay extends StatelessWidget {
final BuildContext? pageContext;
final List<String>? otherSpaceModels;
final List<SpaceTemplateModel>? allSpaceModels;
final List<Tag> projectTags;
const TagChipDisplay(BuildContext context,
{Key? key,
@ -31,14 +33,14 @@ class TagChipDisplay extends StatelessWidget {
required this.spaceNameController,
this.pageContext,
this.otherSpaceModels,
this.allSpaceModels})
this.allSpaceModels,
required this.projectTags})
: super(key: key);
@override
Widget build(BuildContext context) {
return (spaceModel?.tags?.isNotEmpty == true ||
spaceModel?.subspaceModels
?.any((subspace) => subspace.tags?.isNotEmpty == true) ==
spaceModel?.subspaceModels?.any((subspace) => subspace.tags?.isNotEmpty == true) ==
true)
? SizedBox(
width: screenWidth * 0.25,
@ -59,8 +61,7 @@ class TagChipDisplay extends StatelessWidget {
// Combine tags from spaceModel and subspaces
...TagHelper.groupTags([
...?spaceModel?.tags,
...?spaceModel?.subspaceModels
?.expand((subspace) => subspace.tags ?? [])
...?spaceModel?.subspaceModels?.expand((subspace) => subspace.tags ?? [])
]).entries.map(
(entry) => Chip(
avatar: SizedBox(
@ -76,9 +77,7 @@ class TagChipDisplay extends StatelessWidget {
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color:
ColorsManager.spaceColor),
.copyWith(color: ColorsManager.spaceColor),
),
backgroundColor: ColorsManager.whiteColors,
shape: RoundedRectangleBorder(
@ -105,13 +104,12 @@ class TagChipDisplay extends StatelessWidget {
spaceModel: spaceModel,
otherSpaceModels: otherSpaceModels,
initialTags: TagHelper.generateInitialTags(
subspaces: subspaces,
spaceTagModels: spaceModel?.tags ?? []),
subspaces: subspaces, spaceTagModels: spaceModel?.tags ?? []),
title: 'Edit Device',
addedProducts:
TagHelper.createInitialSelectedProducts(
spaceModel?.tags ?? [], subspaces),
addedProducts: TagHelper.createInitialSelectedProducts(
spaceModel?.tags ?? [], subspaces),
spaceName: spaceModel?.modelName ?? '',
projectTags: projectTags,
));
})
],
@ -134,6 +132,7 @@ class TagChipDisplay extends StatelessWidget {
isCreate: true,
spaceModel: spaceModel,
otherSpaceModels: otherSpaceModels,
projectTags: projectTags,
),
);
},

View File

@ -28,6 +28,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
final BuildContext? pageContext;
final SpaceTemplateModel? spaceModel;
final List<SpaceTemplateModel>? allSpaceModels;
final List<Tag> projectTags;
const AddDeviceTypeModelWidget(
{super.key,
@ -41,7 +42,8 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
this.pageContext,
this.otherSpaceModels,
this.spaceModel,
this.allSpaceModels});
this.allSpaceModels,
required this.projectTags});
@override
Widget build(BuildContext context) {
@ -78,8 +80,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
const SizedBox(height: 16),
Expanded(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 20.0),
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: ScrollableGridViewWidget(
isCreate: isCreate,
products: products,
@ -112,6 +113,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
allSpaceModels: allSpaceModels,
products: products,
allTags: allTags,
projectTags: projectTags,
pageContext: pageContext,
otherSpaceModels: otherSpaceModels,
spaceModel: SpaceTemplateModel(
@ -137,6 +139,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
subspaces: subspaces,
addedProducts: initialSelectedProducts ?? [],
allTags: allTags,
projectTags: projectTags,
spaceName: spaceName,
initialTags: initialTags,
otherSpaceModels: otherSpaceModels,
@ -149,11 +152,10 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
),
SizedBox(
width: 140,
child:
BlocBuilder<AddDeviceTypeModelBloc, AddDeviceModelState>(
child: BlocBuilder<AddDeviceTypeModelBloc, AddDeviceModelState>(
builder: (context, state) {
final isDisabled = state is AddDeviceModelLoaded &&
state.selectedProducts.isEmpty;
final isDisabled =
state is AddDeviceModelLoaded && state.selectedProducts.isEmpty;
return DefaultButton(
backgroundColor: ColorsManager.secondaryColor,
@ -166,15 +168,13 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
: () async {
if (state is AddDeviceModelLoaded &&
state.selectedProducts.isNotEmpty) {
final initialTags =
TagHelper.generateInitialTags(
final initialTags = TagHelper.generateInitialTags(
spaceTagModels: spaceTagModels,
subspaces: subspaces,
);
final dialogTitle = initialTags.isNotEmpty
? 'Edit Device'
: 'Assign Tags';
final dialogTitle =
initialTags.isNotEmpty ? 'Edit Device' : 'Assign Tags';
Navigator.of(context).pop();
await showDialog<bool>(
context: context,
@ -184,6 +184,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
subspaces: subspaces,
addedProducts: state.selectedProducts,
allTags: allTags,
projectTags: projectTags,
spaceName: spaceName,
initialTags: initialTags,
otherSpaceModels: otherSpaceModels,