Beta-Version 0.5.3 (#136)

* Updated createGameView ListBuilder

* Added ReorderableListView

* Increment build no

* Fixed bug with wrong medal icon

* change not equal to greater than

* Updated bool var

* Fixed deletion error

* Small translation improvements

* Implemented first version of point overview

* Visual improvements on table

* Added details and sum row

* Updated strings

* Implemented new strings

* Refactoring

* Updated graph displayment

* Moved new views to statistics section

* Added seperator in main menu

* Renaming

* Updated sign

* Updated colors & class name

* Removed empty line

* Updated round index

* Updated types

* Added new kamikaze button and bundles navigation functionality

* Updated lock icon

* Updated button position and design

* Removed title row and changed segmendetControl Padding

* Refactored logic and added comments

* Updated comment

* Chaned icon

* Added comment

* Removed print

* Updated colors

* Changed var name

* Removed unused strings

* Added gameMode

* Changed creation variable

* Updated mode selection

* Updated strings

* Changed mode order

* Implemented default mode selection

* Updated initState

* Removed print

* Removed print

* Removed comments

* Updated config service

* Changed create game view

* Changed icon

* Updated strings

* Updated config

* Updated mode selection logic

* Deleted getter

* Removed not used code

* Implemented reset logic for default game mode

* Updated to 0.5.0

* Hotfix: Pixel Overflow

* Changed the overall return type for gamemodes

* Updated documentation

* Fixed merge issues

* Added Custom button

* Updated strings

* Updated buttons, implemented animatedOpacity

* Keyboard still doesnt works

* Fixed keyboard behaviour

* Changed keyboard height

* Added method getGameSessionById()

* Updated gameSession class

* id gets added to gameSession class at creation

* Cleaned up file

* Added docs and dependency

* Removed toString

* Implemented null safety

* Added named parameter

* Replaced button with custom button

* Updated key

* Updated addGameSessionMethod

* Update README.md

* Added Strings for popup

* Implemented popup & confetti

* Extracted code to method _playFinishAnimation()

* Replaced tenary operator with Visibility Widget

* Replaced tenary operator with Visibility Widget

* Used variable again

* Added delays in constants.dart

* Removed confetti button

* Updated strings

* Removed print

* Added dispose for confettiController

* Implemented missing constant in code

* Updated gameSession logic so more than one player can be winner

* Updated strings

* Updated winner popup

* game names now can have up to 20 chars

* Updated strings

* Added sized box for visual enhancement

* Centered the add player button and made it wider

* New created player textfields get automatically focused

* Added focus nodes for autofocus and navigation between textfields

* Updated version number

* Updated game title textfield with focus node and textaction

* Added focusnodes to dispose

* Update README.md

* Fixed bug with no popup shown

* Fixed bug with out of range error

* Updated listener notification
This commit is contained in:
2025-07-21 13:29:25 +02:00
committed by GitHub
parent c19ce71198
commit d627f33579
24 changed files with 1503 additions and 799 deletions

View File

@@ -58,162 +58,167 @@ class _MainMenuViewState extends State<MainMenuView> {
listenable: gameManager,
builder: (context, _) {
return CupertinoPageScaffold(
resizeToAvoidBottomInset: false,
navigationBar: CupertinoNavigationBar(
leading: IconButton(
onPressed: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => const SettingsView(),
),
).then((_) {
setState(() {});
});
},
icon: const Icon(CupertinoIcons.settings, size: 30)),
middle: const Text('Cabo Counter'),
trailing: IconButton(
onPressed: () => Navigator.push(
resizeToAvoidBottomInset: false,
navigationBar: CupertinoNavigationBar(
leading: IconButton(
onPressed: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => const CreateGameView(),
builder: (context) => const SettingsView(),
),
).then((_) {
setState(() {});
});
},
icon: const Icon(CupertinoIcons.settings, size: 30)),
middle: Text(AppLocalizations.of(context).app_name),
trailing: IconButton(
onPressed: () => Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => CreateGameView(
gameMode: ConfigService.getGameMode()),
),
),
icon: const Icon(CupertinoIcons.add)),
),
child: CupertinoPageScaffold(
child: SafeArea(
child: Visibility(
visible: _isLoading,
replacement: Visibility(
visible: gameManager.gameList.isEmpty,
replacement: ListView.separated(
itemCount: gameManager.gameList.length,
separatorBuilder: (context, index) => Divider(
height: 1,
thickness: 0.5,
color: CustomTheme.white.withAlpha(50),
indent: 50,
endIndent: 50,
),
icon: const Icon(CupertinoIcons.add)),
),
child: CupertinoPageScaffold(
child: SafeArea(
child: _isLoading
? const Center(child: CupertinoActivityIndicator())
: gameManager.gameList.isEmpty
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 30),
Center(
child: GestureDetector(
onTap: () => Navigator.push(
context,
CupertinoPageRoute(
builder: (context) =>
const CreateGameView(),
itemBuilder: (context, index) {
final session = gameManager.gameList[index];
return ListenableBuilder(
listenable: session,
builder: (context, _) {
return Dismissible(
key: Key(session.id),
background: Container(
color: CupertinoColors.destructiveRed,
alignment: Alignment.centerRight,
padding: const EdgeInsets.only(right: 20.0),
child: const Icon(
CupertinoIcons.delete,
color: CupertinoColors.white,
),
),
child: Icon(
CupertinoIcons.plus,
size: 60,
color: CustomTheme.primaryColor,
),
)),
const SizedBox(height: 10),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 70),
child: Text(
'${AppLocalizations.of(context).empty_text_1}\n${AppLocalizations.of(context).empty_text_2}',
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 16),
),
),
],
)
: ListView.builder(
itemCount: gameManager.gameList.length,
itemBuilder: (context, index) {
final session = gameManager.gameList[index];
return ListenableBuilder(
listenable: session,
builder: (context, _) {
return Dismissible(
key: Key(session.gameTitle),
background: Container(
color: CupertinoColors.destructiveRed,
alignment: Alignment.centerRight,
padding:
const EdgeInsets.only(right: 20.0),
child: const Icon(
CupertinoIcons.delete,
color: CupertinoColors.white,
direction: DismissDirection.endToStart,
confirmDismiss: (direction) async {
return await _showDeleteGamePopup(
context, session.gameTitle);
},
onDismissed: (direction) {
gameManager.removeGameSessionById(session.id);
},
dismissThresholds: const {
DismissDirection.startToEnd: 0.6
},
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0),
child: CupertinoListTile(
backgroundColorActivated:
CustomTheme.backgroundColor,
title: Text(session.gameTitle),
subtitle: Visibility(
visible: session.isGameFinished,
replacement: Text(
'${AppLocalizations.of(context).mode}: ${_translateGameMode(session.isPointsLimitEnabled)}',
style: const TextStyle(fontSize: 14),
),
),
direction: DismissDirection.endToStart,
confirmDismiss: (direction) async {
final String gameTitle = gameManager
.gameList[index].gameTitle;
return await _showDeleteGamePopup(
context, gameTitle);
},
onDismissed: (direction) {
gameManager
.removeGameSessionByIndex(index);
},
dismissThresholds: const {
DismissDirection.startToEnd: 0.6
},
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0),
child: CupertinoListTile(
backgroundColorActivated:
CustomTheme.backgroundColor,
title: Text(session.gameTitle),
subtitle:
session.isGameFinished == true
? Text(
'\u{1F947} ${session.winner}',
style: const TextStyle(
fontSize: 14),
)
: Text(
'${AppLocalizations.of(context).mode}: ${_translateGameMode(session.isPointsLimitEnabled)}',
style: const TextStyle(
fontSize: 14),
),
trailing: Row(
children: [
Text('${session.roundNumber}'),
const SizedBox(width: 3),
const Icon(CupertinoIcons
.arrow_2_circlepath_circle_fill),
const SizedBox(width: 15),
Text('${session.players.length}'),
const SizedBox(width: 3),
const Icon(
CupertinoIcons.person_2_fill),
],
),
onTap: () {
final session =
gameManager.gameList[index];
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) =>
ActiveGameView(
gameSession: session),
),
).then((_) {
setState(() {});
});
},
child: Text(
'\u{1F947} ${session.winner}',
style: const TextStyle(fontSize: 14),
)),
trailing: Row(
children: [
const SizedBox(
width: 5,
),
),
);
});
},
Text('${session.roundNumber}'),
const SizedBox(width: 3),
const Icon(CupertinoIcons
.arrow_2_circlepath_circle_fill),
const SizedBox(width: 15),
Text('${session.players.length}'),
const SizedBox(width: 3),
const Icon(
CupertinoIcons.person_2_fill),
],
),
onTap: () {
final session =
gameManager.gameList[index];
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => ActiveGameView(
gameSession: session),
),
).then((_) {
setState(() {});
});
},
),
),
);
});
},
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 30),
Center(
child: GestureDetector(
onTap: () => Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => CreateGameView(
gameMode: ConfigService.getGameMode()),
),
),
),
),
);
child: Icon(
CupertinoIcons.plus,
size: 60,
color: CustomTheme.primaryColor,
),
)),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 70),
child: Text(
'${AppLocalizations.of(context).empty_text_1}\n${AppLocalizations.of(context).empty_text_2}',
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 16),
),
),
],
),
),
child: const Center(child: CupertinoActivityIndicator()),
),
)));
});
}
/// Translates the game mode boolean into the corresponding String.
/// If [pointLimit] is true, it returns '101 Punkte', otherwise it returns 'Unbegrenzt'.
String _translateGameMode(bool pointLimit) {
if (pointLimit) {
return '${ConfigService.pointLimit} ${AppLocalizations.of(context).points}';
String _translateGameMode(bool isPointLimitEnabled) {
if (isPointLimitEnabled) {
return '${ConfigService.getPointLimit()} ${AppLocalizations.of(context).points}';
}
return AppLocalizations.of(context).unlimited;
}
@@ -237,7 +242,7 @@ class _MainMenuViewState extends State<MainMenuView> {
BadRatingDialogDecision badRatingDecision = BadRatingDialogDecision.cancel;
// so that the bad rating dialog is not shown immediately
await Future.delayed(const Duration(milliseconds: 300));
await Future.delayed(const Duration(milliseconds: Constants.popUpDelay));
switch (preRatingDecision) {
case PreRatingDialogDecision.yes: