Merge pull request 'Spieler erstellen in CreateGroupView' (#43) from feature/42-spieler-erstellen-in-create-group-view-implementieren into development
Reviewed-on: #43 Reviewed-by: Felix Kirchner <felix.kirchner.fk@gmail.com>
This commit was merged in pull request #43.
This commit is contained in:
@@ -37,6 +37,24 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
db = Provider.of<AppDatabase>(context, listen: false);
|
db = Provider.of<AppDatabase>(context, listen: false);
|
||||||
|
_searchBarController.addListener(() {
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
|
_groupNameController.addListener(() {
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
|
loadPlayerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_groupNameController.dispose();
|
||||||
|
_searchBarController
|
||||||
|
.dispose(); // Listener entfernen und Controller aufräumen
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadPlayerList() {
|
||||||
_allPlayersFuture = db.playerDao.getAllPlayers();
|
_allPlayersFuture = db.playerDao.getAllPlayers();
|
||||||
_allPlayersFuture.then((loadedPlayers) {
|
_allPlayersFuture.then((loadedPlayers) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -99,6 +117,19 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
|||||||
minHeight: 45,
|
minHeight: 45,
|
||||||
),
|
),
|
||||||
hintText: 'Search for players',
|
hintText: 'Search for players',
|
||||||
|
trailingButtonShown: true,
|
||||||
|
trailingButtonicon: Icons.add_circle,
|
||||||
|
trailingButtonEnabled: _searchBarController.text
|
||||||
|
.trim()
|
||||||
|
.isNotEmpty,
|
||||||
|
onTrailingButtonPressed: () async {
|
||||||
|
addNewPlayerFromSearch(
|
||||||
|
context: context,
|
||||||
|
searchBarController: _searchBarController,
|
||||||
|
db: db,
|
||||||
|
loadPlayerList: loadPlayerList,
|
||||||
|
);
|
||||||
|
},
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (value.isEmpty) {
|
if (value.isEmpty) {
|
||||||
@@ -216,46 +247,48 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
|||||||
layoutBuilder:
|
layoutBuilder:
|
||||||
AnimatedSwitcher.defaultLayoutBuilder,
|
AnimatedSwitcher.defaultLayoutBuilder,
|
||||||
),
|
),
|
||||||
child:
|
child: Visibility(
|
||||||
(suggestedPlayers.isEmpty &&
|
visible:
|
||||||
allPlayers.isNotEmpty)
|
(suggestedPlayers.isEmpty &&
|
||||||
? TopCenteredMessage(
|
allPlayers.isNotEmpty),
|
||||||
icon: Icons.info,
|
replacement: ListView.builder(
|
||||||
title: 'Info',
|
itemCount: suggestedPlayers.length,
|
||||||
message:
|
itemBuilder:
|
||||||
(selectedPlayers.length ==
|
(BuildContext context, int index) {
|
||||||
allPlayers.length)
|
return TextIconListTile(
|
||||||
? 'No more players to add.'
|
text: suggestedPlayers[index].name,
|
||||||
: 'No players found with that name.',
|
onPressed: () {
|
||||||
)
|
setState(() {
|
||||||
: ListView.builder(
|
if (!selectedPlayers.contains(
|
||||||
itemCount: suggestedPlayers.length,
|
suggestedPlayers[index],
|
||||||
itemBuilder:
|
)) {
|
||||||
(BuildContext context, int index) {
|
selectedPlayers.add(
|
||||||
return TextIconListTile(
|
suggestedPlayers[index],
|
||||||
text: suggestedPlayers[index]
|
);
|
||||||
.name,
|
selectedPlayers.sort(
|
||||||
onPressed: () {
|
(a, b) => a.name.compareTo(
|
||||||
setState(() {
|
b.name,
|
||||||
if (!selectedPlayers.contains(
|
),
|
||||||
suggestedPlayers[index],
|
);
|
||||||
)) {
|
suggestedPlayers.remove(
|
||||||
selectedPlayers.add(
|
suggestedPlayers[index],
|
||||||
suggestedPlayers[index],
|
);
|
||||||
);
|
}
|
||||||
selectedPlayers.sort(
|
});
|
||||||
(a, b) => a.name
|
|
||||||
.compareTo(b.name),
|
|
||||||
);
|
|
||||||
suggestedPlayers.remove(
|
|
||||||
suggestedPlayers[index],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
child: TopCenteredMessage(
|
||||||
|
icon: Icons.info,
|
||||||
|
title: 'Info',
|
||||||
|
message:
|
||||||
|
(selectedPlayers.length ==
|
||||||
|
allPlayers.length)
|
||||||
|
? 'No more players to add.'
|
||||||
|
: 'No players found with that name.',
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -274,7 +307,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
|||||||
: () async {
|
: () async {
|
||||||
bool success = await db.groupDao.addGroup(
|
bool success = await db.groupDao.addGroup(
|
||||||
group: Group(
|
group: Group(
|
||||||
name: _groupNameController.text,
|
name: _groupNameController.text.trim(),
|
||||||
members: selectedPlayers,
|
members: selectedPlayers,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -307,3 +340,47 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a new player to the database from the search bar input.
|
||||||
|
/// Shows a snackbar indicating success or failure.
|
||||||
|
/// [context] - BuildContext to show the snackbar.
|
||||||
|
/// [searchBarController] - TextEditingController of the search bar.
|
||||||
|
/// [db] - AppDatabase instance to interact with the database.
|
||||||
|
/// [loadPlayerList] - Function to reload the player list after adding.
|
||||||
|
void addNewPlayerFromSearch({
|
||||||
|
required BuildContext context,
|
||||||
|
required TextEditingController searchBarController,
|
||||||
|
required AppDatabase db,
|
||||||
|
required Function loadPlayerList,
|
||||||
|
}) async {
|
||||||
|
String playerName = searchBarController.text.trim();
|
||||||
|
bool success = await db.playerDao.addPlayer(player: Player(name: playerName));
|
||||||
|
if (!context.mounted) return;
|
||||||
|
if (success) {
|
||||||
|
loadPlayerList();
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
backgroundColor: CustomTheme.boxColor,
|
||||||
|
content: Center(
|
||||||
|
child: Text(
|
||||||
|
'Successfully added player $playerName.',
|
||||||
|
style: const TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
searchBarController.clear();
|
||||||
|
} else {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
backgroundColor: CustomTheme.boxColor,
|
||||||
|
content: Center(
|
||||||
|
child: Text(
|
||||||
|
'Could not add player $playerName.',
|
||||||
|
style: const TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,11 +6,19 @@ class CustomSearchBar extends StatelessWidget {
|
|||||||
final String hintText;
|
final String hintText;
|
||||||
final ValueChanged<String>? onChanged;
|
final ValueChanged<String>? onChanged;
|
||||||
final BoxConstraints? constraints;
|
final BoxConstraints? constraints;
|
||||||
|
final bool trailingButtonShown;
|
||||||
|
final bool trailingButtonEnabled;
|
||||||
|
final VoidCallback? onTrailingButtonPressed;
|
||||||
|
final IconData trailingButtonicon;
|
||||||
|
|
||||||
const CustomSearchBar({
|
const CustomSearchBar({
|
||||||
super.key,
|
super.key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
required this.hintText,
|
required this.hintText,
|
||||||
|
this.trailingButtonShown = false,
|
||||||
|
this.trailingButtonicon = Icons.clear,
|
||||||
|
this.trailingButtonEnabled = true,
|
||||||
|
this.onTrailingButtonPressed,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
this.constraints,
|
this.constraints,
|
||||||
});
|
});
|
||||||
@@ -22,9 +30,24 @@ class CustomSearchBar extends StatelessWidget {
|
|||||||
constraints:
|
constraints:
|
||||||
constraints ?? const BoxConstraints(maxHeight: 45, minHeight: 45),
|
constraints ?? const BoxConstraints(maxHeight: 45, minHeight: 45),
|
||||||
hintText: hintText,
|
hintText: hintText,
|
||||||
onChanged: onChanged,
|
onChanged: trailingButtonEnabled ? onChanged : null,
|
||||||
hintStyle: WidgetStateProperty.all(const TextStyle(fontSize: 16)),
|
hintStyle: WidgetStateProperty.all(const TextStyle(fontSize: 16)),
|
||||||
leading: const Icon(Icons.search),
|
leading: const Icon(Icons.search),
|
||||||
|
trailing: [
|
||||||
|
Visibility(
|
||||||
|
visible: trailingButtonShown,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: trailingButtonEnabled ? onTrailingButtonPressed : null,
|
||||||
|
child: Icon(
|
||||||
|
trailingButtonicon,
|
||||||
|
color: trailingButtonEnabled
|
||||||
|
? null
|
||||||
|
: Colors.grey.withValues(alpha: 0.2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 5),
|
||||||
|
],
|
||||||
backgroundColor: WidgetStateProperty.all(CustomTheme.boxColor),
|
backgroundColor: WidgetStateProperty.all(CustomTheme.boxColor),
|
||||||
side: WidgetStateProperty.all(BorderSide(color: CustomTheme.boxBorder)),
|
side: WidgetStateProperty.all(BorderSide(color: CustomTheme.boxBorder)),
|
||||||
shape: WidgetStateProperty.all(
|
shape: WidgetStateProperty.all(
|
||||||
|
|||||||
Reference in New Issue
Block a user