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: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/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'; import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_type_model_event.dart';
class AddDeviceTypeModelBloc class AddDeviceTypeModelBloc
extends Bloc<AddDeviceTypeModelEvent, List<SelectedProduct>> { extends Bloc<AddDeviceTypeModelEvent, AddDeviceModelState> {
AddDeviceTypeModelBloc(List<SelectedProduct> initialProducts) AddDeviceTypeModelBloc() : super(AddDeviceModelInitial()) {
: super(initialProducts) { on<InitializeDeviceTypeModel>(_onInitializeTagModels);
on<UpdateProductCountEvent>(_onUpdateProductCount); on<UpdateProductCountEvent>(_onUpdateProductCount);
} }
void _onUpdateProductCount( void _onInitializeTagModels(
UpdateProductCountEvent event, Emitter<List<SelectedProduct>> emit) { InitializeDeviceTypeModel event, Emitter<AddDeviceModelState> emit) {
final existingProduct = state.firstWhere( emit(AddDeviceModelLoaded(
(p) => p.productId == event.productId, selectedProducts: event.addedProducts,
orElse: () => SelectedProduct(productId: event.productId, count: 0,productName: event.productName,product: event.product ), initialTag: event.initialTags,
); ));
}
if (event.count > 0) { void _onUpdateProductCount(
if (!state.contains(existingProduct)) { UpdateProductCountEvent event, Emitter<AddDeviceModelState> emit) {
emit([ final currentState = state;
...state,
SelectedProduct(productId: event.productId, count: event.count, productName: event.productName, product: event.product) 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 { } else {
final updatedList = state.map((p) { // Remove the product if the count is 0
if (p.productId == event.productId) { updatedProducts = currentState.selectedProducts
return SelectedProduct(productId: p.productId, count: event.count, productName: p.productName,product: p.product); .where((p) => p.productId != event.productId)
} .toList();
return p;
}).toList();
emit(updatedList);
} }
} 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: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/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 { abstract class AddDeviceTypeModelEvent extends Equatable {
const AddDeviceTypeModelEvent();
@override @override
List<Object> get props => []; List<Object> get props => [];
} }
class UpdateProductCountEvent extends AddDeviceTypeModelEvent { class UpdateProductCountEvent extends AddDeviceTypeModelEvent {
final String productId; final String productId;
final int count; final int count;
@ -17,3 +22,17 @@ class UpdateProductCountEvent extends AddDeviceTypeModelEvent {
@override @override
List<Object> get props => [productId, count]; 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/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/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_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/action_button_widget.dart';
import 'package:syncrow_web/pages/spaces_management/tag_model/widgets/scrollable_grid_view_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'; import 'package:syncrow_web/utils/color_manager.dart';
@ -21,14 +23,15 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
final List<String>? allTags; final List<String>? allTags;
final String spaceName; final String spaceName;
const AddDeviceTypeModelWidget( const AddDeviceTypeModelWidget({
{super.key, super.key,
this.products, this.products,
this.initialSelectedProducts, this.initialSelectedProducts,
this.subspaces, this.subspaces,
this.allTags, this.allTags,
this.spaceTagModels, this.spaceTagModels,
required this.spaceName}); required this.spaceName,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -40,91 +43,108 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
: 3; : 3;
return BlocProvider( return BlocProvider(
create: (_) => AddDeviceTypeModelBloc(initialSelectedProducts ?? []), create: (_) => AddDeviceTypeModelBloc()
child: Builder( ..add(InitializeDeviceTypeModel(
builder: (context) => AlertDialog( initialTags: spaceTagModels ?? [],
title: const Text('Add Devices'), addedProducts: initialSelectedProducts ?? [],
backgroundColor: ColorsManager.whiteColors, )),
content: SingleChildScrollView( child: Builder(
child: Container( builder: (context) => AlertDialog(
width: size.width * 0.9, title: const Text('Add Devices'),
height: size.height * 0.65, backgroundColor: ColorsManager.whiteColors,
color: ColorsManager.textFieldGreyColor, content: BlocBuilder<AddDeviceTypeModelBloc, AddDeviceModelState>(
child: Column( builder: (context, state) {
children: [ if (state is AddDeviceModelLoading) {
const SizedBox(height: 16), return const Center(child: CircularProgressIndicator());
Expanded( }
child: Padding( if (state is AddDeviceModelLoaded) {
padding: const EdgeInsets.symmetric(horizontal: 20.0), return SingleChildScrollView(
child: ScrollableGridViewWidget( child: Container(
products: products, crossAxisCount: crossAxisCount), 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,
),
),
);
},
), ),
), ActionButton(
), label: 'Continue',
actions: [ backgroundColor: ColorsManager.secondaryColor,
Row( foregroundColor: ColorsManager.whiteColors,
mainAxisAlignment: MainAxisAlignment.spaceBetween, onPressed: () async {
children: [ final state = context.read<AddDeviceTypeModelBloc>().state;
CancelButton( if (state is AddDeviceModelLoaded &&
label: 'Cancel', state.selectedProducts.isNotEmpty) {
onPressed: () async { final initialTags = generateInitialTags(
Navigator.of(context).pop(); spaceTagModels: spaceTagModels,
await showDialog( subspaces: subspaces,
);
final dialogTitle = initialTags.isNotEmpty
? 'Edit Device'
: 'Assign Tags';
await showDialog<bool>(
barrierDismissible: false, barrierDismissible: false,
context: context, context: context,
builder: (context) => CreateSpaceModelDialog( builder: (context) => AssignTagModelsDialog(
products: products, 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,
subspaces: subspaces, subspaces: subspaces,
); addedProducts: state.selectedProducts,
allTags: allTags,
final dialogTitle = initialTags.isNotEmpty spaceName: spaceName,
? 'Edit Device' initialTags: state.initialTag,
: 'Assign Tags'; title: dialogTitle,
await showDialog<bool>( ),
barrierDismissible: false, );
context: context, }
builder: (context) => AssignTagModelsDialog( },
products: products, ),
subspaces: subspaces, ],
addedProducts: currentState, ),
allTags: allTags, ],
spaceName: spaceName, ),
initialTags: initialTags, ),
title: dialogTitle, );
),
);
}
},
),
],
),
],
),
));
} }
List<TagModel> generateInitialTags({ 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/product_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_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_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'; import 'package:syncrow_web/pages/spaces_management/tag_model/widgets/device_type_tile_widget.dart';
class ScrollableGridViewWidget extends StatelessWidget { class ScrollableGridViewWidget extends StatelessWidget {
@ -24,8 +25,12 @@ class ScrollableGridViewWidget extends StatelessWidget {
return Scrollbar( return Scrollbar(
controller: scrollController, controller: scrollController,
thumbVisibility: true, thumbVisibility: true,
child: BlocBuilder<AddDeviceTypeModelBloc, List<SelectedProduct>>( child: BlocBuilder<AddDeviceTypeModelBloc, AddDeviceModelState>(
builder: (context, productCounts) { builder: (context, state) {
final productCounts = state is AddDeviceModelLoaded
? state.selectedProducts
: <SelectedProduct>[];
return GridView.builder( return GridView.builder(
controller: scrollController, controller: scrollController,
shrinkWrap: true, shrinkWrap: true,