266 lines
6.8 KiB
Dart
266 lines
6.8 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,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|