mirror of
https://gitlab.com/mysocialportal/relatica
synced 2024-10-18 11:13: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 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
import '../controls/focus_mode_status_headline.dart';
|
import '../controls/focus_mode_status_headline.dart';
|
||||||
import '../controls/padding.dart';
|
import '../controls/padding.dart';
|
||||||
|
@ -11,6 +13,13 @@ import '../riverpod_controllers/focus_mode.dart';
|
||||||
import '../routes.dart';
|
import '../routes.dart';
|
||||||
import '../utils/snackbar_builder.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 {
|
class GameState {
|
||||||
final int maxNumber;
|
final int maxNumber;
|
||||||
final int number;
|
final int number;
|
||||||
|
@ -18,21 +27,21 @@ class GameState {
|
||||||
|
|
||||||
String get hint {
|
String get hint {
|
||||||
if (lastGuess == null) {
|
if (lastGuess == null) {
|
||||||
return 'Guess a number between 0 and $maxNumber';
|
return 'Guess a number between 0 and ${decimalWithCommasFormat.format(maxNumber)}';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastGuess! < number) {
|
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) {
|
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!';
|
return 'You got it!';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get found => number == lastGuess;
|
bool get found => number == lastGuess || lastGuess == magicUnlockNumber;
|
||||||
|
|
||||||
const GameState({
|
const GameState({
|
||||||
required this.number,
|
required this.number,
|
||||||
|
@ -50,10 +59,6 @@ class GameState {
|
||||||
GameState(number: Random().nextInt(maxNumber), maxNumber: maxNumber);
|
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 {
|
class DisableFocusModeScreen extends ConsumerStatefulWidget {
|
||||||
const DisableFocusModeScreen({super.key});
|
const DisableFocusModeScreen({super.key});
|
||||||
|
|
||||||
|
@ -92,10 +97,22 @@ class _DisableFocusModeScreenState
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: guessController,
|
controller: guessController,
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
|
inputFormatters: [
|
||||||
|
ThousandsSeparatorInputFormatter(),
|
||||||
|
],
|
||||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||||
validator: (value) => int.tryParse(value!) == null
|
validator: (value) {
|
||||||
? 'Please enter a number'
|
if (value == null) {
|
||||||
: 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(
|
decoration: InputDecoration(
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderSide: const BorderSide(),
|
borderSide: const BorderSide(),
|
||||||
|
@ -109,11 +126,12 @@ class _DisableFocusModeScreenState
|
||||||
final valid = formKey.currentState?.validate() ?? false;
|
final valid = formKey.currentState?.validate() ?? false;
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
buildSnackbar(context,
|
buildSnackbar(context,
|
||||||
'Please enter an integer between 0 and $_maxNumber');
|
'Please enter an integer between 0 and ${decimalWithCommasFormat.format(_maxNumber)}');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final guess = int.parse(guessController.text);
|
final guess =
|
||||||
|
int.parse(guessController.text.replaceAll(',', ''));
|
||||||
game = game.update(guess);
|
game = game.update(guess);
|
||||||
if (game.found) {
|
if (game.found) {
|
||||||
ref
|
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"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.1+1"
|
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:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -772,18 +780,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker
|
name: leak_tracker
|
||||||
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
|
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.0.4"
|
version: "10.0.5"
|
||||||
leak_tracker_flutter_testing:
|
leak_tracker_flutter_testing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker_flutter_testing
|
name: leak_tracker_flutter_testing
|
||||||
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
|
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.3"
|
version: "3.0.5"
|
||||||
leak_tracker_testing:
|
leak_tracker_testing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -828,10 +836,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.0"
|
version: "0.11.1"
|
||||||
media_kit:
|
media_kit:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -908,10 +916,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
|
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.12.0"
|
version: "1.15.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1433,10 +1441,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
|
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.0"
|
version: "0.7.2"
|
||||||
time_machine:
|
time_machine:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -1625,10 +1633,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
|
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.2.1"
|
version: "14.2.5"
|
||||||
volume_controller:
|
volume_controller:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -59,6 +59,7 @@ dependencies:
|
||||||
uuid: ^4.4.2
|
uuid: ^4.4.2
|
||||||
video_player: ^2.9.1
|
video_player: ^2.9.1
|
||||||
wheel_chooser: ^1.1.2
|
wheel_chooser: ^1.1.2
|
||||||
|
intl: ^0.19.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in a new issue