💄 Optimize lotteries

This commit is contained in:
2025-10-25 00:29:36 +08:00
parent cdf1413fe0
commit eeae865cc8
2 changed files with 60 additions and 36 deletions

View File

@@ -1258,6 +1258,7 @@
"messageSentAt": "Sent at {}", "messageSentAt": "Sent at {}",
"myTickets": "My Tickets", "myTickets": "My Tickets",
"drawHistory": "Draw History", "drawHistory": "Draw History",
"lottery": "Lottery",
"noLotteryTickets": "No lottery tickets yet", "noLotteryTickets": "No lottery tickets yet",
"buyYourFirstTicket": "Buy your first lottery ticket to get started!", "buyYourFirstTicket": "Buy your first lottery ticket to get started!",
"buyTicket": "Buy Ticket", "buyTicket": "Buy Ticket",
@@ -1272,7 +1273,7 @@
"noDrawHistory": "No draw history yet", "noDrawHistory": "No draw history yet",
"buyLotteryTicket": "Buy Lottery Ticket", "buyLotteryTicket": "Buy Lottery Ticket",
"selectNumbers": "Select Numbers", "selectNumbers": "Select Numbers",
"select5UniqueNumbers": "Select 5 unique numbers (0-99)", "select5UniqueNumbers": "Select 5 unique numbers",
"selectSpecialNumber": "Select Special Number", "selectSpecialNumber": "Select Special Number",
"selectMultiplier": "Select Multiplier", "selectMultiplier": "Select Multiplier",
"baseCost": "Base Cost", "baseCost": "Base Cost",
@@ -1285,5 +1286,9 @@
"totalTickets": "Total Tickets", "totalTickets": "Total Tickets",
"totalWinners": "Total Winners", "totalWinners": "Total Winners",
"prizePool": "Prize Pool", "prizePool": "Prize Pool",
"enterPinToConfirmPayment": "Enter your PIN code to confirm payment" "enterPinToConfirmPayment": "Enter your PIN code to confirm payment",
"purchase": "Purchase",
"multiplierLabel": "Multiplier",
"specialOnly": "Special Only",
"matches": "Matches"
} }

View File

@@ -293,14 +293,23 @@ class LotteryTicketsList extends HookConsumerWidget {
final numbers = <Widget>[]; final numbers = <Widget>[];
// Check if any numbers matched // Check if any numbers matched
bool hasAnyMatch = false; bool hasAnyMatch =
ticket.matchedRegionOneNumbers != null &&
ticket.matchedRegionOneNumbers!.isNotEmpty;
// Add region one numbers // Add region one numbers
for (final number in ticket.regionOneNumbers) { for (final number in ticket.regionOneNumbers) {
final isMatched = final isMatched =
ticket.matchedRegionOneNumbers?.contains(number) ?? false; ticket.matchedRegionOneNumbers?.contains(number) ?? false;
if (isMatched) hasAnyMatch = true; if (isMatched) hasAnyMatch = true;
numbers.add(_buildNumberWidget(context, number, isMatched: isMatched)); numbers.add(
_buildNumberWidget(
context,
number,
isMatched: isMatched,
allUnmatched: !hasAnyMatch && ticket.drawStatus >= 1,
),
);
} }
// Add region two number // Add region two number
@@ -313,28 +322,15 @@ class LotteryTicketsList extends HookConsumerWidget {
ticket.regionTwoNumber, ticket.regionTwoNumber,
isMatched: isSpecialMatched, isMatched: isSpecialMatched,
isSpecial: true, isSpecial: true,
allUnmatched: !hasAnyMatch && ticket.drawStatus >= 1,
), ),
); );
final wrapWidget = Wrap( return Wrap(
spacing: 6, spacing: 6,
crossAxisAlignment: WrapCrossAlignment.center, crossAxisAlignment: WrapCrossAlignment.center,
children: numbers, children: numbers,
); );
// If no numbers matched and ticket is drawn, apply red background
if (!hasAnyMatch && ticket.drawStatus >= 1) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: wrapWidget,
);
}
return wrapWidget;
} }
Widget _buildNumberWidget( Widget _buildNumberWidget(
@@ -342,6 +338,7 @@ class LotteryTicketsList extends HookConsumerWidget {
int number, { int number, {
bool isMatched = false, bool isMatched = false,
bool isSpecial = false, bool isSpecial = false,
bool allUnmatched = false,
}) { }) {
Color backgroundColor; Color backgroundColor;
Color textColor; Color textColor;
@@ -364,6 +361,17 @@ class LotteryTicketsList extends HookConsumerWidget {
isSpecial isSpecial
? Theme.of(context).colorScheme.secondary ? Theme.of(context).colorScheme.secondary
: Theme.of(context).colorScheme.outline.withOpacity(0.3); : Theme.of(context).colorScheme.outline.withOpacity(0.3);
// Blend with red if all numbers are unmatched
if (allUnmatched) {
backgroundColor = Color.alphaBlend(
Colors.red.withOpacity(0.3),
backgroundColor,
);
if (!isSpecial) {
textColor = Color.alphaBlend(Colors.red.withOpacity(0.5), textColor);
}
}
} }
return Container( return Container(
@@ -548,7 +556,7 @@ class _LotteryPurchaseSheetState extends State<LotteryPurchaseSheet> {
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
), ),
), ),
const Gap(8), const Gap(16),
_buildMultiplierSelector(), _buildMultiplierSelector(),
const Gap(16), const Gap(16),
@@ -667,7 +675,7 @@ class _LotteryPurchaseSheetState extends State<LotteryPurchaseSheet> {
selectedNumbers.last == number && selectedNumbers.last == number &&
selectedNumbers.length == 6; selectedNumbers.length == 6;
return InkWell( return GestureDetector(
onTap: () => _toggleNumber(number), onTap: () => _toggleNumber(number),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -714,7 +722,8 @@ class _LotteryPurchaseSheetState extends State<LotteryPurchaseSheet> {
initialValue: multiplier.toString(), initialValue: multiplier.toString(),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Multiplier (1-10)', labelText: 'multiplierLabel'.tr(),
prefixText: 'x',
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
contentPadding: const EdgeInsets.symmetric( contentPadding: const EdgeInsets.symmetric(
horizontal: 16, horizontal: 16,
@@ -723,7 +732,7 @@ class _LotteryPurchaseSheetState extends State<LotteryPurchaseSheet> {
), ),
onChanged: (value) { onChanged: (value) {
final parsed = int.tryParse(value); final parsed = int.tryParse(value);
if (parsed != null && parsed >= 1 && parsed <= 10) { if (parsed != null && parsed >= 1) {
setState(() => multiplier = parsed); setState(() => multiplier = parsed);
} }
}, },
@@ -741,18 +750,24 @@ class _LotteryPurchaseSheetState extends State<LotteryPurchaseSheet> {
} }
Widget _buildPrizeStructure() { Widget _buildPrizeStructure() {
final prizeStructure = { // Base rewards for matched numbers (0-5)
'5+Special': '1000000.00', final baseRewards = [0, 10, 100, 500, 1000, 10000];
'5': '100000.00',
'4+Special': '5000.00', final prizeStructure = <String, String>{};
'4': '500.00',
'3+Special': '100.00', // Generate prize structure for 0-5 matches with and without special
'3': '50.00', for (int matches = 5; matches >= 0; matches--) {
'2+Special': '10.00', final baseReward = baseRewards[matches];
'2': '5.00',
'1+Special': '2.00', // With special number match (x10 multiplier)
'0+Special': '1.00', final specialReward = baseReward * 10;
}; prizeStructure['$matches+Special'] = specialReward.toStringAsFixed(2);
// Without special number match
if (matches > 0) {
prizeStructure[matches.toString()] = baseReward.toStringAsFixed(2);
}
}
return Card( return Card(
child: Padding( child: Padding(
@@ -765,7 +780,11 @@ class _LotteryPurchaseSheetState extends State<LotteryPurchaseSheet> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text(entry.key.tr()), Text(
entry.key == '0+Special'
? 'specialOnly'.tr()
: entry.key.tr(),
),
Text( Text(
'${entry.value} ${'walletCurrencyShortPoints'.tr()}', '${entry.value} ${'walletCurrencyShortPoints'.tr()}',
), ),