Files
worker/lib/shared/widgets/price_display.dart
Phuoc Nguyen 628c81ce13 runable
2025-10-17 17:22:28 +07:00

270 lines
6.9 KiB
Dart

/// Price Display Widget
///
/// Formats and displays prices in Vietnamese currency format
library;
import 'package:flutter/material.dart';
import '../../core/utils/formatters.dart';
/// Price display with Vietnamese currency formatting
class PriceDisplay extends StatelessWidget {
final double price;
final TextStyle? style;
final bool showSymbol;
final int decimalDigits;
final Color? color;
final FontWeight? fontWeight;
final double? fontSize;
const PriceDisplay({
super.key,
required this.price,
this.style,
this.showSymbol = true,
this.decimalDigits = 0,
this.color,
this.fontWeight,
this.fontSize,
});
@override
Widget build(BuildContext context) {
final formattedPrice = CurrencyFormatter.formatWithDecimals(
price,
decimalDigits: decimalDigits,
showSymbol: showSymbol,
);
return Text(
formattedPrice,
style: style ??
TextStyle(
color: color,
fontWeight: fontWeight ?? FontWeight.w600,
fontSize: fontSize,
),
);
}
}
/// Price display with sale price comparison
class SalePriceDisplay extends StatelessWidget {
final double originalPrice;
final double salePrice;
final TextStyle? originalPriceStyle;
final TextStyle? salePriceStyle;
final bool showSymbol;
final MainAxisAlignment alignment;
const SalePriceDisplay({
super.key,
required this.originalPrice,
required this.salePrice,
this.originalPriceStyle,
this.salePriceStyle,
this.showSymbol = true,
this.alignment = MainAxisAlignment.start,
});
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: alignment,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
// Sale price (larger, prominent)
Text(
CurrencyFormatter.format(salePrice, showSymbol: showSymbol),
style: salePriceStyle ??
const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.red,
),
),
const SizedBox(width: 8),
// Original price (smaller, strikethrough)
Text(
CurrencyFormatter.format(originalPrice, showSymbol: showSymbol),
style: originalPriceStyle ??
TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Colors.grey[600],
decoration: TextDecoration.lineThrough,
),
),
],
);
}
}
/// Price display with discount percentage badge
class PriceWithDiscount extends StatelessWidget {
final double originalPrice;
final double salePrice;
final bool showSymbol;
final TextStyle? salePriceStyle;
final TextStyle? originalPriceStyle;
const PriceWithDiscount({
super.key,
required this.originalPrice,
required this.salePrice,
this.showSymbol = true,
this.salePriceStyle,
this.originalPriceStyle,
});
double get discountPercentage {
return ((originalPrice - salePrice) / originalPrice * 100);
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
// Sale price
Text(
CurrencyFormatter.format(salePrice, showSymbol: showSymbol),
style: salePriceStyle ??
const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.red,
),
),
const SizedBox(width: 8),
// Discount badge
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(4),
),
child: Text(
'-${discountPercentage.toStringAsFixed(0)}%',
style: const TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
),
const SizedBox(height: 4),
// Original price
Text(
CurrencyFormatter.format(originalPrice, showSymbol: showSymbol),
style: originalPriceStyle ??
TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Colors.grey[600],
decoration: TextDecoration.lineThrough,
),
),
],
);
}
}
/// Compact price display for lists/grids
class CompactPriceDisplay extends StatelessWidget {
final double price;
final double? salePrice;
final bool showSymbol;
const CompactPriceDisplay({
super.key,
required this.price,
this.salePrice,
this.showSymbol = true,
});
@override
Widget build(BuildContext context) {
final bool isOnSale = salePrice != null && salePrice! < price;
if (isOnSale) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
CurrencyFormatter.format(salePrice!, showSymbol: showSymbol),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.red,
),
),
Text(
CurrencyFormatter.format(price, showSymbol: showSymbol),
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
decoration: TextDecoration.lineThrough,
),
),
],
);
}
return Text(
CurrencyFormatter.format(price, showSymbol: showSymbol),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
);
}
}
/// Large price display for checkout/order summary
class LargePriceDisplay extends StatelessWidget {
final double price;
final String? label;
final bool showSymbol;
final Color? color;
const LargePriceDisplay({
super.key,
required this.price,
this.label,
this.showSymbol = true,
this.color,
});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (label != null) ...[
Text(
label!,
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
),
),
const SizedBox(height: 4),
],
Text(
CurrencyFormatter.format(price, showSymbol: showSymbol),
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: color ?? Theme.of(context).primaryColor,
),
),
],
);
}
}