Merge branch 'development' into feature/168-teamspiele-implementieren

# Conflicts:
#	lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart
#	lib/presentation/views/main_menu/match_view/match_detail_view.dart
#	lib/presentation/views/main_menu/match_view/match_result_view.dart
#	lib/presentation/widgets/buttons/main_menu_button.dart
#	pubspec.yaml
This commit is contained in:
2026-05-18 01:06:46 +02:00
39 changed files with 846 additions and 380 deletions

View File

@@ -7,6 +7,7 @@ import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/models/game.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/views/main_menu/match_view/create_match/create_game_view.dart';
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
import 'package:tallee/presentation/widgets/tiles/game_tile.dart';
import 'package:tallee/presentation/widgets/top_centered_message.dart';
@@ -70,7 +71,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
backgroundColor: CustomTheme.backgroundColor,
resizeToAvoidBottomInset: false,
appBar: AppBar(
leading: IconButton(
leading: HapticIconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: () {
Navigator.of(context).pop(
@@ -83,7 +84,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
},
),
actions: [
IconButton(
HapticIconButton(
icon: const Icon(Icons.add),
onPressed: () async {
final result = await Navigator.push(

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/data/models/group.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
import 'package:tallee/presentation/widgets/tiles/group_tile.dart';
import 'package:tallee/presentation/widgets/top_centered_message.dart';
@@ -45,7 +46,7 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
backgroundColor: CustomTheme.backgroundColor,
resizeToAvoidBottomInset: false,
appBar: AppBar(
leading: IconButton(
leading: HapticIconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: () {
Navigator.of(context).pop(
@@ -111,7 +112,10 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
padding: const EdgeInsets.only(bottom: 85),
itemCount: filteredGroups.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
return GroupTile(
group: filteredGroups[index],
isHighlighted:
selectedGroupId == filteredGroups[index].id,
onTap: () {
setState(() {
if (selectedGroupId != filteredGroups[index].id) {
@@ -121,11 +125,6 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
}
});
},
child: GroupTile(
group: filteredGroups[index],
isHighlighted:
selectedGroupId == filteredGroups[index].id,
),
);
},
),

View File

@@ -1,6 +1,7 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_popup/flutter_popup.dart';
import 'package:provider/provider.dart';
import 'package:tallee/core/common.dart';
@@ -12,6 +13,7 @@ import 'package:tallee/data/models/game.dart';
import 'package:tallee/data/models/group.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart';
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
import 'package:tallee/presentation/widgets/dialog/custom_alert_dialog.dart';
import 'package:tallee/presentation/widgets/dialog/custom_dialog_action.dart';
import 'package:tallee/presentation/widgets/text_input/text_input_field.dart';
@@ -47,9 +49,9 @@ class _CreateGameViewState extends State<CreateGameView> {
late final AppDatabase db;
late List<(Ruleset, String)> _rulesets;
Ruleset? selectedRuleset = Ruleset.singleWinner;
late List<(GameColor, String)> _colors;
Ruleset? selectedRuleset = Ruleset.singleWinner;
GameColor? selectedColor = GameColor.orange;
/// Controller for the game name input field.
@@ -77,38 +79,20 @@ class _CreateGameViewState extends State<CreateGameView> {
@override
void didChangeDependencies() {
super.didChangeDependencies();
_rulesets = [
(
Ruleset.singleWinner,
translateRulesetToString(Ruleset.singleWinner, context),
_rulesets = List.generate(
Ruleset.values.length,
(index) => (
Ruleset.values[index],
translateRulesetToString(Ruleset.values[index], context),
),
(
Ruleset.singleLoser,
translateRulesetToString(Ruleset.singleLoser, context),
);
_colors = List.generate(
GameColor.values.length,
(index) => (
GameColor.values[index],
translateGameColorToString(GameColor.values[index], context),
),
(
Ruleset.highestScore,
translateRulesetToString(Ruleset.highestScore, context),
),
(
Ruleset.lowestScore,
translateRulesetToString(Ruleset.lowestScore, context),
),
(
Ruleset.multipleWinners,
translateRulesetToString(Ruleset.multipleWinners, context),
),
];
_colors = [
(GameColor.green, translateGameColorToString(GameColor.green, context)),
(GameColor.teal, translateGameColorToString(GameColor.teal, context)),
(GameColor.blue, translateGameColorToString(GameColor.blue, context)),
(GameColor.purple, translateGameColorToString(GameColor.purple, context)),
(GameColor.pink, translateGameColorToString(GameColor.pink, context)),
(GameColor.red, translateGameColorToString(GameColor.red, context)),
(GameColor.orange, translateGameColorToString(GameColor.orange, context)),
(GameColor.yellow, translateGameColorToString(GameColor.yellow, context)),
];
);
if (widget.gameToEdit != null) {
_gameNameController.text = widget.gameToEdit!.name;
@@ -138,7 +122,7 @@ class _CreateGameViewState extends State<CreateGameView> {
title: Text(isEditing ? loc.edit_game : loc.create_game),
actions: [
if (isEditMode())
IconButton(
HapticIconButton(
icon: const Icon(Icons.delete),
onPressed: () async {
if (!context.mounted) return;
@@ -214,10 +198,13 @@ class _CreateGameViewState extends State<CreateGameView> {
// Choose ruleset tile
if (!isEditMode())
ChooseTile(title: loc.ruleset, trailing: getColorDropdown(loc)),
ChooseTile(
title: loc.ruleset,
trailing: getRulesetDropdown(loc),
),
// Choose color tile
ChooseTile(title: loc.color, trailing: getRulesetDropdown(loc)),
ChooseTile(title: loc.color, trailing: getColorDropdown(loc)),
// Description input field
Container(
@@ -344,6 +331,12 @@ class _CreateGameViewState extends State<CreateGameView> {
contentPadding: const EdgeInsets.symmetric(horizontal: 0, vertical: 10),
barrierColor: Colors.transparent,
contentDecoration: CustomTheme.standardBoxDecoration,
onBeforePopup: () async {
await HapticFeedback.selectionClick();
},
onAfterPopup: () async {
await HapticFeedback.selectionClick();
},
content: StatefulBuilder(
builder: (context, setPopupState) => SizedBox(
width: 280,
@@ -353,7 +346,8 @@ class _CreateGameViewState extends State<CreateGameView> {
children: List.generate(
_rulesets.length,
(index) => GestureDetector(
onTap: () {
onTap: () async {
await HapticFeedback.selectionClick();
setState(() {
selectedRuleset = _rulesets[index].$1;
});
@@ -427,6 +421,12 @@ class _CreateGameViewState extends State<CreateGameView> {
contentPadding: const EdgeInsets.symmetric(horizontal: 0, vertical: 10),
barrierColor: Colors.transparent,
contentDecoration: CustomTheme.standardBoxDecoration,
onBeforePopup: () async {
await HapticFeedback.selectionClick();
},
onAfterPopup: () async {
await HapticFeedback.selectionClick();
},
content: StatefulBuilder(
builder: (context, setPopupState) => SizedBox(
width: 150,
@@ -436,7 +436,8 @@ class _CreateGameViewState extends State<CreateGameView> {
children: List.generate(
_colors.length,
(index) => GestureDetector(
onTap: () {
onTap: () async {
await HapticFeedback.selectionClick();
setState(() {
selectedColor = _colors[index].$1;
});

View File

@@ -273,11 +273,11 @@ class _CreateMatchViewState extends State<CreateMatchView> {
/// Determines whether the "Create Match" button should be enabled.
///
/// Returns `true` if:
/// - A ruleset is selected AND
/// - A game is selected AND
/// - Either a group is selected OR at least 2 players are selected.
bool isSubmitButtonEnabled() {
return (selectedGroup != null ||
(selectedPlayers.length > 1) && selectedGame != null);
return ((selectedGroup != null || selectedPlayers.length > 1) &&
selectedGame != null);
}
/// Handles navigation when the create or save button is pressed.