Merge pull request #122 from flixcoo/enhance/104-rework-kamikaze-features
Rework kamikaze feature
This commit is contained in:
@@ -4,7 +4,9 @@ class CustomTheme {
|
||||
static Color white = CupertinoColors.white;
|
||||
static Color primaryColor = CupertinoColors.systemGreen;
|
||||
static Color backgroundColor = const Color(0xFF101010);
|
||||
static Color backgroundTintColor = CupertinoColors.darkBackgroundGray;
|
||||
static Color mainElementBackgroundColor = CupertinoColors.darkBackgroundGray;
|
||||
static Color playerTileColor = CupertinoColors.secondaryLabel;
|
||||
static Color buttonBackgroundColor = const Color(0xFF202020);
|
||||
|
||||
// Line Colors for GraphView
|
||||
static const Color graphColor1 = Color(0xFFF44336);
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
"results": "Ergebnisse",
|
||||
"who_said_cabo": "Wer hat CABO gesagt?",
|
||||
"kamikaze": "Kamikaze",
|
||||
"who_has_kamikaze": "Wer hat Kamikaze?",
|
||||
"done": "Fertig",
|
||||
"next_round": "Nächste Runde",
|
||||
"bonus_points_title": "Bonus-Punkte!",
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
"results": "Results",
|
||||
"who_said_cabo": "Who called Cabo?",
|
||||
"kamikaze": "Kamikaze",
|
||||
"who_has_kamikaze": "Who has Kamikaze?",
|
||||
"done": "Done",
|
||||
"next_round": "Next Round",
|
||||
"bonus_points_title": "Bonus-Points!",
|
||||
|
||||
@@ -404,6 +404,12 @@ abstract class AppLocalizations {
|
||||
/// **'Kamikaze'**
|
||||
String get kamikaze;
|
||||
|
||||
/// No description provided for @who_has_kamikaze.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
/// **'Wer hat Kamikaze?'**
|
||||
String get who_has_kamikaze;
|
||||
|
||||
/// No description provided for @done.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
|
||||
@@ -172,6 +172,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
@override
|
||||
String get kamikaze => 'Kamikaze';
|
||||
|
||||
@override
|
||||
String get who_has_kamikaze => 'Wer hat Kamikaze?';
|
||||
|
||||
@override
|
||||
String get done => 'Fertig';
|
||||
|
||||
|
||||
@@ -170,6 +170,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get kamikaze => 'Kamikaze';
|
||||
|
||||
@override
|
||||
String get who_has_kamikaze => 'Who has Kamikaze?';
|
||||
|
||||
@override
|
||||
String get done => 'Done';
|
||||
|
||||
|
||||
@@ -74,21 +74,22 @@ class _RoundViewState extends State<RoundView> {
|
||||
return CupertinoPageScaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
transitionBetweenRoutes: true,
|
||||
leading: CupertinoButton(
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () =>
|
||||
{LocalStorageService.saveGameSessions(), Navigator.pop(context)},
|
||||
child: Text(AppLocalizations.of(context).cancel),
|
||||
),
|
||||
middle: Text(AppLocalizations.of(context).results),
|
||||
trailing: widget.gameSession.isGameFinished
|
||||
? const Icon(
|
||||
transitionBetweenRoutes: true,
|
||||
leading: CupertinoButton(
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () => {
|
||||
LocalStorageService.saveGameSessions(),
|
||||
Navigator.pop(context)
|
||||
},
|
||||
child: Text(AppLocalizations.of(context).cancel),
|
||||
),
|
||||
middle: Text(AppLocalizations.of(context).results),
|
||||
trailing: Visibility(
|
||||
visible: widget.gameSession.isGameFinished,
|
||||
child: const Icon(
|
||||
CupertinoIcons.lock,
|
||||
size: 25,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
))),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
@@ -114,9 +115,10 @@ class _RoundViewState extends State<RoundView> {
|
||||
vertical: 10,
|
||||
),
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
height: 60,
|
||||
child: CupertinoSegmentedControl<int>(
|
||||
unselectedColor: CustomTheme.backgroundTintColor,
|
||||
unselectedColor:
|
||||
CustomTheme.mainElementBackgroundColor,
|
||||
selectedColor: CustomTheme.primaryColor,
|
||||
groupValue: _caboPlayerIndex,
|
||||
children: Map.fromEntries(widget.gameSession.players
|
||||
@@ -130,7 +132,7 @@ class _RoundViewState extends State<RoundView> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 6,
|
||||
vertical: 8,
|
||||
),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
@@ -154,27 +156,6 @@ class _RoundViewState extends State<RoundView> {
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: CupertinoListTile(
|
||||
title: Text(AppLocalizations.of(context).player),
|
||||
trailing: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 100,
|
||||
child: Center(
|
||||
child: Text(
|
||||
AppLocalizations.of(context).points))),
|
||||
const SizedBox(width: 20),
|
||||
SizedBox(
|
||||
width: 80,
|
||||
child: Center(
|
||||
child: Text(AppLocalizations.of(context)
|
||||
.kamikaze))),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
@@ -190,7 +171,7 @@ class _RoundViewState extends State<RoundView> {
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: CupertinoListTile(
|
||||
backgroundColor: CupertinoColors.secondaryLabel,
|
||||
backgroundColor: CustomTheme.playerTileColor,
|
||||
title: Row(children: [
|
||||
Expanded(
|
||||
child: Row(children: [
|
||||
@@ -204,90 +185,68 @@ class _RoundViewState extends State<RoundView> {
|
||||
),
|
||||
Visibility(
|
||||
visible: shouldShowMedal,
|
||||
child: const Icon(FontAwesomeIcons.medal,
|
||||
child: const Icon(FontAwesomeIcons.crown,
|
||||
size: 15))
|
||||
]))
|
||||
]),
|
||||
subtitle: Text(
|
||||
'${widget.gameSession.playerScores[originalIndex]}'
|
||||
' ${AppLocalizations.of(context).points}'),
|
||||
trailing: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 100,
|
||||
child: CupertinoTextField(
|
||||
maxLength: 3,
|
||||
focusNode: _focusNodeList[originalIndex],
|
||||
keyboardType:
|
||||
const TextInputType.numberWithOptions(
|
||||
signed: true,
|
||||
decimal: false,
|
||||
),
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.digitsOnly,
|
||||
],
|
||||
textInputAction: index ==
|
||||
widget.gameSession.players
|
||||
.length -
|
||||
1
|
||||
? TextInputAction.done
|
||||
: TextInputAction.next,
|
||||
controller:
|
||||
_scoreControllerList[originalIndex],
|
||||
placeholder:
|
||||
AppLocalizations.of(context).points,
|
||||
textAlign: TextAlign.center,
|
||||
onSubmitted: (_) =>
|
||||
_focusNextTextfield(originalIndex),
|
||||
onChanged: (_) => setState(() {}),
|
||||
),
|
||||
trailing: SizedBox(
|
||||
width: 100,
|
||||
child: CupertinoTextField(
|
||||
maxLength: 3,
|
||||
focusNode: _focusNodeList[originalIndex],
|
||||
keyboardType:
|
||||
const TextInputType.numberWithOptions(
|
||||
signed: true,
|
||||
decimal: false,
|
||||
),
|
||||
const SizedBox(width: 50),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_kamikazePlayerIndex =
|
||||
(_kamikazePlayerIndex ==
|
||||
originalIndex)
|
||||
? null
|
||||
: originalIndex;
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
width: 24,
|
||||
height: 24,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: _kamikazePlayerIndex ==
|
||||
originalIndex
|
||||
? CupertinoColors.systemRed
|
||||
: CupertinoColors
|
||||
.tertiarySystemFill,
|
||||
border: Border.all(
|
||||
color: _kamikazePlayerIndex ==
|
||||
originalIndex
|
||||
? CupertinoColors.systemRed
|
||||
: CupertinoColors.systemGrey,
|
||||
),
|
||||
),
|
||||
child: _kamikazePlayerIndex ==
|
||||
originalIndex
|
||||
? const Icon(
|
||||
CupertinoIcons.exclamationmark,
|
||||
size: 16,
|
||||
color: CupertinoColors.white,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 22),
|
||||
],
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.digitsOnly,
|
||||
],
|
||||
textInputAction: index ==
|
||||
widget.gameSession.players.length - 1
|
||||
? TextInputAction.done
|
||||
: TextInputAction.next,
|
||||
controller:
|
||||
_scoreControllerList[originalIndex],
|
||||
placeholder:
|
||||
AppLocalizations.of(context).points,
|
||||
textAlign: TextAlign.center,
|
||||
onSubmitted: (_) =>
|
||||
_focusNextTextfield(originalIndex),
|
||||
onChanged: (_) => setState(() {}),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
|
||||
child: Center(
|
||||
heightFactor: 1,
|
||||
child: CupertinoButton(
|
||||
sizeStyle: CupertinoButtonSize.medium,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: CustomTheme.buttonBackgroundColor,
|
||||
onPressed: () async {
|
||||
if (await _showKamikazeSheet(context)) {
|
||||
if (!context.mounted) return;
|
||||
_endOfRoundNavigation(context, true);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
AppLocalizations.of(context).kamikaze,
|
||||
style: const TextStyle(
|
||||
color: CupertinoColors.destructiveRed,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -302,21 +261,14 @@ class _RoundViewState extends State<RoundView> {
|
||||
return Container(
|
||||
height: 80,
|
||||
padding: const EdgeInsets.only(bottom: 20),
|
||||
color: CustomTheme.backgroundTintColor,
|
||||
color: CustomTheme.mainElementBackgroundColor,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
CupertinoButton(
|
||||
onPressed: _areRoundInputsValid()
|
||||
? () async {
|
||||
List<int> bonusPlayersIndices = _finishRound();
|
||||
if (bonusPlayersIndices.isNotEmpty) {
|
||||
await _showBonusPopup(
|
||||
context, bonusPlayersIndices);
|
||||
}
|
||||
LocalStorageService.saveGameSessions();
|
||||
if (!context.mounted) return;
|
||||
Navigator.pop(context);
|
||||
? () {
|
||||
_endOfRoundNavigation(context, false);
|
||||
}
|
||||
: null,
|
||||
child: Text(AppLocalizations.of(context).done),
|
||||
@@ -324,21 +276,8 @@ class _RoundViewState extends State<RoundView> {
|
||||
if (!widget.gameSession.isGameFinished)
|
||||
CupertinoButton(
|
||||
onPressed: _areRoundInputsValid()
|
||||
? () async {
|
||||
List<int> bonusPlayersIndices =
|
||||
_finishRound();
|
||||
if (bonusPlayersIndices.isNotEmpty) {
|
||||
await _showBonusPopup(
|
||||
context, bonusPlayersIndices);
|
||||
}
|
||||
LocalStorageService.saveGameSessions();
|
||||
if (widget.gameSession.isGameFinished &&
|
||||
context.mounted) {
|
||||
Navigator.pop(context);
|
||||
} else if (context.mounted) {
|
||||
Navigator.pop(
|
||||
context, widget.roundNumber + 1);
|
||||
}
|
||||
? () {
|
||||
_endOfRoundNavigation(context, true);
|
||||
}
|
||||
: null,
|
||||
child: Text(AppLocalizations.of(context).next_round),
|
||||
@@ -401,6 +340,37 @@ class _RoundViewState extends State<RoundView> {
|
||||
];
|
||||
}
|
||||
|
||||
/// Shows a Cupertino action sheet to select the player who has Kamikaze.
|
||||
/// It returns true if a player was selected, false if the action was cancelled.
|
||||
Future<bool> _showKamikazeSheet(BuildContext context) async {
|
||||
return await showCupertinoModalPopup<bool?>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return CupertinoActionSheet(
|
||||
title: Text(AppLocalizations.of(context).kamikaze),
|
||||
message: Text(AppLocalizations.of(context).who_has_kamikaze),
|
||||
actions: widget.gameSession.players.asMap().entries.map((entry) {
|
||||
final index = entry.key;
|
||||
final name = entry.value;
|
||||
return CupertinoActionSheetAction(
|
||||
onPressed: () {
|
||||
_kamikazePlayerIndex = index;
|
||||
Navigator.pop(context, true);
|
||||
},
|
||||
child: Text(name),
|
||||
);
|
||||
}).toList(),
|
||||
cancelButton: CupertinoActionSheetAction(
|
||||
onPressed: () => Navigator.pop(context, false),
|
||||
isDestructiveAction: true,
|
||||
child: Text(AppLocalizations.of(context).cancel),
|
||||
),
|
||||
);
|
||||
},
|
||||
) ??
|
||||
false;
|
||||
}
|
||||
|
||||
/// Focuses the next text field in the list of text fields.
|
||||
/// [index] is the index of the current text field.
|
||||
void _focusNextTextfield(int index) {
|
||||
@@ -471,10 +441,9 @@ class _RoundViewState extends State<RoundView> {
|
||||
return bonusPlayers;
|
||||
}
|
||||
|
||||
/// Shows a popup dialog with the bonus information.
|
||||
/// Shows a popup dialog with the information which player received the bonus points.
|
||||
Future<void> _showBonusPopup(
|
||||
BuildContext context, List<int> bonusPlayers) async {
|
||||
print('Bonus Popup wird angezeigt');
|
||||
int pointLimit = widget.gameSession.pointLimit;
|
||||
int bonusPoints = (pointLimit / 2).round();
|
||||
|
||||
@@ -521,6 +490,37 @@ class _RoundViewState extends State<RoundView> {
|
||||
return resultText;
|
||||
}
|
||||
|
||||
/// Handles the navigation for the end of the round.
|
||||
/// It checks for bonus players and shows a popup, saves the game session,
|
||||
/// and navigates to the next round or back to the previous screen.
|
||||
/// It takes the BuildContext [context] and a boolean [navigateToNextRound] to determine
|
||||
/// if it should navigate to the next round or not.
|
||||
Future<void> _endOfRoundNavigation(
|
||||
BuildContext context, bool navigateToNextRound) async {
|
||||
List<int> bonusPlayersIndices = _finishRound();
|
||||
if (bonusPlayersIndices.isNotEmpty) {
|
||||
await _showBonusPopup(context, bonusPlayersIndices);
|
||||
}
|
||||
|
||||
LocalStorageService.saveGameSessions();
|
||||
|
||||
if (context.mounted) {
|
||||
// If the game is finished, pop the context and return to the previous screen.
|
||||
if (widget.gameSession.isGameFinished) {
|
||||
Navigator.pop(context);
|
||||
return;
|
||||
}
|
||||
// If navigateToNextRound is false, pop the context and return to the previous screen.
|
||||
if (!navigateToNextRound) {
|
||||
Navigator.pop(context);
|
||||
return;
|
||||
}
|
||||
// If navigateToNextRound is true and the game isn't finished yet,
|
||||
// pop the context and navigate to the next round.
|
||||
Navigator.pop(context, widget.roundNumber + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
for (final controller in _scoreControllerList) {
|
||||
|
||||
@@ -17,7 +17,7 @@ class _TabViewState extends State<TabView> {
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoTabScaffold(
|
||||
tabBar: CupertinoTabBar(
|
||||
backgroundColor: CustomTheme.backgroundTintColor,
|
||||
backgroundColor: CustomTheme.mainElementBackgroundColor,
|
||||
iconSize: 27,
|
||||
height: 55,
|
||||
items: <BottomNavigationBarItem>[
|
||||
|
||||
@@ -2,7 +2,7 @@ name: cabo_counter
|
||||
description: "Mobile app for the card game Cabo"
|
||||
publish_to: 'none'
|
||||
|
||||
version: 0.4.8+525
|
||||
version: 0.4.9+533
|
||||
|
||||
environment:
|
||||
sdk: ^3.5.4
|
||||
|
||||
Reference in New Issue
Block a user