Merge remote-tracking branch 'origin/development' into bug/162-text-overflows-durch-tastatur
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m6s
Pull Request Pipeline / lint (pull_request) Successful in 2m9s

# Conflicts:
#	pubspec.yaml
This commit is contained in:
2026-01-17 14:44:49 +01:00
12 changed files with 46 additions and 10 deletions

View File

@@ -10,4 +10,5 @@ linter:
prefer_const_declarations: true prefer_const_declarations: true
prefer_const_literals_to_create_immutables: true prefer_const_literals_to_create_immutables: true
unnecessary_const: true unnecessary_const: true
lines_longer_than_80_chars: false lines_longer_than_80_chars: false
constant_identifier_names: false

View File

@@ -3,5 +3,20 @@ class Constants {
Constants._(); // Private constructor to prevent instantiation Constants._(); // Private constructor to prevent instantiation
/// Minimum duration of all app skeletons /// 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;
} }

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; 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/custom_theme.dart';
import 'package:game_tracker/core/enums.dart'; import 'package:game_tracker/core/enums.dart';
import 'package:game_tracker/data/db/database.dart'; import 'package:game_tracker/data/db/database.dart';
@@ -59,6 +60,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
child: TextInputField( child: TextInputField(
controller: _groupNameController, controller: _groupNameController,
hintText: loc.group_name, hintText: loc.group_name,
maxLength: Constants.MAX_GROUP_NAME_LENGTH,
), ),
), ),
Expanded( Expanded(

View File

@@ -107,7 +107,7 @@ class _GroupsViewState extends State<GroupsView> {
void loadGroups() { void loadGroups() {
Future.wait([ Future.wait([
db.groupDao.getAllGroups(), db.groupDao.getAllGroups(),
Future.delayed(Constants.minimumSkeletonDuration), Future.delayed(Constants.MINIMUM_SKELETON_DURATION),
]).then((results) { ]).then((results) {
loadedGroups = results[0] as List<Group>; loadedGroups = results[0] as List<Group>;
setState(() { setState(() {

View File

@@ -195,7 +195,7 @@ class _HomeViewState extends State<HomeView> {
db.matchDao.getMatchCount(), db.matchDao.getMatchCount(),
db.groupDao.getGroupCount(), db.groupDao.getGroupCount(),
db.matchDao.getAllMatches(), db.matchDao.getAllMatches(),
Future.delayed(Constants.minimumSkeletonDuration), Future.delayed(Constants.MINIMUM_SKELETON_DURATION),
]).then((results) { ]).then((results) {
matchCount = results[0] as int; matchCount = results[0] as int;
groupCount = results[1] as int; groupCount = results[1] as int;

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:game_tracker/core/adaptive_page_route.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/custom_theme.dart';
import 'package:game_tracker/core/enums.dart'; import 'package:game_tracker/core/enums.dart';
import 'package:game_tracker/data/db/database.dart'; import 'package:game_tracker/data/db/database.dart';
@@ -137,6 +138,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
child: TextInputField( child: TextInputField(
controller: _matchNameController, controller: _matchNameController,
hintText: hintText ?? '', hintText: hintText ?? '',
maxLength: Constants.MAX_MATCH_NAME_LENGTH,
), ),
), ),
ChooseTile( ChooseTile(

View File

@@ -130,7 +130,7 @@ class _MatchViewState extends State<MatchView> {
void loadGames() { void loadGames() {
Future.wait([ Future.wait([
db.matchDao.getAllMatches(), db.matchDao.getAllMatches(),
Future.delayed(Constants.minimumSkeletonDuration), Future.delayed(Constants.MINIMUM_SKELETON_DURATION),
]).then((results) { ]).then((results) {
if (mounted) { if (mounted) {
setState(() { setState(() {

View File

@@ -106,7 +106,7 @@ class _StatisticsViewState extends State<StatisticsView> {
Future.wait([ Future.wait([
db.matchDao.getAllMatches(), db.matchDao.getAllMatches(),
db.playerDao.getAllPlayers(), db.playerDao.getAllPlayers(),
Future.delayed(Constants.minimumSkeletonDuration), Future.delayed(Constants.MINIMUM_SKELETON_DURATION),
]).then((results) async { ]).then((results) async {
if (!mounted) return; if (!mounted) return;
final matches = results[0] as List<Match>; final matches = results[0] as List<Match>;

View File

@@ -219,7 +219,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
void loadPlayerList() { void loadPlayerList() {
_allPlayersFuture = Future.wait([ _allPlayersFuture = Future.wait([
db.playerDao.getAllPlayers(), db.playerDao.getAllPlayers(),
Future.delayed(Constants.minimumSkeletonDuration), Future.delayed(Constants.MINIMUM_SKELETON_DURATION),
]).then((results) => results[0] as List<Player>); ]).then((results) => results[0] as List<Player>);
if (mounted) { if (mounted) {
_allPlayersFuture.then((loadedPlayers) { _allPlayersFuture.then((loadedPlayers) {

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; 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/custom_theme.dart';
class CustomSearchBar extends StatelessWidget { class CustomSearchBar extends StatelessWidget {
@@ -49,6 +50,15 @@ class CustomSearchBar extends StatelessWidget {
@override @override
Widget build(BuildContext context) { 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( return SearchBar(
controller: controller, controller: controller,
constraints: constraints:

View File

@@ -4,29 +4,35 @@ import 'package:game_tracker/core/custom_theme.dart';
class TextInputField extends StatelessWidget { class TextInputField extends StatelessWidget {
/// A custom text input field widget that encapsulates a [TextField] with specific styling. /// A custom text input field widget that encapsulates a [TextField] with specific styling.
/// - [controller]: The controller for the text input field. /// - [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 /// - [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({ const TextInputField({
super.key, super.key,
required this.controller, required this.controller,
required this.hintText, required this.hintText,
this.onChanged, this.onChanged,
this.maxLength,
}); });
/// The controller for the text input field. /// The controller for the text input field.
final TextEditingController controller; 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<String>? onChanged; final ValueChanged<String>? onChanged;
/// The hint text displayed in the text input field when it is empty. /// The hint text displayed in the text input field when it is empty.
final String hintText; final String hintText;
/// Optional parameter for maximum length of the input text.
final int? maxLength;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return TextField( return TextField(
controller: controller, controller: controller,
onChanged: onChanged, onChanged: onChanged,
maxLength: maxLength,
decoration: InputDecoration( decoration: InputDecoration(
filled: true, filled: true,
fillColor: CustomTheme.boxColor, fillColor: CustomTheme.boxColor,

View File

@@ -1,7 +1,7 @@
name: game_tracker name: game_tracker
description: "Game Tracking App for Card Games" description: "Game Tracking App for Card Games"
publish_to: 'none' publish_to: 'none'
version: 0.0.8+213 version: 0.0.8+214
environment: environment:
sdk: ^3.8.1 sdk: ^3.8.1