mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 15:17:31 +00:00
added subspace model events
This commit is contained in:
@ -59,10 +59,12 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
|||||||
selectedSpace: state.selectedSpace,
|
selectedSpace: state.selectedSpace,
|
||||||
products: state.products,
|
products: state.products,
|
||||||
);
|
);
|
||||||
}else if(state is SpaceModelLoaded){
|
} else if (state is SpaceModelLoaded) {
|
||||||
return LoadedSpaceView(communities: state.communities, products: state.products, spaceModels: state.spaceModels);
|
return LoadedSpaceView(
|
||||||
}
|
communities: state.communities,
|
||||||
else if (state is SpaceManagementError) {
|
products: state.products,
|
||||||
|
spaceModels: state.spaceModels);
|
||||||
|
} else if (state is SpaceManagementError) {
|
||||||
return Center(child: Text('Error: ${state.errorMessage}'));
|
return Center(child: Text('Error: ${state.errorMessage}'));
|
||||||
}
|
}
|
||||||
return Container();
|
return Container();
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
|
|
||||||
|
// Events
|
||||||
|
abstract class SubSpaceModelEvent {}
|
||||||
|
|
||||||
|
class AddSubSpaceModel extends SubSpaceModelEvent {
|
||||||
|
final SubspaceTemplateModel subSpace;
|
||||||
|
AddSubSpaceModel(this.subSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
class RemoveSubSpaceModel extends SubSpaceModelEvent {
|
||||||
|
final SubspaceTemplateModel subSpace;
|
||||||
|
RemoveSubSpaceModel(this.subSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
// State
|
||||||
|
class SubSpaceModelState {
|
||||||
|
final List<SubspaceTemplateModel> subSpaces;
|
||||||
|
SubSpaceModelState(this.subSpaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BLoC
|
||||||
|
class SubSpaceModelBloc extends Bloc<SubSpaceModelEvent, SubSpaceModelState> {
|
||||||
|
SubSpaceModelBloc() : super(SubSpaceModelState([])) {
|
||||||
|
on<AddSubSpaceModel>((event, emit) {
|
||||||
|
final updatedSubSpaces = List<SubspaceTemplateModel>.from(state.subSpaces)
|
||||||
|
..add(event.subSpace);
|
||||||
|
emit(SubSpaceModelState(updatedSubSpaces));
|
||||||
|
});
|
||||||
|
|
||||||
|
on<RemoveSubSpaceModel>((event, emit) {
|
||||||
|
final updatedSubSpaces = List<SubspaceTemplateModel>.from(state.subSpaces)
|
||||||
|
..remove(event.subSpace);
|
||||||
|
emit(SubSpaceModelState(updatedSubSpaces));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class SpaceTemplateModel {
|
class SpaceTemplateModel {
|
||||||
final String uuid;
|
final String uuid;
|
||||||
@ -6,28 +7,33 @@ class SpaceTemplateModel {
|
|||||||
final DateTime updatedAt;
|
final DateTime updatedAt;
|
||||||
final String modelName;
|
final String modelName;
|
||||||
final bool disabled;
|
final bool disabled;
|
||||||
final List<SubspaceModel> subspaceModels;
|
final List<SubspaceTemplateModel> subspaceModels;
|
||||||
final List<TagModel> tags;
|
final List<TagModel> tags;
|
||||||
|
String internalId;
|
||||||
|
|
||||||
SpaceTemplateModel({
|
SpaceTemplateModel({
|
||||||
required this.uuid,
|
required this.uuid,
|
||||||
|
String? internalId,
|
||||||
required this.createdAt,
|
required this.createdAt,
|
||||||
required this.updatedAt,
|
required this.updatedAt,
|
||||||
required this.modelName,
|
required this.modelName,
|
||||||
required this.disabled,
|
required this.disabled,
|
||||||
required this.subspaceModels,
|
required this.subspaceModels,
|
||||||
required this.tags,
|
required this.tags,
|
||||||
});
|
}) : internalId = internalId ?? const Uuid().v4();
|
||||||
|
|
||||||
factory SpaceTemplateModel.fromJson(Map<String, dynamic> json) {
|
factory SpaceTemplateModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
final String internalId = json['internalId'] ?? const Uuid().v4();
|
||||||
|
|
||||||
return SpaceTemplateModel(
|
return SpaceTemplateModel(
|
||||||
uuid: json['uuid'] ?? '',
|
uuid: json['uuid'] ?? '',
|
||||||
|
internalId: internalId,
|
||||||
createdAt: DateTime.parse(json['createdAt']),
|
createdAt: DateTime.parse(json['createdAt']),
|
||||||
updatedAt: DateTime.parse(json['updatedAt']),
|
updatedAt: DateTime.parse(json['updatedAt']),
|
||||||
modelName: json['modelName'] ?? '',
|
modelName: json['modelName'] ?? '',
|
||||||
disabled: json['disabled'] ?? false,
|
disabled: json['disabled'] ?? false,
|
||||||
subspaceModels: (json['subspaceModels'] as List)
|
subspaceModels: (json['subspaceModels'] as List)
|
||||||
.map((item) => SubspaceModel.fromJson(item))
|
.map((item) => SubspaceTemplateModel.fromJson(item))
|
||||||
.toList(),
|
.toList(),
|
||||||
tags: (json['tags'] as List)
|
tags: (json['tags'] as List)
|
||||||
.map((item) => TagModel.fromJson(item))
|
.map((item) => TagModel.fromJson(item))
|
||||||
@ -48,28 +54,22 @@ class SpaceTemplateModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SubspaceModel {
|
class SubspaceTemplateModel {
|
||||||
final String uuid;
|
final String? uuid;
|
||||||
final DateTime createdAt;
|
|
||||||
final DateTime updatedAt;
|
|
||||||
final String subspaceName;
|
final String subspaceName;
|
||||||
final bool disabled;
|
final bool disabled;
|
||||||
final List<TagModel> tags;
|
final List<TagModel>? tags;
|
||||||
|
|
||||||
SubspaceModel({
|
SubspaceTemplateModel({
|
||||||
required this.uuid,
|
this.uuid,
|
||||||
required this.createdAt,
|
|
||||||
required this.updatedAt,
|
|
||||||
required this.subspaceName,
|
required this.subspaceName,
|
||||||
required this.disabled,
|
required this.disabled,
|
||||||
required this.tags,
|
this.tags,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory SubspaceModel.fromJson(Map<String, dynamic> json) {
|
factory SubspaceTemplateModel.fromJson(Map<String, dynamic> json) {
|
||||||
return SubspaceModel(
|
return SubspaceTemplateModel(
|
||||||
uuid: json['uuid'] ?? '',
|
uuid: json['uuid'] ?? '',
|
||||||
createdAt: DateTime.parse(json['createdAt']),
|
|
||||||
updatedAt: DateTime.parse(json['updatedAt']),
|
|
||||||
subspaceName: json['subspaceName'] ?? '',
|
subspaceName: json['subspaceName'] ?? '',
|
||||||
disabled: json['disabled'] ?? false,
|
disabled: json['disabled'] ?? false,
|
||||||
tags: (json['tags'] as List)
|
tags: (json['tags'] as List)
|
||||||
@ -81,11 +81,9 @@ class SubspaceModel {
|
|||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'uuid': uuid,
|
'uuid': uuid,
|
||||||
'createdAt': createdAt.toIso8601String(),
|
|
||||||
'updatedAt': updatedAt.toIso8601String(),
|
|
||||||
'subspaceName': subspaceName,
|
'subspaceName': subspaceName,
|
||||||
'disabled': disabled,
|
'disabled': disabled,
|
||||||
'tags': tags.map((e) => e.toJson()).toList(),
|
'tags': tags?.map((e) => e.toJson()).toList() ?? [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/create_subspace_model_dialog.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class CreateSpaceModelDialog extends StatelessWidget {
|
class CreateSpaceModelDialog extends StatelessWidget {
|
||||||
@ -48,37 +50,58 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
SizedBox(
|
GestureDetector(
|
||||||
width: screenWidth * 0.25,
|
onTap: () async {
|
||||||
child: Container(
|
final result = await showDialog(
|
||||||
decoration: BoxDecoration(
|
context: context,
|
||||||
color: ColorsManager.textFieldGreyColor,
|
builder: (BuildContext context) {
|
||||||
border: Border.all(
|
return CreateSubSpaceModelDialog(
|
||||||
color: ColorsManager.neutralGray,
|
isEdit: true,
|
||||||
width: 3.0,
|
dialogTitle: 'Create Sub-space',
|
||||||
|
existingSubSpaces: [
|
||||||
|
SubspaceTemplateModel(
|
||||||
|
subspaceName: "Living Room",
|
||||||
|
disabled: false,
|
||||||
|
uuid: "mkmkl,",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (result == true) {}
|
||||||
|
},
|
||||||
|
child: SizedBox(
|
||||||
|
width: screenWidth * 0.25,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: ColorsManager.textFieldGreyColor,
|
||||||
|
border: Border.all(
|
||||||
|
color: ColorsManager.neutralGray,
|
||||||
|
width: 3.0,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(20),
|
child: const Padding(
|
||||||
),
|
padding:
|
||||||
child: const Padding(
|
EdgeInsets.symmetric(vertical: 10.0, horizontal: 16.0),
|
||||||
padding:
|
child: Row(
|
||||||
EdgeInsets.symmetric(vertical: 10.0, horizontal: 16.0),
|
children: [
|
||||||
child: Row(
|
Icon(
|
||||||
children: [
|
Icons.add,
|
||||||
Icon(
|
color: ColorsManager.spaceColor,
|
||||||
Icons.add,
|
),
|
||||||
color: ColorsManager.spaceColor,
|
SizedBox(width: 10),
|
||||||
),
|
Expanded(
|
||||||
SizedBox(width: 10),
|
child: Text(
|
||||||
Expanded(
|
'Create sub space',
|
||||||
child: Text(
|
style: TextStyle(
|
||||||
'Create sub space',
|
color: ColorsManager.blackColor,
|
||||||
style: TextStyle(
|
fontSize: 16,
|
||||||
color: ColorsManager.blackColor,
|
),
|
||||||
fontSize: 16,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -0,0 +1,188 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/subspace_model_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class CreateSubSpaceModelDialog extends StatefulWidget {
|
||||||
|
final bool isEdit; // Flag to determine if it's edit or create
|
||||||
|
final String dialogTitle; // Title for the dialog
|
||||||
|
final List<SubspaceTemplateModel>? existingSubSpaces; // For edit mode
|
||||||
|
|
||||||
|
const CreateSubSpaceModelDialog({
|
||||||
|
super.key,
|
||||||
|
required this.isEdit,
|
||||||
|
required this.dialogTitle,
|
||||||
|
this.existingSubSpaces,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_CreateSubSpaceModelDialogState createState() =>
|
||||||
|
_CreateSubSpaceModelDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CreateSubSpaceModelDialogState extends State<CreateSubSpaceModelDialog> {
|
||||||
|
final TextEditingController textController = TextEditingController();
|
||||||
|
final FocusNode focusNode = FocusNode();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
focusNode.requestFocus();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (widget.isEdit) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
textController.dispose();
|
||||||
|
focusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
|
return Dialog(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: BlocProvider(
|
||||||
|
create: (_) => SubSpaceModelBloc(),
|
||||||
|
child: BlocBuilder<SubSpaceModelBloc, SubSpaceModelState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return SizedBox(
|
||||||
|
width: screenWidth * 0.35,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
widget.dialogTitle,
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.headlineLarge
|
||||||
|
?.copyWith(color: ColorsManager.blackColor),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Container(
|
||||||
|
width: screenWidth * 0.35,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 10.0, horizontal: 16.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: ColorsManager.boxColor,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 8.0,
|
||||||
|
runSpacing: 8.0,
|
||||||
|
children: [
|
||||||
|
...state.subSpaces.map(
|
||||||
|
(subSpace) => Chip(
|
||||||
|
label: Text(subSpace.subspaceName,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: ColorsManager.spaceColor)),
|
||||||
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
side: const BorderSide(
|
||||||
|
color: ColorsManager.transparentColor,
|
||||||
|
width: 0),
|
||||||
|
),
|
||||||
|
deleteIcon: Container(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
border: Border.all(
|
||||||
|
color: ColorsManager.lightGrayColor,
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.close,
|
||||||
|
size: 16,
|
||||||
|
color: ColorsManager.lightGrayColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onDeleted: () => context
|
||||||
|
.read<SubSpaceModelBloc>()
|
||||||
|
.add(RemoveSubSpaceModel(subSpace)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 200,
|
||||||
|
child: TextField(
|
||||||
|
controller: textController,
|
||||||
|
focusNode: focusNode,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
hintText: state.subSpaces.isEmpty
|
||||||
|
? 'Please enter the name'
|
||||||
|
: null,
|
||||||
|
hintStyle: const TextStyle(
|
||||||
|
color: ColorsManager.lightGrayColor),
|
||||||
|
),
|
||||||
|
onSubmitted: (value) {
|
||||||
|
if (value.trim().isNotEmpty) {
|
||||||
|
context.read<SubSpaceModelBloc>().add(
|
||||||
|
AddSubSpaceModel(SubspaceTemplateModel(
|
||||||
|
subspaceName: value.trim(),
|
||||||
|
disabled: false)));
|
||||||
|
textController.clear();
|
||||||
|
focusNode.requestFocus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
style: const TextStyle(
|
||||||
|
color: ColorsManager.blackColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CancelButton(
|
||||||
|
label: 'Cancel',
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: DefaultButton(
|
||||||
|
onPressed: () {
|
||||||
|
final subSpaces = context
|
||||||
|
.read<SubSpaceModelBloc>()
|
||||||
|
.state
|
||||||
|
.subSpaces;
|
||||||
|
Navigator.of(context).pop(subSpaces);
|
||||||
|
},
|
||||||
|
backgroundColor: ColorsManager.secondaryColor,
|
||||||
|
borderRadius: 10,
|
||||||
|
foregroundColor: ColorsManager.whiteColors,
|
||||||
|
child: const Text('OK'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -19,9 +19,11 @@ class SpaceModelCardWidget extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (var subspace in model.subspaceModels) {
|
for (var subspace in model.subspaceModels) {
|
||||||
for (var tag in subspace.tags) {
|
if (subspace.tags != null) {
|
||||||
final prodIcon = tag.product?.icon ?? 'Unknown';
|
for (var tag in subspace.tags!) {
|
||||||
productTagCount[prodIcon] = (productTagCount[prodIcon] ?? 0) + 1;
|
final prodIcon = tag.product?.icon ?? 'Unknown';
|
||||||
|
productTagCount[prodIcon] = (productTagCount[prodIcon] ?? 0) + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
class TempConst {
|
class TempConst {
|
||||||
static const projectId = '0e62577c-06fa-41b9-8a92-99a21fbaf51c';
|
static const projectId = '0685c781-df33-4cbf-bf65-9f4e835eb468';
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user