updated grid view

This commit is contained in:
hannathkadher
2025-01-17 12:40:17 +04:00
parent bae5ae17a7
commit 145086b9de
5 changed files with 231 additions and 114 deletions

View File

@ -1,38 +1,75 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_model_state.dart';
import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_type_model_event.dart';
class AddDeviceTypeModelBloc
extends Bloc<AddDeviceTypeModelEvent, List<SelectedProduct>> {
AddDeviceTypeModelBloc(List<SelectedProduct> initialProducts)
: super(initialProducts) {
extends Bloc<AddDeviceTypeModelEvent, AddDeviceModelState> {
AddDeviceTypeModelBloc() : super(AddDeviceModelInitial()) {
on<InitializeDeviceTypeModel>(_onInitializeTagModels);
on<UpdateProductCountEvent>(_onUpdateProductCount);
}
void _onUpdateProductCount(
UpdateProductCountEvent event, Emitter<List<SelectedProduct>> emit) {
final existingProduct = state.firstWhere(
(p) => p.productId == event.productId,
orElse: () => SelectedProduct(productId: event.productId, count: 0,productName: event.productName,product: event.product ),
);
void _onInitializeTagModels(
InitializeDeviceTypeModel event, Emitter<AddDeviceModelState> emit) {
emit(AddDeviceModelLoaded(
selectedProducts: event.addedProducts,
initialTag: event.initialTags,
));
}
if (event.count > 0) {
if (!state.contains(existingProduct)) {
emit([
...state,
SelectedProduct(productId: event.productId, count: event.count, productName: event.productName, product: event.product)
]);
void _onUpdateProductCount(
UpdateProductCountEvent event, Emitter<AddDeviceModelState> emit) {
final currentState = state;
if (currentState is AddDeviceModelLoaded) {
final existingProduct = currentState.selectedProducts.firstWhere(
(p) => p.productId == event.productId,
orElse: () => SelectedProduct(
productId: event.productId,
count: 0,
productName: event.productName,
product: event.product,
),
);
List<SelectedProduct> updatedProducts;
if (event.count > 0) {
if (!currentState.selectedProducts.contains(existingProduct)) {
updatedProducts = [
...currentState.selectedProducts,
SelectedProduct(
productId: event.productId,
count: event.count,
productName: event.productName,
product: event.product,
),
];
} else {
updatedProducts = currentState.selectedProducts.map((p) {
if (p.productId == event.productId) {
return SelectedProduct(
productId: p.productId,
count: event.count,
productName: p.productName,
product: p.product,
);
}
return p;
}).toList();
}
} else {
final updatedList = state.map((p) {
if (p.productId == event.productId) {
return SelectedProduct(productId: p.productId, count: event.count, productName: p.productName,product: p.product);
}
return p;
}).toList();
emit(updatedList);
// Remove the product if the count is 0
updatedProducts = currentState.selectedProducts
.where((p) => p.productId != event.productId)
.toList();
}
} else {
emit(state.where((p) => p.productId != event.productId).toList());
// Emit the updated state
emit(AddDeviceModelLoaded(
selectedProducts: updatedProducts,
initialTag: currentState.initialTag));
}
}
}

View File

@ -0,0 +1,36 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
abstract class AddDeviceModelState extends Equatable {
const AddDeviceModelState();
@override
List<Object> get props => [];
}
class AddDeviceModelInitial extends AddDeviceModelState {}
class AddDeviceModelLoading extends AddDeviceModelState {}
class AddDeviceModelLoaded extends AddDeviceModelState {
final List<SelectedProduct> selectedProducts;
final List<TagModel> initialTag;
const AddDeviceModelLoaded({
required this.selectedProducts,
required this.initialTag,
});
@override
List<Object> get props => [selectedProducts, initialTag];
}
class AddDeviceModelError extends AddDeviceModelState {
final String errorMessage;
const AddDeviceModelError(this.errorMessage);
@override
List<Object> get props => [errorMessage];
}

View File

@ -1,11 +1,16 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
abstract class AddDeviceTypeModelEvent extends Equatable {
const AddDeviceTypeModelEvent();
@override
List<Object> get props => [];
}
class UpdateProductCountEvent extends AddDeviceTypeModelEvent {
final String productId;
final int count;
@ -17,3 +22,17 @@ class UpdateProductCountEvent extends AddDeviceTypeModelEvent {
@override
List<Object> get props => [productId, count];
}
class InitializeDeviceTypeModel extends AddDeviceTypeModelEvent {
final List<TagModel> initialTags;
final List<SelectedProduct> addedProducts;
const InitializeDeviceTypeModel({
this.initialTags = const [],
required this.addedProducts,
});
@override
List<Object> get props => [initialTags, addedProducts];
}

View File

@ -9,6 +9,8 @@ import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_model_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_model_state.dart';
import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_type_model_event.dart';
import 'package:syncrow_web/pages/spaces_management/tag_model/widgets/action_button_widget.dart';
import 'package:syncrow_web/pages/spaces_management/tag_model/widgets/scrollable_grid_view_widget.dart';
import 'package:syncrow_web/utils/color_manager.dart';
@ -21,14 +23,15 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
final List<String>? allTags;
final String spaceName;
const AddDeviceTypeModelWidget(
{super.key,
this.products,
this.initialSelectedProducts,
this.subspaces,
this.allTags,
this.spaceTagModels,
required this.spaceName});
const AddDeviceTypeModelWidget({
super.key,
this.products,
this.initialSelectedProducts,
this.subspaces,
this.allTags,
this.spaceTagModels,
required this.spaceName,
});
@override
Widget build(BuildContext context) {
@ -40,91 +43,108 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
: 3;
return BlocProvider(
create: (_) => AddDeviceTypeModelBloc(initialSelectedProducts ?? []),
child: Builder(
builder: (context) => AlertDialog(
title: const Text('Add Devices'),
backgroundColor: ColorsManager.whiteColors,
content: SingleChildScrollView(
child: Container(
width: size.width * 0.9,
height: size.height * 0.65,
color: ColorsManager.textFieldGreyColor,
child: Column(
children: [
const SizedBox(height: 16),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: ScrollableGridViewWidget(
products: products, crossAxisCount: crossAxisCount),
),
create: (_) => AddDeviceTypeModelBloc()
..add(InitializeDeviceTypeModel(
initialTags: spaceTagModels ?? [],
addedProducts: initialSelectedProducts ?? [],
)),
child: Builder(
builder: (context) => AlertDialog(
title: const Text('Add Devices'),
backgroundColor: ColorsManager.whiteColors,
content: BlocBuilder<AddDeviceTypeModelBloc, AddDeviceModelState>(
builder: (context, state) {
if (state is AddDeviceModelLoading) {
return const Center(child: CircularProgressIndicator());
}
if (state is AddDeviceModelLoaded) {
return SingleChildScrollView(
child: Container(
width: size.width * 0.9,
height: size.height * 0.65,
color: ColorsManager.textFieldGreyColor,
child: Column(
children: [
const SizedBox(height: 16),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: ScrollableGridViewWidget(
products: products,
crossAxisCount: crossAxisCount,
initialProductCounts: state.selectedProducts,
),
),
),
],
),
],
),
);
}
return const SizedBox();
},
),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CancelButton(
label: 'Cancel',
onPressed: () async {
Navigator.of(context).pop();
await showDialog(
barrierDismissible: false,
context: context,
builder: (context) => CreateSpaceModelDialog(
products: products,
allTags: allTags,
spaceModel: SpaceTemplateModel(
modelName: spaceName,
subspaceModels: subspaces,
tags: spaceTagModels,
),
),
);
},
),
),
),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CancelButton(
label: 'Cancel',
onPressed: () async {
Navigator.of(context).pop();
await showDialog(
ActionButton(
label: 'Continue',
backgroundColor: ColorsManager.secondaryColor,
foregroundColor: ColorsManager.whiteColors,
onPressed: () async {
final state = context.read<AddDeviceTypeModelBloc>().state;
if (state is AddDeviceModelLoaded &&
state.selectedProducts.isNotEmpty) {
final initialTags = generateInitialTags(
spaceTagModels: spaceTagModels,
subspaces: subspaces,
);
final dialogTitle = initialTags.isNotEmpty
? 'Edit Device'
: 'Assign Tags';
await showDialog<bool>(
barrierDismissible: false,
context: context,
builder: (context) => CreateSpaceModelDialog(
products: products,
allTags: allTags,
spaceModel: SpaceTemplateModel(
modelName: spaceName,
subspaceModels: subspaces,
tags: spaceTagModels,
)),
);
},
),
ActionButton(
label: 'Continue',
backgroundColor: ColorsManager.secondaryColor,
foregroundColor: ColorsManager.whiteColors,
onPressed: () async {
final currentState =
context.read<AddDeviceTypeModelBloc>().state;
Navigator.of(context).pop();
if (currentState.isNotEmpty) {
final initialTags = generateInitialTags(
spaceTagModels: spaceTagModels,
builder: (context) => AssignTagModelsDialog(
products: products,
subspaces: subspaces,
);
final dialogTitle = initialTags.isNotEmpty
? 'Edit Device'
: 'Assign Tags';
await showDialog<bool>(
barrierDismissible: false,
context: context,
builder: (context) => AssignTagModelsDialog(
products: products,
subspaces: subspaces,
addedProducts: currentState,
allTags: allTags,
spaceName: spaceName,
initialTags: initialTags,
title: dialogTitle,
),
);
}
},
),
],
),
],
),
));
addedProducts: state.selectedProducts,
allTags: allTags,
spaceName: spaceName,
initialTags: state.initialTag,
title: dialogTitle,
),
);
}
},
),
],
),
],
),
),
);
}
List<TagModel> generateInitialTags({

View File

@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_model_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_model_state.dart';
import 'package:syncrow_web/pages/spaces_management/tag_model/widgets/device_type_tile_widget.dart';
class ScrollableGridViewWidget extends StatelessWidget {
@ -24,8 +25,12 @@ class ScrollableGridViewWidget extends StatelessWidget {
return Scrollbar(
controller: scrollController,
thumbVisibility: true,
child: BlocBuilder<AddDeviceTypeModelBloc, List<SelectedProduct>>(
builder: (context, productCounts) {
child: BlocBuilder<AddDeviceTypeModelBloc, AddDeviceModelState>(
builder: (context, state) {
final productCounts = state is AddDeviceModelLoaded
? state.selectedProducts
: <SelectedProduct>[];
return GridView.builder(
controller: scrollController,
shrinkWrap: true,