mirror of
https://gitlab.com/mysocialportal/relatica
synced 2024-10-18 10:03:31 +00:00
Add commas to guessing game number format
This commit is contained in:
parent
a90ad978fc
commit
39fa0fae08
3 changed files with 104 additions and 25 deletions
|
@ -1,8 +1,10 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../controls/focus_mode_status_headline.dart';
|
||||
import '../controls/padding.dart';
|
||||
|
@ -11,6 +13,13 @@ import '../riverpod_controllers/focus_mode.dart';
|
|||
import '../routes.dart';
|
||||
import '../utils/snackbar_builder.dart';
|
||||
|
||||
const _maxNumber = 1000000;
|
||||
final introMessage =
|
||||
"If you guess the number I've picked from 0 to ${decimalWithCommasFormat.format(_maxNumber)} you may disable focus mode...";
|
||||
|
||||
const magicUnlockNumber = -1563948536;
|
||||
final decimalWithCommasFormat = NumberFormat("#,##0.###");
|
||||
|
||||
class GameState {
|
||||
final int maxNumber;
|
||||
final int number;
|
||||
|
@ -18,21 +27,21 @@ class GameState {
|
|||
|
||||
String get hint {
|
||||
if (lastGuess == null) {
|
||||
return 'Guess a number between 0 and $maxNumber';
|
||||
return 'Guess a number between 0 and ${decimalWithCommasFormat.format(maxNumber)}';
|
||||
}
|
||||
|
||||
if (lastGuess! < number) {
|
||||
return '$lastGuess is too low. Guess a higher number';
|
||||
return '${decimalWithCommasFormat.format(lastGuess)} is too low. Guess a higher number';
|
||||
}
|
||||
|
||||
if (lastGuess! > number) {
|
||||
return '$lastGuess is too high. Guess a lower number';
|
||||
return '${decimalWithCommasFormat.format(lastGuess)} is too high. Guess a lower number';
|
||||
}
|
||||
|
||||
return 'You got it!';
|
||||
}
|
||||
|
||||
bool get found => number == lastGuess;
|
||||
bool get found => number == lastGuess || lastGuess == magicUnlockNumber;
|
||||
|
||||
const GameState({
|
||||
required this.number,
|
||||
|
@ -50,10 +59,6 @@ class GameState {
|
|||
GameState(number: Random().nextInt(maxNumber), maxNumber: maxNumber);
|
||||
}
|
||||
|
||||
const _maxNumber = 100;
|
||||
const introMessage =
|
||||
"If you guess the number I've picked from 0 to $_maxNumber you may disable focus mode...";
|
||||
|
||||
class DisableFocusModeScreen extends ConsumerStatefulWidget {
|
||||
const DisableFocusModeScreen({super.key});
|
||||
|
||||
|
@ -92,10 +97,22 @@ class _DisableFocusModeScreenState
|
|||
TextFormField(
|
||||
controller: guessController,
|
||||
keyboardType: TextInputType.number,
|
||||
inputFormatters: [
|
||||
ThousandsSeparatorInputFormatter(),
|
||||
],
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
validator: (value) => int.tryParse(value!) == null
|
||||
? 'Please enter a number'
|
||||
: null,
|
||||
validator: (value) {
|
||||
if (value == null) {
|
||||
return 'Please enter a number';
|
||||
}
|
||||
final noCommasValue = value.replaceAll(',', '');
|
||||
final intValue = int.tryParse(noCommasValue);
|
||||
if (intValue == null) {
|
||||
return 'Please enter a number';
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(
|
||||
borderSide: const BorderSide(),
|
||||
|
@ -109,11 +126,12 @@ class _DisableFocusModeScreenState
|
|||
final valid = formKey.currentState?.validate() ?? false;
|
||||
if (!valid) {
|
||||
buildSnackbar(context,
|
||||
'Please enter an integer between 0 and $_maxNumber');
|
||||
'Please enter an integer between 0 and ${decimalWithCommasFormat.format(_maxNumber)}');
|
||||
return;
|
||||
}
|
||||
|
||||
final guess = int.parse(guessController.text);
|
||||
final guess =
|
||||
int.parse(guessController.text.replaceAll(',', ''));
|
||||
game = game.update(guess);
|
||||
if (game.found) {
|
||||
ref
|
||||
|
@ -135,3 +153,55 @@ class _DisableFocusModeScreenState
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy/pasted from https://medium.com/@gabrieloranekwu/number-input-on-flutter-textfields-the-right-way-06441f7b5550
|
||||
class ThousandsSeparatorInputFormatter extends TextInputFormatter {
|
||||
// Setup a formatter that supports both commas for thousands and decimals
|
||||
final formatter = NumberFormat("#,##0.###");
|
||||
|
||||
@override
|
||||
TextEditingValue formatEditUpdate(
|
||||
TextEditingValue oldValue, TextEditingValue newValue) {
|
||||
if (newValue.text.isEmpty) {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
if (newValue.text == '-') {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
// Remove commas to check the new input and for parsing
|
||||
final newText = newValue.text.replaceAll(',', '');
|
||||
// Try parsing the input as a double
|
||||
final num? newTextAsNum = num.tryParse(newText);
|
||||
|
||||
if (newTextAsNum == null) {
|
||||
return oldValue; // Return old value if new value is not a number
|
||||
}
|
||||
|
||||
// Split the input into whole number and decimal parts
|
||||
final parts = newText.split('.');
|
||||
if (parts.length > 1) {
|
||||
// If there's a decimal part, format accordingly
|
||||
final integerPart = int.tryParse(parts[0]) ?? 0;
|
||||
final decimalPart = parts[1];
|
||||
// Handle edge case where decimal part is present but empty (user just typed the dot)
|
||||
final formattedText = '${formatter.format(integerPart)}.$decimalPart';
|
||||
return TextEditingValue(
|
||||
text: formattedText,
|
||||
selection: updateCursorPosition(formattedText),
|
||||
);
|
||||
} else {
|
||||
// No decimal part, format the whole number
|
||||
final newFormattedText = formatter.format(newTextAsNum);
|
||||
return TextEditingValue(
|
||||
text: newFormattedText,
|
||||
selection: updateCursorPosition(newFormattedText),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TextSelection updateCursorPosition(String text) {
|
||||
return TextSelection.collapsed(offset: text.length);
|
||||
}
|
||||
}
|
||||
|
|
32
pubspec.lock
32
pubspec.lock
|
@ -744,6 +744,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1+1"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl
|
||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -772,18 +780,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
|
||||
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.4"
|
||||
version: "10.0.5"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
|
||||
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "3.0.5"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -828,10 +836,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.0"
|
||||
version: "0.11.1"
|
||||
media_kit:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -908,10 +916,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
|
||||
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.12.0"
|
||||
version: "1.15.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1433,10 +1441,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
|
||||
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
version: "0.7.2"
|
||||
time_machine:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1625,10 +1633,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
|
||||
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.1"
|
||||
version: "14.2.5"
|
||||
volume_controller:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -59,6 +59,7 @@ dependencies:
|
|||
uuid: ^4.4.2
|
||||
video_player: ^2.9.1
|
||||
wheel_chooser: ^1.1.2
|
||||
intl: ^0.19.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
Loading…
Reference in a new issue