feat: implemented team organsation
This commit is contained in:
@@ -26,6 +26,7 @@
|
|||||||
"create_new_group": "Neue Gruppe erstellen",
|
"create_new_group": "Neue Gruppe erstellen",
|
||||||
"create_new_match": "Neues Spiel erstellen",
|
"create_new_match": "Neues Spiel erstellen",
|
||||||
"created_on": "Erstellt am",
|
"created_on": "Erstellt am",
|
||||||
|
"create_teams": "Teams erstellen",
|
||||||
"data": "Daten",
|
"data": "Daten",
|
||||||
"data_successfully_deleted": "Daten erfolgreich gelöscht",
|
"data_successfully_deleted": "Daten erfolgreich gelöscht",
|
||||||
"data_successfully_exported": "Daten erfolgreich exportiert",
|
"data_successfully_exported": "Daten erfolgreich exportiert",
|
||||||
@@ -49,6 +50,7 @@
|
|||||||
"edit_game": "Spielvorlage bearbeiten",
|
"edit_game": "Spielvorlage bearbeiten",
|
||||||
"edit_group": "Gruppe bearbeiten",
|
"edit_group": "Gruppe bearbeiten",
|
||||||
"edit_match": "Gruppe bearbeiten",
|
"edit_match": "Gruppe bearbeiten",
|
||||||
|
"edit_members": "Mitglieder bearbeiten",
|
||||||
"enter_points": "Punkte eingeben",
|
"enter_points": "Punkte eingeben",
|
||||||
"enter_results": "Ergebnisse eintragen",
|
"enter_results": "Ergebnisse eintragen",
|
||||||
"error_creating_group": "Fehler beim Erstellen der Gruppe, bitte erneut versuchen",
|
"error_creating_group": "Fehler beim Erstellen der Gruppe, bitte erneut versuchen",
|
||||||
@@ -108,6 +110,7 @@
|
|||||||
"privacy_policy": "Datenschutzerklärung",
|
"privacy_policy": "Datenschutzerklärung",
|
||||||
"quick_create": "Schnellzugriff",
|
"quick_create": "Schnellzugriff",
|
||||||
"recent_matches": "Letzte Spiele",
|
"recent_matches": "Letzte Spiele",
|
||||||
|
"redistribute": "Neu verteilen",
|
||||||
"result": "Ergebnis",
|
"result": "Ergebnis",
|
||||||
"results": "Ergebnisse",
|
"results": "Ergebnisse",
|
||||||
"ruleset": "Regelwerk",
|
"ruleset": "Regelwerk",
|
||||||
@@ -133,6 +136,7 @@
|
|||||||
"statistics": "Statistiken",
|
"statistics": "Statistiken",
|
||||||
"stats": "Statistiken",
|
"stats": "Statistiken",
|
||||||
"successfully_added_player": "Spieler:in {playerName} erfolgreich hinzugefügt",
|
"successfully_added_player": "Spieler:in {playerName} erfolgreich hinzugefügt",
|
||||||
|
"team": "Team",
|
||||||
"teams": "Teams",
|
"teams": "Teams",
|
||||||
"there_are_no_games_matching_your_search": "Es gibt keine Spielvorlagen, die deiner Suche entspricht",
|
"there_are_no_games_matching_your_search": "Es gibt keine Spielvorlagen, die deiner Suche entspricht",
|
||||||
"there_is_no_group_matching_your_search": "Es gibt keine Gruppe, die deiner Suche entspricht",
|
"there_is_no_group_matching_your_search": "Es gibt keine Gruppe, die deiner Suche entspricht",
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
"create_new_group": "Create new group",
|
"create_new_group": "Create new group",
|
||||||
"created_on": "Created on",
|
"created_on": "Created on",
|
||||||
"create_new_match": "Create new match",
|
"create_new_match": "Create new match",
|
||||||
|
"create_teams": "Create teams",
|
||||||
"data": "Data",
|
"data": "Data",
|
||||||
"data_successfully_deleted": "Data successfully deleted",
|
"data_successfully_deleted": "Data successfully deleted",
|
||||||
"data_successfully_exported": "Data successfully exported",
|
"data_successfully_exported": "Data successfully exported",
|
||||||
@@ -50,6 +51,7 @@
|
|||||||
"edit_game": "Edit Game",
|
"edit_game": "Edit Game",
|
||||||
"edit_group": "Edit Group",
|
"edit_group": "Edit Group",
|
||||||
"edit_match": "Edit Match",
|
"edit_match": "Edit Match",
|
||||||
|
"edit_members": "Edit Members",
|
||||||
"enter_points": "Enter points",
|
"enter_points": "Enter points",
|
||||||
"enter_results": "Enter Results",
|
"enter_results": "Enter Results",
|
||||||
"error_creating_group": "Error while creating group, please try again",
|
"error_creating_group": "Error while creating group, please try again",
|
||||||
@@ -109,6 +111,7 @@
|
|||||||
"privacy_policy": "Privacy Policy",
|
"privacy_policy": "Privacy Policy",
|
||||||
"quick_create": "Quick Create",
|
"quick_create": "Quick Create",
|
||||||
"recent_matches": "Recent Matches",
|
"recent_matches": "Recent Matches",
|
||||||
|
"redistribute": "Redistribute",
|
||||||
"results": "Results",
|
"results": "Results",
|
||||||
"ruleset": "Ruleset",
|
"ruleset": "Ruleset",
|
||||||
"ruleset_least_points": "Inverse scoring: the player with the fewest points wins.",
|
"ruleset_least_points": "Inverse scoring: the player with the fewest points wins.",
|
||||||
@@ -142,6 +145,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"team": "Team",
|
||||||
"teams": "Teams",
|
"teams": "Teams",
|
||||||
"there_are_no_games_matching_your_search": "There are no games matching your search",
|
"there_are_no_games_matching_your_search": "There are no games matching your search",
|
||||||
"there_is_no_group_matching_your_search": "There is no group matching your search",
|
"there_is_no_group_matching_your_search": "There is no group matching your search",
|
||||||
|
|||||||
@@ -254,6 +254,12 @@ abstract class AppLocalizations {
|
|||||||
/// **'Create new match'**
|
/// **'Create new match'**
|
||||||
String get create_new_match;
|
String get create_new_match;
|
||||||
|
|
||||||
|
/// No description provided for @create_teams.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Create teams'**
|
||||||
|
String get create_teams;
|
||||||
|
|
||||||
/// No description provided for @data.
|
/// No description provided for @data.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
@@ -350,6 +356,12 @@ abstract class AppLocalizations {
|
|||||||
/// **'Edit Match'**
|
/// **'Edit Match'**
|
||||||
String get edit_match;
|
String get edit_match;
|
||||||
|
|
||||||
|
/// No description provided for @edit_members.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Edit Members'**
|
||||||
|
String get edit_members;
|
||||||
|
|
||||||
/// No description provided for @enter_points.
|
/// No description provided for @enter_points.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
@@ -704,6 +716,12 @@ abstract class AppLocalizations {
|
|||||||
/// **'Recent Matches'**
|
/// **'Recent Matches'**
|
||||||
String get recent_matches;
|
String get recent_matches;
|
||||||
|
|
||||||
|
/// No description provided for @redistribute.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Redistribute'**
|
||||||
|
String get redistribute;
|
||||||
|
|
||||||
/// No description provided for @results.
|
/// No description provided for @results.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
@@ -848,6 +866,12 @@ abstract class AppLocalizations {
|
|||||||
/// **'Successfully added player {playerName}'**
|
/// **'Successfully added player {playerName}'**
|
||||||
String successfully_added_player(String playerName);
|
String successfully_added_player(String playerName);
|
||||||
|
|
||||||
|
/// No description provided for @team.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Team'**
|
||||||
|
String get team;
|
||||||
|
|
||||||
/// No description provided for @teams.
|
/// No description provided for @teams.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|||||||
@@ -88,6 +88,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get create_new_match => 'Neues Spiel erstellen';
|
String get create_new_match => 'Neues Spiel erstellen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get create_teams => 'Teams erstellen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get data => 'Daten';
|
String get data => 'Daten';
|
||||||
|
|
||||||
@@ -146,6 +149,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get edit_match => 'Gruppe bearbeiten';
|
String get edit_match => 'Gruppe bearbeiten';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get edit_members => 'Mitglieder bearbeiten';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enter_points => 'Punkte eingeben';
|
String get enter_points => 'Punkte eingeben';
|
||||||
|
|
||||||
@@ -328,6 +334,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get recent_matches => 'Letzte Spiele';
|
String get recent_matches => 'Letzte Spiele';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get redistribute => 'Neu verteilen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get results => 'Ergebnisse';
|
String get results => 'Ergebnisse';
|
||||||
|
|
||||||
@@ -407,6 +416,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
return 'Spieler:in $playerName erfolgreich hinzugefügt';
|
return 'Spieler:in $playerName erfolgreich hinzugefügt';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get team => 'Team';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get teams => 'Teams';
|
String get teams => 'Teams';
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get create_new_match => 'Create new match';
|
String get create_new_match => 'Create new match';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get create_teams => 'Create teams';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get data => 'Data';
|
String get data => 'Data';
|
||||||
|
|
||||||
@@ -146,6 +149,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get edit_match => 'Edit Match';
|
String get edit_match => 'Edit Match';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get edit_members => 'Edit Members';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enter_points => 'Enter points';
|
String get enter_points => 'Enter points';
|
||||||
|
|
||||||
@@ -328,6 +334,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get recent_matches => 'Recent Matches';
|
String get recent_matches => 'Recent Matches';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get redistribute => 'Redistribute';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get results => 'Results';
|
String get results => 'Results';
|
||||||
|
|
||||||
@@ -407,6 +416,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
return 'Successfully added player $playerName';
|
return 'Successfully added player $playerName';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get team => 'Team';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get teams => 'Teams';
|
String get teams => 'Teams';
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import 'package:tallee/data/models/player.dart';
|
|||||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/match_view/create_match/choose_game_view.dart';
|
import 'package:tallee/presentation/views/main_menu/match_view/create_match/choose_game_view.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/match_view/create_match/choose_group_view.dart';
|
import 'package:tallee/presentation/views/main_menu/match_view/create_match/choose_group_view.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/match_view/create_match/organize_teams_view.dart';
|
import 'package:tallee/presentation/views/main_menu/match_view/create_match/team_match/organize_teams_view.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart';
|
import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart';
|
||||||
import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart';
|
import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart';
|
||||||
import 'package:tallee/presentation/widgets/player_selection.dart';
|
import 'package:tallee/presentation/widgets/player_selection.dart';
|
||||||
@@ -296,7 +296,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
|
|
||||||
if (isTeamMatch) {
|
if (isTeamMatch) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
Navigator.pushReplacement(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
adaptivePageRoute(
|
adaptivePageRoute(
|
||||||
fullscreenDialog: !isTeamMatch,
|
fullscreenDialog: !isTeamMatch,
|
||||||
@@ -385,7 +385,9 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
isTeamMatch: isTeamMatch,
|
isTeamMatch: isTeamMatch,
|
||||||
game: selectedGame!,
|
game: selectedGame!,
|
||||||
);
|
);
|
||||||
await db.matchDao.addMatch(match: match);
|
|
||||||
|
// Team matches are saved in OrganizeTeamsView
|
||||||
|
if (!isTeamMatch) await db.matchDao.addMatch(match: match);
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,263 +0,0 @@
|
|||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:tallee/core/adaptive_page_route.dart';
|
|
||||||
import 'package:tallee/core/common.dart';
|
|
||||||
import 'package:tallee/core/custom_theme.dart';
|
|
||||||
import 'package:tallee/core/enums.dart';
|
|
||||||
import 'package:tallee/data/db/database.dart';
|
|
||||||
import 'package:tallee/data/models/match.dart';
|
|
||||||
import 'package:tallee/data/models/player.dart';
|
|
||||||
import 'package:tallee/data/models/team.dart';
|
|
||||||
import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart';
|
|
||||||
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
|
|
||||||
import 'package:tallee/presentation/widgets/tiles/team_creation_tile.dart';
|
|
||||||
|
|
||||||
class OrganizeTeamsView extends StatefulWidget {
|
|
||||||
const OrganizeTeamsView({super.key, required this.match});
|
|
||||||
|
|
||||||
final Match match;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<OrganizeTeamsView> createState() => _OrganizeTeamsViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _OrganizeTeamsViewState extends State<OrganizeTeamsView> {
|
|
||||||
final Random _random = Random();
|
|
||||||
late final List<_TeamDraft> _teams;
|
|
||||||
|
|
||||||
List<Player> get _players => widget.match.players;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_teams = List.generate(2, _createTeamDraft);
|
|
||||||
_redistributePlayers();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
for (final team in _teams) {
|
|
||||||
team.dispose();
|
|
||||||
}
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: CustomTheme.backgroundColor,
|
|
||||||
appBar: AppBar(title: const Text('Organize Teams')),
|
|
||||||
body: SafeArea(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: ListView.builder(
|
|
||||||
padding: const EdgeInsets.only(top: 12, bottom: 12),
|
|
||||||
itemCount: _teams.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
return TeamCreationTile(
|
|
||||||
color: _teams[index].color,
|
|
||||||
controller: _teams[index].nameController,
|
|
||||||
players: _teams[index].members,
|
|
||||||
hintText: 'Team ${index + 1}',
|
|
||||||
onDelete: () => _removeTeam(index),
|
|
||||||
onColorSelection: (color) {
|
|
||||||
setState(() {
|
|
||||||
_teams[index].color = color;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onPlayerTap: (player) =>
|
|
||||||
_showMovePlayerSheet(player, index),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
MainMenuButton(
|
|
||||||
icon: Icons.cached,
|
|
||||||
onPressed: () => setState(() {
|
|
||||||
_redistributePlayers();
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 15),
|
|
||||||
MainMenuButton(
|
|
||||||
text: 'Add team',
|
|
||||||
icon: Icons.emoji_events,
|
|
||||||
onPressed: _teams.length >= widget.match.players.length
|
|
||||||
? null
|
|
||||||
: _addTeam,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 15),
|
|
||||||
MainMenuButton(
|
|
||||||
icon: Icons.check,
|
|
||||||
onPressed: () async {
|
|
||||||
final match = await createMatchWithTeams();
|
|
||||||
if (context.mounted) {
|
|
||||||
Navigator.pushReplacement(
|
|
||||||
context,
|
|
||||||
adaptivePageRoute(
|
|
||||||
fullscreenDialog: true,
|
|
||||||
builder: (context) => MatchResultView(match: match),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Match> createMatchWithTeams() async {
|
|
||||||
final teams = _teams
|
|
||||||
.map(
|
|
||||||
(team) => Team(
|
|
||||||
name: team.nameController.text.trim().isNotEmpty
|
|
||||||
? team.nameController.text.trim()
|
|
||||||
: 'Team ${_teams.indexOf(team) + 1}',
|
|
||||||
color: team.color,
|
|
||||||
members: team.members,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList();
|
|
||||||
final db = Provider.of<AppDatabase>(context, listen: false);
|
|
||||||
await db.teamDao.addTeamsAsList(teams: teams, matchId: widget.match.id);
|
|
||||||
return widget.match.copyWith(teams: teams);
|
|
||||||
}
|
|
||||||
|
|
||||||
_TeamDraft _createTeamDraft(int index) {
|
|
||||||
return _TeamDraft(
|
|
||||||
nameController: TextEditingController(text: 'Team ${index + 1}'),
|
|
||||||
color: getTeamColor(index),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _addTeam() {
|
|
||||||
setState(() {
|
|
||||||
_teams.add(_createTeamDraft(_teams.length));
|
|
||||||
_redistributePlayers();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _removeTeam(int index) {
|
|
||||||
setState(() {
|
|
||||||
final removedTeam = _teams.removeAt(index);
|
|
||||||
removedTeam.dispose();
|
|
||||||
|
|
||||||
if (_teams.isEmpty) {
|
|
||||||
_teams.add(_createTeamDraft(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
_redistributePlayers();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _movePlayer(Player player, int fromTeamIndex, int toTeamIndex) {
|
|
||||||
setState(() {
|
|
||||||
_teams[fromTeamIndex].members.remove(player);
|
|
||||||
_teams[toTeamIndex].members.add(player);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showMovePlayerSheet(Player player, int fromTeamIndex) {
|
|
||||||
final otherTeams = [
|
|
||||||
for (int i = 0; i < _teams.length; i++)
|
|
||||||
if (i != fromTeamIndex) (index: i, team: _teams[i]),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (otherTeams.isEmpty) return;
|
|
||||||
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
backgroundColor: CustomTheme.backgroundColor,
|
|
||||||
shape: const RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
|
||||||
),
|
|
||||||
builder: (context) {
|
|
||||||
return SafeArea(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 16,
|
|
||||||
vertical: 8,
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
'${player.name} verschieben in …',
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: CustomTheme.textColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Divider(),
|
|
||||||
...otherTeams.map((entry) {
|
|
||||||
final teamName =
|
|
||||||
entry.team.nameController.text.trim().isNotEmpty
|
|
||||||
? entry.team.nameController.text.trim()
|
|
||||||
: 'Team ${entry.index + 1}';
|
|
||||||
final teamColor = getColorFromGameColor(entry.team.color);
|
|
||||||
return ListTile(
|
|
||||||
leading: CircleAvatar(
|
|
||||||
radius: 12,
|
|
||||||
backgroundColor: teamColor,
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
teamName,
|
|
||||||
style: const TextStyle(color: CustomTheme.textColor),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
_movePlayer(player, fromTeamIndex, entry.index);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _redistributePlayers() {
|
|
||||||
for (final team in _teams) {
|
|
||||||
team.members.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_players.isEmpty || _teams.isEmpty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final shuffledPlayers = [..._players]..shuffle(_random);
|
|
||||||
|
|
||||||
for (int i = 0; i < shuffledPlayers.length; i++) {
|
|
||||||
final teamIndex = i % _teams.length;
|
|
||||||
_teams[teamIndex].members.add(shuffledPlayers[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TeamDraft {
|
|
||||||
_TeamDraft({required this.nameController, required this.color});
|
|
||||||
|
|
||||||
final TextEditingController nameController;
|
|
||||||
GameColor color;
|
|
||||||
final List<Player> members = [];
|
|
||||||
|
|
||||||
void dispose() {
|
|
||||||
nameController.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tallee/data/models/player.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/player_selection.dart';
|
||||||
|
|
||||||
|
class EditMembersView extends StatefulWidget {
|
||||||
|
const EditMembersView({
|
||||||
|
super.key,
|
||||||
|
required this.matchPlayer,
|
||||||
|
required this.teamMember,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<Player> matchPlayer;
|
||||||
|
|
||||||
|
final List<Player> teamMember;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<EditMembersView> createState() => _EditMembersViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EditMembersViewState extends State<EditMembersView> {
|
||||||
|
List<Player> selectedPlayers = [];
|
||||||
|
List<Player> matchPlayer = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
selectedPlayers = [...widget.teamMember];
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final loc = AppLocalizations.of(context);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(loc.edit_members),
|
||||||
|
leading: HapticIconButton(
|
||||||
|
onPressed: selectedPlayers.isNotEmpty
|
||||||
|
? () => Navigator.pop(context, selectedPlayers)
|
||||||
|
: null,
|
||||||
|
icon: const Icon(Icons.arrow_back_ios_new_outlined),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: PlayerSelection(
|
||||||
|
initialSelectedPlayers: widget.teamMember,
|
||||||
|
availablePlayers: widget.matchPlayer,
|
||||||
|
onChanged: (List<Player> newSelectedPlayers) {
|
||||||
|
setState(() {
|
||||||
|
selectedPlayers = newSelectedPlayers;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tallee/core/adaptive_page_route.dart';
|
||||||
|
import 'package:tallee/core/common.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/models/match.dart';
|
||||||
|
import 'package:tallee/data/models/player.dart';
|
||||||
|
import 'package:tallee/data/models/team.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/match_view/create_match/team_match/edit_members_view.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/team_creation_tile.dart';
|
||||||
|
|
||||||
|
class OrganizeTeamsView extends StatefulWidget {
|
||||||
|
const OrganizeTeamsView({super.key, required this.match});
|
||||||
|
|
||||||
|
final Match match;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<OrganizeTeamsView> createState() => _OrganizeTeamsViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OrganizeTeamsViewState extends State<OrganizeTeamsView> {
|
||||||
|
final Random random = Random();
|
||||||
|
late List<Team> teams;
|
||||||
|
late List<TextEditingController> nameController;
|
||||||
|
|
||||||
|
final int initialTeamCount = 2;
|
||||||
|
List<Player> get matchPlayers => widget.match.players;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
final loc = AppLocalizations.of(context);
|
||||||
|
|
||||||
|
// Init the teams
|
||||||
|
teams = List.generate(
|
||||||
|
initialTeamCount,
|
||||||
|
(index) => Team(
|
||||||
|
name: '${loc.team} ${index + 1}',
|
||||||
|
color: getTeamColor(index),
|
||||||
|
members: [],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Init the controllers
|
||||||
|
nameController = teams.map(getNewController).toList();
|
||||||
|
redistributePlayers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final loc = AppLocalizations.of(context);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
|
appBar: AppBar(title: Text(loc.create_teams)),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
padding: const EdgeInsets.only(top: 12, bottom: 12),
|
||||||
|
itemCount: teams.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return TeamCreationTile(
|
||||||
|
color: teams[index].color,
|
||||||
|
controller: nameController[index],
|
||||||
|
players: teams[index].members,
|
||||||
|
hintText: '${loc.team} ${index + 1}',
|
||||||
|
onEdit: () async {
|
||||||
|
final newPlayers = await Navigator.push(
|
||||||
|
context,
|
||||||
|
adaptivePageRoute(
|
||||||
|
fullscreenDialog: true,
|
||||||
|
builder: (context) => EditMembersView(
|
||||||
|
matchPlayer: widget.match.players,
|
||||||
|
teamMember: teams[index].members,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
// Remove the selected players from every team
|
||||||
|
for (final player in newPlayers) {
|
||||||
|
for (final team in teams) {
|
||||||
|
if (team.members.contains(player)) {
|
||||||
|
team.members.remove(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the selected players to the current team
|
||||||
|
teams[index] = teams[index].copyWith(
|
||||||
|
members: newPlayers,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onDelete: teams.length >= 3
|
||||||
|
? () => _removeTeam(index)
|
||||||
|
: null,
|
||||||
|
onColorSelection: (color) {
|
||||||
|
setState(() {
|
||||||
|
teams[index] = teams[index].copyWith(color: color);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
MainMenuButton(
|
||||||
|
icon: Icons.cached,
|
||||||
|
text: loc.redistribute,
|
||||||
|
onPressed: () => setState(() {
|
||||||
|
redistributePlayers();
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 15),
|
||||||
|
MainMenuButton(
|
||||||
|
icon: Icons.add,
|
||||||
|
onPressed: teams.length >= widget.match.players.length
|
||||||
|
? null
|
||||||
|
: addTeam,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 15),
|
||||||
|
MainMenuButton(
|
||||||
|
icon: Icons.check,
|
||||||
|
onPressed: teams.every((team) => team.members.isNotEmpty)
|
||||||
|
? () async {
|
||||||
|
final match = await createMatchWithTeams();
|
||||||
|
if (context.mounted) {
|
||||||
|
Navigator.pushAndRemoveUntil(
|
||||||
|
context,
|
||||||
|
adaptivePageRoute(
|
||||||
|
fullscreenDialog: true,
|
||||||
|
builder: (context) =>
|
||||||
|
MatchResultView(match: match),
|
||||||
|
),
|
||||||
|
(route) => route.isFirst,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a new team to the list of teams, creates a corresponding controller,
|
||||||
|
/// and redistributes the players among all teams.
|
||||||
|
void addTeam() {
|
||||||
|
setState(() {
|
||||||
|
final newTeam = getNewTeam();
|
||||||
|
teams.add(newTeam);
|
||||||
|
nameController.add(getNewController(newTeam));
|
||||||
|
redistributePlayers();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new team with a default name and color based on the current number
|
||||||
|
Team getNewTeam() {
|
||||||
|
final loc = AppLocalizations.of(context);
|
||||||
|
return Team(
|
||||||
|
name: '${loc.team} ${teams.length + 1}',
|
||||||
|
color: getTeamColor(teams.length),
|
||||||
|
members: [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds a [TextEditingController] for the given team and sets up a listener
|
||||||
|
/// to update the team's name whenever the text changes.
|
||||||
|
TextEditingController getNewController(Team team) {
|
||||||
|
final textController = TextEditingController(text: team.name);
|
||||||
|
textController.addListener(() {
|
||||||
|
final index = teams.indexWhere((t) => t.id == team.id);
|
||||||
|
if (index == -1) return;
|
||||||
|
teams[index] = teams[index].copyWith(name: textController.text);
|
||||||
|
});
|
||||||
|
return textController;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes the team with the given index and redistributes its players to the
|
||||||
|
/// remaining teams. If there are less than 2 teams the removed team gets
|
||||||
|
/// replaced with a new one
|
||||||
|
void _removeTeam(int index) {
|
||||||
|
final loc = AppLocalizations.of(context);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
final removedTeam = teams.removeAt(index);
|
||||||
|
final removedController = nameController.removeAt(index);
|
||||||
|
removedController.dispose();
|
||||||
|
if (teams.length < 2) {
|
||||||
|
final fallbackTeam = getNewTeam();
|
||||||
|
teams.add(fallbackTeam);
|
||||||
|
nameController.add(getNewController(fallbackTeam));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update index-based team names
|
||||||
|
for (int i = 0; i < nameController.length; i++) {
|
||||||
|
if (nameController[i].text.contains(
|
||||||
|
RegExp('^${RegExp.escape(loc.team)} \\d+\$'),
|
||||||
|
)) {
|
||||||
|
nameController[i].text = '${loc.team} ${i + 1}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addToSmallestTeams(removedTeam.members);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the given players to the teams with the least amount of members
|
||||||
|
/// [orphanedPlayers] The players to be added to the teams.
|
||||||
|
void addToSmallestTeams(List<Player> orphanedPlayers) {
|
||||||
|
if (teams.isEmpty || orphanedPlayers.isEmpty) return;
|
||||||
|
|
||||||
|
for (final player in orphanedPlayers) {
|
||||||
|
var targetIndex = 0;
|
||||||
|
for (var i = 1; i < teams.length; i++) {
|
||||||
|
if (teams[i].members.length < teams[targetIndex].members.length) {
|
||||||
|
targetIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
teams[targetIndex].members.add(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterates through all teams and redistributes players randomly and
|
||||||
|
// as evenly as possible.
|
||||||
|
void redistributePlayers() {
|
||||||
|
for (final team in teams) {
|
||||||
|
team.members.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchPlayers.isEmpty || teams.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final shuffledPlayers = [...matchPlayers]..shuffle(random);
|
||||||
|
|
||||||
|
for (int i = 0; i < shuffledPlayers.length; i++) {
|
||||||
|
final teamIndex = i % teams.length;
|
||||||
|
teams[teamIndex].members.add(shuffledPlayers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Saves the teams to the database and returns the updated match with the teams.
|
||||||
|
Future<Match> createMatchWithTeams() async {
|
||||||
|
final db = Provider.of<AppDatabase>(context, listen: false);
|
||||||
|
final match = widget.match.copyWith(teams: teams);
|
||||||
|
await db.matchDao.addMatch(match: match);
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
for (final c in nameController) {
|
||||||
|
c.dispose();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -333,6 +333,7 @@ class _MatchResultViewState extends State<MatchResultView> {
|
|||||||
} else {
|
} else {
|
||||||
return await db.teamDao.setWinnerTeams(
|
return await db.teamDao.setWinnerTeams(
|
||||||
matchId: widget.match.id,
|
matchId: widget.match.id,
|
||||||
|
|
||||||
winners: _selectedTeams.toList(),
|
winners: _selectedTeams.toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ class _MatchViewState extends State<MatchView> {
|
|||||||
|
|
||||||
/// Loads the matches from the database and sorts them by creation date.
|
/// Loads the matches from the database and sorts them by creation date.
|
||||||
void loadMatches() {
|
void loadMatches() {
|
||||||
|
print('Loading matches from database');
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
Future.wait([
|
Future.wait([
|
||||||
db.matchDao.getAllMatches(),
|
db.matchDao.getAllMatches(),
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import 'package:tallee/core/constants.dart';
|
|||||||
import 'package:tallee/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:tallee/core/enums.dart';
|
import 'package:tallee/core/enums.dart';
|
||||||
import 'package:tallee/data/models/player.dart';
|
import 'package:tallee/data/models/player.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/animated_dialog_button.dart';
|
||||||
import 'package:tallee/presentation/widgets/text_input/text_input_field.dart';
|
import 'package:tallee/presentation/widgets/text_input/text_input_field.dart';
|
||||||
import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart';
|
||||||
|
|
||||||
@@ -14,9 +16,9 @@ class TeamCreationTile extends StatefulWidget {
|
|||||||
required this.controller,
|
required this.controller,
|
||||||
required this.players,
|
required this.players,
|
||||||
required this.hintText,
|
required this.hintText,
|
||||||
|
this.onEdit,
|
||||||
this.onDelete,
|
this.onDelete,
|
||||||
this.onColorSelection,
|
this.onColorSelection,
|
||||||
this.onPlayerTap,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final GameColor color;
|
final GameColor color;
|
||||||
@@ -27,28 +29,34 @@ class TeamCreationTile extends StatefulWidget {
|
|||||||
|
|
||||||
final String hintText;
|
final String hintText;
|
||||||
|
|
||||||
|
final VoidCallback? onEdit;
|
||||||
|
|
||||||
final VoidCallback? onDelete;
|
final VoidCallback? onDelete;
|
||||||
|
|
||||||
final ValueChanged<GameColor>? onColorSelection;
|
final ValueChanged<GameColor>? onColorSelection;
|
||||||
|
|
||||||
final void Function(Player player)? onPlayerTap;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<TeamCreationTile> createState() => _TeamCreationTileState();
|
State<TeamCreationTile> createState() => _TeamCreationTileState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TeamCreationTileState extends State<TeamCreationTile> {
|
class _TeamCreationTileState extends State<TeamCreationTile> {
|
||||||
|
final teamColors = List.generate(
|
||||||
|
GameColor.values.length,
|
||||||
|
(index) => getTeamColor(index),
|
||||||
|
);
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final loc = AppLocalizations.of(context);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: CustomTheme.standardMargin,
|
margin: CustomTheme.standardMargin,
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||||
decoration: CustomTheme.standardBoxDecoration,
|
decoration: CustomTheme.standardBoxDecoration,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextInputField(
|
child: TextInputField(
|
||||||
@@ -57,17 +65,19 @@ class _TeamCreationTileState extends State<TeamCreationTile> {
|
|||||||
maxLength: Constants.MAX_TEAM_NAME_LENGTH,
|
maxLength: Constants.MAX_TEAM_NAME_LENGTH,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 12),
|
||||||
IconButton(
|
AnimatedDialogButton(
|
||||||
onPressed: () => widget.onDelete?.call(),
|
content: const Icon(Icons.delete),
|
||||||
icon: const Icon(Icons.delete, size: 24),
|
isDescructive: true,
|
||||||
|
onPressed: widget.onDelete,
|
||||||
|
buttonText: '',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
const Text(
|
Text(
|
||||||
'Color',
|
loc.color,
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: CustomTheme.textColor,
|
color: CustomTheme.textColor,
|
||||||
@@ -77,7 +87,7 @@ class _TeamCreationTileState extends State<TeamCreationTile> {
|
|||||||
Wrap(
|
Wrap(
|
||||||
spacing: 8,
|
spacing: 8,
|
||||||
runSpacing: 8,
|
runSpacing: 8,
|
||||||
children: GameColor.values.map((color) {
|
children: teamColors.map((color) {
|
||||||
final isSelected = widget.color == color;
|
final isSelected = widget.color == color;
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -102,9 +112,9 @@ class _TeamCreationTileState extends State<TeamCreationTile> {
|
|||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
const Text(
|
Text(
|
||||||
'Players',
|
loc.players,
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: CustomTheme.textColor,
|
color: CustomTheme.textColor,
|
||||||
@@ -112,9 +122,9 @@ class _TeamCreationTileState extends State<TeamCreationTile> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
if (widget.players.isEmpty)
|
if (widget.players.isEmpty)
|
||||||
const Text(
|
Text(
|
||||||
'Keine Spieler:innen zugewiesen',
|
loc.no_players_selected,
|
||||||
style: TextStyle(color: CustomTheme.hintColor),
|
style: const TextStyle(color: CustomTheme.hintColor),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
Wrap(
|
Wrap(
|
||||||
@@ -122,18 +132,25 @@ class _TeamCreationTileState extends State<TeamCreationTile> {
|
|||||||
runSpacing: 8,
|
runSpacing: 8,
|
||||||
children: widget.players
|
children: widget.players
|
||||||
.map(
|
.map(
|
||||||
(player) => GestureDetector(
|
(player) => TextIconTile(
|
||||||
onTap: () => widget.onPlayerTap?.call(player),
|
text: player.name,
|
||||||
child: TextIconTile(
|
suffixText: getNameCountText(player),
|
||||||
text: player.name,
|
iconEnabled: false,
|
||||||
suffixText: getNameCountText(player),
|
|
||||||
iconEnabled: widget.onPlayerTap != null,
|
|
||||||
onIconTap: () => widget.onPlayerTap?.call(player),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
|
if (widget.onEdit != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 12),
|
||||||
|
child: AnimatedDialogButton(
|
||||||
|
buttonConstraints: const BoxConstraints(
|
||||||
|
minWidth: double.infinity,
|
||||||
|
),
|
||||||
|
buttonText: loc.edit_members,
|
||||||
|
onPressed: widget.onEdit!,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user