diff --git a/analysis_options.yaml b/analysis_options.yaml index 30e5d08..04172d4 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -10,4 +10,5 @@ linter: prefer_const_declarations: true prefer_const_literals_to_create_immutables: true unnecessary_const: true - lines_longer_than_80_chars: false \ No newline at end of file + lines_longer_than_80_chars: false + constant_identifier_names: false \ No newline at end of file diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 4ed41c0..c1bc0fe 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -3,5 +3,20 @@ class Constants { Constants._(); // Private constructor to prevent instantiation /// Minimum duration of all app skeletons - static Duration minimumSkeletonDuration = const Duration(milliseconds: 250); + static const Duration MINIMUM_SKELETON_DURATION = Duration(milliseconds: 250); + + /// Maximum length for player names + static const int MAX_PLAYER_NAME_LENGTH = 32; + + /// Maximum length for group names + static const int MAX_GROUP_NAME_LENGTH = 32; + + /// Maximum length for match names + static const int MAX_MATCH_NAME_LENGTH = 32; + + /// Maximum length for game names + static const int MAX_GAME_NAME_LENGTH = 32; + + /// Maximum length for team names + static const int MAX_TEAM_NAME_LENGTH = 32; } diff --git a/lib/presentation/views/main_menu/group_view/create_group_view.dart b/lib/presentation/views/main_menu/group_view/create_group_view.dart index 719b47d..da7eb1d 100644 --- a/lib/presentation/views/main_menu/group_view/create_group_view.dart +++ b/lib/presentation/views/main_menu/group_view/create_group_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:game_tracker/core/constants.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/core/enums.dart'; import 'package:game_tracker/data/db/database.dart'; @@ -58,6 +59,7 @@ class _CreateGroupViewState extends State { child: TextInputField( controller: _groupNameController, hintText: loc.group_name, + maxLength: Constants.MAX_GROUP_NAME_LENGTH, ), ), Expanded( diff --git a/lib/presentation/views/main_menu/group_view/groups_view.dart b/lib/presentation/views/main_menu/group_view/groups_view.dart index 0083f26..81922f5 100644 --- a/lib/presentation/views/main_menu/group_view/groups_view.dart +++ b/lib/presentation/views/main_menu/group_view/groups_view.dart @@ -126,7 +126,7 @@ class _GroupsViewState extends State { }); Future.wait([ db.groupDao.getAllGroups(), - Future.delayed(Constants.minimumSkeletonDuration), + Future.delayed(Constants.MINIMUM_SKELETON_DURATION), ]).then((results) { loadedGroups = results[0] as List; setState(() { diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart index 2f25d5a..f28341e 100644 --- a/lib/presentation/views/main_menu/home_view.dart +++ b/lib/presentation/views/main_menu/home_view.dart @@ -195,7 +195,7 @@ class _HomeViewState extends State { db.matchDao.getMatchCount(), db.groupDao.getGroupCount(), db.matchDao.getAllMatches(), - Future.delayed(Constants.minimumSkeletonDuration), + Future.delayed(Constants.MINIMUM_SKELETON_DURATION), ]).then((results) { matchCount = results[0] as int; groupCount = results[1] as int; diff --git a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart index 694a82d..ea9cfd5 100644 --- a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart +++ b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/adaptive_page_route.dart'; +import 'package:game_tracker/core/constants.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/core/enums.dart'; import 'package:game_tracker/data/db/database.dart'; @@ -136,6 +137,7 @@ class _CreateMatchViewState extends State { child: TextInputField( controller: _matchNameController, hintText: hintText ?? '', + maxLength: Constants.MAX_MATCH_NAME_LENGTH, ), ), ChooseTile( diff --git a/lib/presentation/views/main_menu/match_view/match_view.dart b/lib/presentation/views/main_menu/match_view/match_view.dart index b656c61..e85bf77 100644 --- a/lib/presentation/views/main_menu/match_view/match_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_view.dart @@ -130,7 +130,7 @@ class _MatchViewState extends State { void loadGames() { Future.wait([ db.matchDao.getAllMatches(), - Future.delayed(Constants.minimumSkeletonDuration), + Future.delayed(Constants.MINIMUM_SKELETON_DURATION), ]).then((results) { if (mounted) { setState(() { diff --git a/lib/presentation/views/main_menu/statistics_view.dart b/lib/presentation/views/main_menu/statistics_view.dart index fc7165d..f87a3fb 100644 --- a/lib/presentation/views/main_menu/statistics_view.dart +++ b/lib/presentation/views/main_menu/statistics_view.dart @@ -106,7 +106,7 @@ class _StatisticsViewState extends State { Future.wait([ db.matchDao.getAllMatches(), db.playerDao.getAllPlayers(), - Future.delayed(Constants.minimumSkeletonDuration), + Future.delayed(Constants.MINIMUM_SKELETON_DURATION), ]).then((results) async { if (!mounted) return; final matches = results[0] as List; diff --git a/lib/presentation/widgets/player_selection.dart b/lib/presentation/widgets/player_selection.dart index 8b2f2c1..587c8af 100644 --- a/lib/presentation/widgets/player_selection.dart +++ b/lib/presentation/widgets/player_selection.dart @@ -219,7 +219,7 @@ class _PlayerSelectionState extends State { void loadPlayerList() { _allPlayersFuture = Future.wait([ db.playerDao.getAllPlayers(), - Future.delayed(Constants.minimumSkeletonDuration), + Future.delayed(Constants.MINIMUM_SKELETON_DURATION), ]).then((results) => results[0] as List); if (mounted) { _allPlayersFuture.then((loadedPlayers) { diff --git a/lib/presentation/widgets/text_input/custom_search_bar.dart b/lib/presentation/widgets/text_input/custom_search_bar.dart index 1b453da..76bb6e5 100644 --- a/lib/presentation/widgets/text_input/custom_search_bar.dart +++ b/lib/presentation/widgets/text_input/custom_search_bar.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:game_tracker/core/constants.dart'; import 'package:game_tracker/core/custom_theme.dart'; class CustomSearchBar extends StatelessWidget { @@ -49,6 +50,15 @@ class CustomSearchBar extends StatelessWidget { @override Widget build(BuildContext context) { + /// Enforce maximum length on the input text + const maxLength = Constants.MAX_PLAYER_NAME_LENGTH; + if (controller.text.length > maxLength) { + controller.text = controller.text.substring(0, maxLength); + controller.selection = TextSelection.fromPosition( + TextPosition(offset: controller.text.length), + ); + } + return SearchBar( controller: controller, constraints: diff --git a/lib/presentation/widgets/text_input/text_input_field.dart b/lib/presentation/widgets/text_input/text_input_field.dart index 7d11767..8f7a597 100644 --- a/lib/presentation/widgets/text_input/text_input_field.dart +++ b/lib/presentation/widgets/text_input/text_input_field.dart @@ -4,29 +4,35 @@ import 'package:game_tracker/core/custom_theme.dart'; class TextInputField extends StatelessWidget { /// A custom text input field widget that encapsulates a [TextField] with specific styling. /// - [controller]: The controller for the text input field. - /// - [onChanged]: The callback invoked when the text in the field changes. + /// - [onChanged]: Optional callback invoked when the text in the field changes. /// - [hintText]: The hint text displayed in the text input field when it is empty + /// - [maxLength]: Optional parameter for maximum length of the input text. const TextInputField({ super.key, required this.controller, required this.hintText, this.onChanged, + this.maxLength, }); /// The controller for the text input field. final TextEditingController controller; - /// The callback invoked when the text in the field changes. + /// Optional callback invoked when the text in the field changes. final ValueChanged? onChanged; /// The hint text displayed in the text input field when it is empty. final String hintText; + /// Optional parameter for maximum length of the input text. + final int? maxLength; + @override Widget build(BuildContext context) { return TextField( controller: controller, onChanged: onChanged, + maxLength: maxLength, decoration: InputDecoration( filled: true, fillColor: CustomTheme.boxColor, diff --git a/pubspec.yaml b/pubspec.yaml index 8b52ca1..6f6fd9b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.8+231 +version: 0.0.8+232 environment: sdk: ^3.8.1