update products page + filter
This commit is contained in:
@@ -194,7 +194,10 @@ class _LoginPageState extends ConsumerState<LoginPage> {
|
|||||||
|
|
||||||
TextButton(onPressed: () {
|
TextButton(onPressed: () {
|
||||||
context.pushNamed(RouteNames.otpVerification);
|
context.pushNamed(RouteNames.otpVerification);
|
||||||
}, child: Text('otp'))
|
}, child: Text('otp')),
|
||||||
|
TextButton(onPressed: () {
|
||||||
|
context.pushReplacementNamed(RouteNames.home);
|
||||||
|
}, child: Text('home'))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import 'package:worker/features/cart/presentation/providers/cart_provider.dart';
|
|||||||
import 'package:worker/features/products/presentation/providers/categories_provider.dart';
|
import 'package:worker/features/products/presentation/providers/categories_provider.dart';
|
||||||
import 'package:worker/features/products/presentation/providers/products_provider.dart';
|
import 'package:worker/features/products/presentation/providers/products_provider.dart';
|
||||||
import 'package:worker/features/products/presentation/widgets/category_filter_chips.dart';
|
import 'package:worker/features/products/presentation/widgets/category_filter_chips.dart';
|
||||||
|
import 'package:worker/features/products/presentation/widgets/product_filter_drawer.dart';
|
||||||
import 'package:worker/features/products/presentation/widgets/product_grid.dart';
|
import 'package:worker/features/products/presentation/widgets/product_grid.dart';
|
||||||
import 'package:worker/features/products/presentation/widgets/product_search_bar.dart';
|
import 'package:worker/features/products/presentation/widgets/product_search_bar.dart';
|
||||||
import 'package:worker/generated/l10n/app_localizations.dart';
|
import 'package:worker/generated/l10n/app_localizations.dart';
|
||||||
@@ -37,6 +38,7 @@ class ProductsPage extends ConsumerWidget {
|
|||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: const Color(0xFFF4F6F8), // Match HTML background
|
backgroundColor: const Color(0xFFF4F6F8), // Match HTML background
|
||||||
|
endDrawer: const ProductFilterDrawer(),
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_back, color: Colors.black),
|
icon: const Icon(Icons.arrow_back, color: Colors.black),
|
||||||
@@ -65,12 +67,55 @@ class ProductsPage extends ConsumerWidget {
|
|||||||
const SizedBox(width: AppSpacing.sm),
|
const SizedBox(width: AppSpacing.sm),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Builder(
|
||||||
|
builder: (BuildContext scaffoldContext) {
|
||||||
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
// Search Bar
|
// Search Bar with Filter Button
|
||||||
const SizedBox(height: AppSpacing.sm),
|
Padding(
|
||||||
const ProductSearchBar(),
|
padding: const EdgeInsets.all(AppSpacing.md),
|
||||||
const SizedBox(height: AppSpacing.sm),
|
child: Row(
|
||||||
|
children: [
|
||||||
|
// Search Bar (Expanded)
|
||||||
|
const Expanded(
|
||||||
|
child: ProductSearchBar(),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
// Filter Button
|
||||||
|
SizedBox(
|
||||||
|
height: InputFieldSpecs.height,
|
||||||
|
child: OutlinedButton.icon(
|
||||||
|
onPressed: () {
|
||||||
|
// Open filter drawer from right
|
||||||
|
Scaffold.of(scaffoldContext).openEndDrawer();
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.filter_list, size: 20),
|
||||||
|
label: const Text(
|
||||||
|
'Lọc',
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
|
),
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
foregroundColor: AppColors.grey900,
|
||||||
|
side: const BorderSide(
|
||||||
|
color: AppColors.white,
|
||||||
|
width: 0,
|
||||||
|
),
|
||||||
|
backgroundColor: AppColors.white,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
InputFieldSpecs.borderRadius,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
// Category Filter Chips
|
// Category Filter Chips
|
||||||
categoriesAsync.when(
|
categoriesAsync.when(
|
||||||
@@ -104,7 +149,8 @@ class ProductsPage extends ConsumerWidget {
|
|||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text('${product.name} đã thêm vào giỏ hàng'),
|
content:
|
||||||
|
Text('${product.name} đã thêm vào giỏ hàng'),
|
||||||
duration: const Duration(seconds: 2),
|
duration: const Duration(seconds: 2),
|
||||||
action: SnackBarAction(
|
action: SnackBarAction(
|
||||||
label: 'Xem',
|
label: 'Xem',
|
||||||
@@ -121,6 +167,8 @@ class ProductsPage extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/// Provider: Product Filters State
|
||||||
|
///
|
||||||
|
/// Manages product filter selections.
|
||||||
|
library;
|
||||||
|
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
/// Product Filters State
|
||||||
|
class ProductFiltersState {
|
||||||
|
final Set<String> productLines;
|
||||||
|
final Set<String> spaces;
|
||||||
|
final Set<String> sizes;
|
||||||
|
final Set<String> surfaces;
|
||||||
|
final Set<String> brands;
|
||||||
|
|
||||||
|
const ProductFiltersState({
|
||||||
|
this.productLines = const {},
|
||||||
|
this.spaces = const {},
|
||||||
|
this.sizes = const {},
|
||||||
|
this.surfaces = const {},
|
||||||
|
this.brands = const {},
|
||||||
|
});
|
||||||
|
|
||||||
|
ProductFiltersState copyWith({
|
||||||
|
Set<String>? productLines,
|
||||||
|
Set<String>? spaces,
|
||||||
|
Set<String>? sizes,
|
||||||
|
Set<String>? surfaces,
|
||||||
|
Set<String>? brands,
|
||||||
|
}) {
|
||||||
|
return ProductFiltersState(
|
||||||
|
productLines: productLines ?? this.productLines,
|
||||||
|
spaces: spaces ?? this.spaces,
|
||||||
|
sizes: sizes ?? this.sizes,
|
||||||
|
surfaces: surfaces ?? this.surfaces,
|
||||||
|
brands: brands ?? this.brands,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get total filter count
|
||||||
|
int get totalCount =>
|
||||||
|
productLines.length +
|
||||||
|
spaces.length +
|
||||||
|
sizes.length +
|
||||||
|
surfaces.length +
|
||||||
|
brands.length;
|
||||||
|
|
||||||
|
/// Check if any filters are active
|
||||||
|
bool get hasActiveFilters => totalCount > 0;
|
||||||
|
|
||||||
|
/// Reset all filters
|
||||||
|
ProductFiltersState reset() {
|
||||||
|
return const ProductFiltersState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Product Filters Notifier
|
||||||
|
class ProductFiltersNotifier extends Notifier<ProductFiltersState> {
|
||||||
|
@override
|
||||||
|
ProductFiltersState build() => const ProductFiltersState();
|
||||||
|
|
||||||
|
/// Toggle product line filter
|
||||||
|
void toggleProductLine(String value) {
|
||||||
|
final newSet = Set<String>.from(state.productLines);
|
||||||
|
if (newSet.contains(value)) {
|
||||||
|
newSet.remove(value);
|
||||||
|
} else {
|
||||||
|
newSet.add(value);
|
||||||
|
}
|
||||||
|
state = state.copyWith(productLines: newSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Toggle space filter
|
||||||
|
void toggleSpace(String value) {
|
||||||
|
final newSet = Set<String>.from(state.spaces);
|
||||||
|
if (newSet.contains(value)) {
|
||||||
|
newSet.remove(value);
|
||||||
|
} else {
|
||||||
|
newSet.add(value);
|
||||||
|
}
|
||||||
|
state = state.copyWith(spaces: newSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Toggle size filter
|
||||||
|
void toggleSize(String value) {
|
||||||
|
final newSet = Set<String>.from(state.sizes);
|
||||||
|
if (newSet.contains(value)) {
|
||||||
|
newSet.remove(value);
|
||||||
|
} else {
|
||||||
|
newSet.add(value);
|
||||||
|
}
|
||||||
|
state = state.copyWith(sizes: newSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Toggle surface filter
|
||||||
|
void toggleSurface(String value) {
|
||||||
|
final newSet = Set<String>.from(state.surfaces);
|
||||||
|
if (newSet.contains(value)) {
|
||||||
|
newSet.remove(value);
|
||||||
|
} else {
|
||||||
|
newSet.add(value);
|
||||||
|
}
|
||||||
|
state = state.copyWith(surfaces: newSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Toggle brand filter
|
||||||
|
void toggleBrand(String value) {
|
||||||
|
final newSet = Set<String>.from(state.brands);
|
||||||
|
if (newSet.contains(value)) {
|
||||||
|
newSet.remove(value);
|
||||||
|
} else {
|
||||||
|
newSet.add(value);
|
||||||
|
}
|
||||||
|
state = state.copyWith(brands: newSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reset all filters
|
||||||
|
void reset() {
|
||||||
|
state = const ProductFiltersState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply filters (placeholder for future implementation)
|
||||||
|
void apply() {
|
||||||
|
// TODO: Trigger products provider refresh with filters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Product Filters Provider
|
||||||
|
final productFiltersProvider =
|
||||||
|
NotifierProvider<ProductFiltersNotifier, ProductFiltersState>(
|
||||||
|
ProductFiltersNotifier.new,
|
||||||
|
);
|
||||||
@@ -0,0 +1,311 @@
|
|||||||
|
/// Widget: Product Filter Drawer
|
||||||
|
///
|
||||||
|
/// Right side drawer with product filtering options.
|
||||||
|
library;
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:worker/core/constants/ui_constants.dart';
|
||||||
|
import 'package:worker/core/theme/colors.dart';
|
||||||
|
import 'package:worker/features/products/presentation/providers/product_filters_provider.dart';
|
||||||
|
|
||||||
|
/// Product Filter Drawer Widget
|
||||||
|
///
|
||||||
|
/// A drawer that slides from the right with filter options:
|
||||||
|
/// - Dòng sản phẩm (Product Line)
|
||||||
|
/// - Không gian (Space)
|
||||||
|
/// - Kích thước (Size)
|
||||||
|
/// - Bề mặt (Surface)
|
||||||
|
/// - Thương hiệu (Brand)
|
||||||
|
class ProductFilterDrawer extends ConsumerWidget {
|
||||||
|
const ProductFilterDrawer({super.key});
|
||||||
|
|
||||||
|
// Filter options (from HTML)
|
||||||
|
static const List<FilterOption> _productLines = [
|
||||||
|
FilterOption(value: 'tam-lon', label: 'Tấm lớn'),
|
||||||
|
FilterOption(value: 'third-firing', label: 'Third-Firing'),
|
||||||
|
FilterOption(value: 'outdoor', label: 'Outdoor'),
|
||||||
|
FilterOption(value: 'van-da', label: 'Vân đá'),
|
||||||
|
FilterOption(value: 'xi-mang', label: 'Xi măng'),
|
||||||
|
FilterOption(value: 'van-go', label: 'Vân gỗ'),
|
||||||
|
FilterOption(value: 'xuong-trang', label: 'Xương trắng'),
|
||||||
|
FilterOption(value: 'cam-thach', label: 'Cẩm thạch'),
|
||||||
|
];
|
||||||
|
|
||||||
|
static const List<FilterOption> _spaces = [
|
||||||
|
FilterOption(value: 'phong-khach', label: 'Phòng khách'),
|
||||||
|
FilterOption(value: 'phong-ngu', label: 'Phòng ngủ'),
|
||||||
|
FilterOption(value: 'phong-tam', label: 'Phòng tắm'),
|
||||||
|
FilterOption(value: 'nha-bep', label: 'Nhà bếp'),
|
||||||
|
FilterOption(value: 'khong-gian-khac', label: 'Không gian khác'),
|
||||||
|
];
|
||||||
|
|
||||||
|
static const List<FilterOption> _sizes = [
|
||||||
|
FilterOption(value: '200x1600', label: '200x1600'),
|
||||||
|
FilterOption(value: '1200x2400', label: '1200x2400'),
|
||||||
|
FilterOption(value: '7500x1500', label: '7500x1500'),
|
||||||
|
FilterOption(value: '1200x1200', label: '1200x1200'),
|
||||||
|
FilterOption(value: '600x1200', label: '600x1200'),
|
||||||
|
FilterOption(value: '450x900', label: '450x900'),
|
||||||
|
];
|
||||||
|
|
||||||
|
static const List<FilterOption> _surfaces = [
|
||||||
|
FilterOption(value: 'satin', label: 'SATIN'),
|
||||||
|
FilterOption(value: 'honed', label: 'HONED'),
|
||||||
|
FilterOption(value: 'matt', label: 'MATT'),
|
||||||
|
FilterOption(value: 'polish', label: 'POLISH'),
|
||||||
|
FilterOption(value: 'babyskin', label: 'BABYSKIN'),
|
||||||
|
];
|
||||||
|
|
||||||
|
static const List<FilterOption> _brands = [
|
||||||
|
FilterOption(value: 'eurotile', label: 'Eurotile'),
|
||||||
|
FilterOption(value: 'vasta-stone', label: 'Vasta Stone'),
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final filtersState = ref.watch(productFiltersProvider);
|
||||||
|
|
||||||
|
return Drawer(
|
||||||
|
child: SafeArea(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// Header
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(AppSpacing.lg),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(color: AppColors.grey100, width: 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Bộ lọc sản phẩm',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: AppColors.grey900,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.close),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
color: AppColors.grey500,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Filter Options (Scrollable)
|
||||||
|
Expanded(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(AppSpacing.lg),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Dòng sản phẩm
|
||||||
|
_buildFilterGroup(
|
||||||
|
title: 'Dòng sản phẩm',
|
||||||
|
options: _productLines,
|
||||||
|
selectedValues: filtersState.productLines,
|
||||||
|
onToggle: (value) => ref
|
||||||
|
.read(productFiltersProvider.notifier)
|
||||||
|
.toggleProductLine(value),
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: AppSpacing.lg),
|
||||||
|
|
||||||
|
// Không gian
|
||||||
|
_buildFilterGroup(
|
||||||
|
title: 'Không gian',
|
||||||
|
options: _spaces,
|
||||||
|
selectedValues: filtersState.spaces,
|
||||||
|
onToggle: (value) => ref
|
||||||
|
.read(productFiltersProvider.notifier)
|
||||||
|
.toggleSpace(value),
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: AppSpacing.lg),
|
||||||
|
|
||||||
|
// Kích thước
|
||||||
|
_buildFilterGroup(
|
||||||
|
title: 'Kích thước',
|
||||||
|
options: _sizes,
|
||||||
|
selectedValues: filtersState.sizes,
|
||||||
|
onToggle: (value) => ref
|
||||||
|
.read(productFiltersProvider.notifier)
|
||||||
|
.toggleSize(value),
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: AppSpacing.lg),
|
||||||
|
|
||||||
|
// Bề mặt
|
||||||
|
_buildFilterGroup(
|
||||||
|
title: 'Bề mặt',
|
||||||
|
options: _surfaces,
|
||||||
|
selectedValues: filtersState.surfaces,
|
||||||
|
onToggle: (value) => ref
|
||||||
|
.read(productFiltersProvider.notifier)
|
||||||
|
.toggleSurface(value),
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: AppSpacing.lg),
|
||||||
|
|
||||||
|
// Thương hiệu
|
||||||
|
_buildFilterGroup(
|
||||||
|
title: 'Thương hiệu',
|
||||||
|
options: _brands,
|
||||||
|
selectedValues: filtersState.brands,
|
||||||
|
onToggle: (value) => ref
|
||||||
|
.read(productFiltersProvider.notifier)
|
||||||
|
.toggleBrand(value),
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 100), // Space for footer buttons
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Footer Buttons
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(AppSpacing.lg),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
top: BorderSide(color: AppColors.grey100, width: 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
// Reset Button
|
||||||
|
Expanded(
|
||||||
|
child: OutlinedButton(
|
||||||
|
onPressed: () {
|
||||||
|
ref.read(productFiltersProvider.notifier).reset();
|
||||||
|
},
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
foregroundColor: AppColors.grey900,
|
||||||
|
side: const BorderSide(
|
||||||
|
color: AppColors.grey100,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: AppSpacing.md,
|
||||||
|
),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'Xóa bộ lọc',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: AppSpacing.md),
|
||||||
|
// Apply Button
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
ref.read(productFiltersProvider.notifier).apply();
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
if (filtersState.hasActiveFilters) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
'Đã áp dụng ${filtersState.totalCount} bộ lọc',
|
||||||
|
),
|
||||||
|
duration: const Duration(seconds: 2),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: AppColors.primaryBlue,
|
||||||
|
foregroundColor: AppColors.white,
|
||||||
|
elevation: 0,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: AppSpacing.md,
|
||||||
|
),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'Áp dụng',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFilterGroup({
|
||||||
|
required String title,
|
||||||
|
required List<FilterOption> options,
|
||||||
|
required Set<String> selectedValues,
|
||||||
|
required Function(String) onToggle,
|
||||||
|
}) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: AppColors.grey900,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Column(
|
||||||
|
children: options.map((option) {
|
||||||
|
return CheckboxListTile(
|
||||||
|
title: Text(
|
||||||
|
option.label,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: AppColors.grey900,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
value: selectedValues.contains(option.value),
|
||||||
|
onChanged: (bool? checked) {
|
||||||
|
onToggle(option.value);
|
||||||
|
},
|
||||||
|
controlAffinity: ListTileControlAffinity.leading,
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
dense: true,
|
||||||
|
activeColor: AppColors.primaryBlue,
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Filter Option Model
|
||||||
|
class FilterOption {
|
||||||
|
final String value;
|
||||||
|
final String label;
|
||||||
|
|
||||||
|
const FilterOption({
|
||||||
|
required this.value,
|
||||||
|
required this.label,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -54,9 +54,8 @@ class _ProductSearchBarState extends ConsumerState<ProductSearchBar> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final l10n = AppLocalizations.of(context)!;
|
final l10n = AppLocalizations.of(context)!;
|
||||||
|
|
||||||
return Container(
|
return SizedBox(
|
||||||
height: InputFieldSpecs.height,
|
height: InputFieldSpecs.height,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
|
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
|
|||||||
Reference in New Issue
Block a user