Merge pull request #88 from flixcoo/feature/46-implement-native-rating-dialogs
Implement native rating dialogs
This commit is contained in:
@@ -11,6 +11,4 @@ linter:
|
||||
prefer_const_literals_to_create_immutables: true
|
||||
unnecessary_const: true
|
||||
lines_longer_than_80_chars: false
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
constant_identifier_names: false
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
arb-dir: lib/l10n
|
||||
arb-dir: lib/l10n/arb
|
||||
template-arb-file: app_de.arb
|
||||
untranslated-messages-file: lib/l10n/untranslated_messages.json
|
||||
untranslated-messages-file: lib/l10n/arb/untranslated_messages.json
|
||||
nullable-getter: false
|
||||
output-localization-file: app_localizations.dart
|
||||
output-dir: lib/l10n/generated
|
||||
22
lib/core/constants.dart
Normal file
22
lib/core/constants.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:rate_my_app/rate_my_app.dart';
|
||||
|
||||
class Constants {
|
||||
static const String appDevPhase = 'Beta';
|
||||
|
||||
static const String INSTAGRAM_LINK = 'https://instagram.felixkirchner.de';
|
||||
static const String GITHUB_LINK = 'https://github.felixkirchner.de';
|
||||
static const String GITHUB_ISSUES_LINK =
|
||||
'https://cabocounter-issues.felixkirchner.de';
|
||||
static const String GITHUB_WIKI_LINK =
|
||||
'https://cabocounter-wiki.felixkirchner.de';
|
||||
static const String EMAIL = 'cabocounter@felixkirchner.de';
|
||||
static const String PRIVACY_POLICY_LINK =
|
||||
'https://www.privacypolicies.com/live/1b3759d4-b2f1-4511-8e3b-21bb1626be68';
|
||||
|
||||
static RateMyApp rateMyApp = RateMyApp(
|
||||
appStoreIdentifier: '6747105718',
|
||||
minDays: 15,
|
||||
remindDays: 45,
|
||||
minLaunches: 15,
|
||||
remindLaunches: 40);
|
||||
}
|
||||
@@ -30,6 +30,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre_rating_title": "Gefällt dir die App?",
|
||||
"pre_rating_message": "Feedback hilft mir, die App zu verbessern. Vielen Dank!",
|
||||
"yes": "Ja",
|
||||
"no": "Nein",
|
||||
"bad_rating_title": "Unzufrieden mit der App?",
|
||||
"bad_rating_message": "Schreib mir gerne direkt eine E-Mail, damit wir dein Problem lösen können!",
|
||||
"contact_email": "E-Mail schreiben",
|
||||
"email_subject": "Feedback: Cabo Counter App",
|
||||
"email_body": "Ich habe folgendes Feedback...",
|
||||
|
||||
"overview": "Übersicht",
|
||||
"new_game": "Neues Spiel",
|
||||
"game_title": "Titel des Spiels",
|
||||
@@ -103,6 +113,7 @@
|
||||
"create_issue": "Issue erstellen",
|
||||
"wiki": "Wiki",
|
||||
"app_version": "App-Version",
|
||||
"privacy_policy": "Datenschutzerklärung",
|
||||
"build": "Build-Nr.",
|
||||
"loading": "Lädt...",
|
||||
|
||||
@@ -30,6 +30,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"pre_rating_title": "Do you like the app?",
|
||||
"pre_rating_message": "Feedback helps me to continuously improve the app. Thank you!",
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
"bad_rating_title": "Not satisfied?",
|
||||
"bad_rating_message": "If you are not satisfied with the app, please let me know before leaving a bad rating. I will try to fix the issue as soon as possible.",
|
||||
"contact_email": "Contact via E-Mail",
|
||||
"email_subject": "Feedback: Cabo Counter App",
|
||||
"email_body": "I have the following feedback...",
|
||||
|
||||
"overview": "Overview",
|
||||
"new_game": "New Game",
|
||||
"game_title": "Game Title",
|
||||
@@ -103,6 +113,7 @@
|
||||
"create_issue": "Create Issue",
|
||||
"wiki": "Wiki",
|
||||
"app_version": "App Version",
|
||||
"privacy_policy": "Privacy Policy",
|
||||
"loading": "Loading...",
|
||||
"build": "Build No.",
|
||||
|
||||
@@ -18,7 +18,7 @@ import 'app_localizations_en.dart';
|
||||
/// `supportedLocales` list. For example:
|
||||
///
|
||||
/// ```dart
|
||||
/// import 'l10n/app_localizations.dart';
|
||||
/// import 'generated/app_localizations.dart';
|
||||
///
|
||||
/// return MaterialApp(
|
||||
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
@@ -218,6 +218,60 @@ abstract class AppLocalizations {
|
||||
/// **'Bist du sicher, dass du das Spiel \"{gameTitle}\" löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.'**
|
||||
String delete_game_message(String gameTitle);
|
||||
|
||||
/// No description provided for @pre_rating_title.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
/// **'Gefällt dir die App?'**
|
||||
String get pre_rating_title;
|
||||
|
||||
/// No description provided for @pre_rating_message.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
/// **'Feedback hilft mir, die App zu verbessern. Vielen Dank!'**
|
||||
String get pre_rating_message;
|
||||
|
||||
/// No description provided for @yes.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
/// **'Ja'**
|
||||
String get yes;
|
||||
|
||||
/// No description provided for @no.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
/// **'Nein'**
|
||||
String get no;
|
||||
|
||||
/// No description provided for @bad_rating_title.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
/// **'Unzufrieden mit der App?'**
|
||||
String get bad_rating_title;
|
||||
|
||||
/// No description provided for @bad_rating_message.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
/// **'Schreib mir gerne direkt eine E-Mail, damit wir dein Problem lösen können!'**
|
||||
String get bad_rating_message;
|
||||
|
||||
/// No description provided for @contact_email.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
/// **'E-Mail schreiben'**
|
||||
String get contact_email;
|
||||
|
||||
/// No description provided for @email_subject.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
/// **'Feedback: Cabo Counter App'**
|
||||
String get email_subject;
|
||||
|
||||
/// No description provided for @email_body.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
/// **'Ich habe folgendes Feedback...'**
|
||||
String get email_body;
|
||||
|
||||
/// No description provided for @overview.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
@@ -566,6 +620,12 @@ abstract class AppLocalizations {
|
||||
/// **'App-Version'**
|
||||
String get app_version;
|
||||
|
||||
/// No description provided for @privacy_policy.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
/// **'Datenschutzerklärung'**
|
||||
String get privacy_policy;
|
||||
|
||||
/// No description provided for @build.
|
||||
///
|
||||
/// In de, this message translates to:
|
||||
@@ -71,6 +71,35 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
return 'Bist du sicher, dass du das Spiel \"$gameTitle\" löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get pre_rating_title => 'Gefällt dir die App?';
|
||||
|
||||
@override
|
||||
String get pre_rating_message =>
|
||||
'Feedback hilft mir, die App zu verbessern. Vielen Dank!';
|
||||
|
||||
@override
|
||||
String get yes => 'Ja';
|
||||
|
||||
@override
|
||||
String get no => 'Nein';
|
||||
|
||||
@override
|
||||
String get bad_rating_title => 'Unzufrieden mit der App?';
|
||||
|
||||
@override
|
||||
String get bad_rating_message =>
|
||||
'Schreib mir gerne direkt eine E-Mail, damit wir dein Problem lösen können!';
|
||||
|
||||
@override
|
||||
String get contact_email => 'E-Mail schreiben';
|
||||
|
||||
@override
|
||||
String get email_subject => 'Feedback: Cabo Counter App';
|
||||
|
||||
@override
|
||||
String get email_body => 'Ich habe folgendes Feedback...';
|
||||
|
||||
@override
|
||||
String get overview => 'Übersicht';
|
||||
|
||||
@@ -256,6 +285,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
@override
|
||||
String get app_version => 'App-Version';
|
||||
|
||||
@override
|
||||
String get privacy_policy => 'Datenschutzerklärung';
|
||||
|
||||
@override
|
||||
String get build => 'Build-Nr.';
|
||||
|
||||
@@ -71,6 +71,35 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
return 'Are you sure you want to delete the game \"$gameTitle\"? This action cannot be undone.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get pre_rating_title => 'Do you like the app?';
|
||||
|
||||
@override
|
||||
String get pre_rating_message =>
|
||||
'Feedback helps me to continuously improve the app. Thank you!';
|
||||
|
||||
@override
|
||||
String get yes => 'Yes';
|
||||
|
||||
@override
|
||||
String get no => 'No';
|
||||
|
||||
@override
|
||||
String get bad_rating_title => 'Not satisfied?';
|
||||
|
||||
@override
|
||||
String get bad_rating_message =>
|
||||
'If you are not satisfied with the app, please let me know before leaving a bad rating. I will try to fix the issue as soon as possible.';
|
||||
|
||||
@override
|
||||
String get contact_email => 'Contac via E-Mail';
|
||||
|
||||
@override
|
||||
String get email_subject => 'Feedback: Cabo Counter App';
|
||||
|
||||
@override
|
||||
String get email_body => 'I have the following feedback...';
|
||||
|
||||
@override
|
||||
String get overview => 'Overview';
|
||||
|
||||
@@ -253,6 +282,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get app_version => 'App Version';
|
||||
|
||||
@override
|
||||
String get privacy_policy => 'Privacy Policy';
|
||||
|
||||
@override
|
||||
String get build => 'Build No.';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:cabo_counter/l10n/app_localizations.dart';
|
||||
import 'package:cabo_counter/core/custom_theme.dart';
|
||||
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
|
||||
import 'package:cabo_counter/presentation/views/tab_view.dart';
|
||||
import 'package:cabo_counter/services/config_service.dart';
|
||||
import 'package:cabo_counter/services/local_storage_service.dart';
|
||||
import 'package:cabo_counter/services/version_service.dart';
|
||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import 'package:cabo_counter/l10n/app_localizations.dart';
|
||||
import 'package:cabo_counter/core/constants.dart';
|
||||
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
|
||||
import 'package:cabo_counter/services/version_service.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class InformationView extends StatelessWidget {
|
||||
const InformationView({super.key});
|
||||
class AboutView extends StatelessWidget {
|
||||
const AboutView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -28,9 +30,13 @@ class InformationView extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${AppLocalizations.of(context).app_version} ${VersionService.getVersionWithBuild()}',
|
||||
style: TextStyle(fontSize: 15, color: Colors.grey[300]),
|
||||
),
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 20, vertical: 30),
|
||||
const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
||||
child: SizedBox(
|
||||
height: 200,
|
||||
child: Image.asset('assets/cabo_counter-logo_rounded.png'),
|
||||
@@ -54,15 +60,15 @@ class InformationView extends StatelessWidget {
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () =>
|
||||
launchUrl(Uri.parse('https://www.instagram.com/fx.kr')),
|
||||
launchUrl(Uri.parse(Constants.INSTAGRAM_LINK)),
|
||||
icon: const Icon(FontAwesomeIcons.instagram)),
|
||||
IconButton(
|
||||
onPressed: () => launchUrl(
|
||||
Uri.parse('mailto:felix.kirchner.fk@gmail.com')),
|
||||
onPressed: () =>
|
||||
launchUrl(Uri.parse('mailto:${Constants.EMAIL}')),
|
||||
icon: const Icon(CupertinoIcons.envelope)),
|
||||
IconButton(
|
||||
onPressed: () =>
|
||||
launchUrl(Uri.parse('https://www.github.com/flixcoo')),
|
||||
launchUrl(Uri.parse(Constants.GITHUB_LINK)),
|
||||
icon: const Icon(FontAwesomeIcons.github)),
|
||||
],
|
||||
),
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'package:cabo_counter/core/custom_theme.dart';
|
||||
import 'package:cabo_counter/data/game_manager.dart';
|
||||
import 'package:cabo_counter/data/game_session.dart';
|
||||
import 'package:cabo_counter/l10n/app_localizations.dart';
|
||||
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
|
||||
import 'package:cabo_counter/presentation/views/create_game_view.dart';
|
||||
import 'package:cabo_counter/presentation/views/graph_view.dart';
|
||||
import 'package:cabo_counter/presentation/views/round_view.dart';
|
||||
import 'package:cabo_counter/services/local_storage_service.dart';
|
||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -235,7 +235,8 @@ class _ActiveGameViewState extends State<ActiveGameView> {
|
||||
child: Text(
|
||||
AppLocalizations.of(context).end_game,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold, color: Colors.red),
|
||||
fontWeight: FontWeight.bold,
|
||||
color: CupertinoColors.destructiveRed),
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'package:cabo_counter/core/custom_theme.dart';
|
||||
import 'package:cabo_counter/data/game_manager.dart';
|
||||
import 'package:cabo_counter/data/game_session.dart';
|
||||
import 'package:cabo_counter/l10n/app_localizations.dart';
|
||||
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
|
||||
import 'package:cabo_counter/presentation/views/active_game_view.dart';
|
||||
import 'package:cabo_counter/presentation/views/mode_selection_view.dart';
|
||||
import 'package:cabo_counter/services/config_service.dart';
|
||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
enum CreateStatus {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:cabo_counter/data/game_session.dart';
|
||||
import 'package:cabo_counter/l10n/app_localizations.dart';
|
||||
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
import 'package:cabo_counter/core/constants.dart';
|
||||
import 'package:cabo_counter/core/custom_theme.dart';
|
||||
import 'package:cabo_counter/data/game_manager.dart';
|
||||
import 'package:cabo_counter/l10n/app_localizations.dart';
|
||||
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
|
||||
import 'package:cabo_counter/presentation/views/active_game_view.dart';
|
||||
import 'package:cabo_counter/presentation/views/create_game_view.dart';
|
||||
import 'package:cabo_counter/presentation/views/settings_view.dart';
|
||||
import 'package:cabo_counter/services/config_service.dart';
|
||||
import 'package:cabo_counter/services/local_storage_service.dart';
|
||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
enum PreRatingDialogDecision { yes, no, cancel }
|
||||
|
||||
enum BadRatingDialogDecision { email, cancel }
|
||||
|
||||
class MainMenuView extends StatefulWidget {
|
||||
const MainMenuView({super.key});
|
||||
@@ -29,6 +35,17 @@ class _MainMenuViewState extends State<MainMenuView> {
|
||||
});
|
||||
});
|
||||
gameManager.addListener(_updateView);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await Constants.rateMyApp.init();
|
||||
|
||||
if (Constants.rateMyApp.shouldOpenDialog &&
|
||||
Constants.appDevPhase != 'Beta') {
|
||||
await Future.delayed(const Duration(milliseconds: 600));
|
||||
if (!mounted) return;
|
||||
_handleFeedbackDialog(context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _updateView() {
|
||||
@@ -57,14 +74,12 @@ class _MainMenuViewState extends State<MainMenuView> {
|
||||
icon: const Icon(CupertinoIcons.settings, size: 30)),
|
||||
middle: const Text('Cabo Counter'),
|
||||
trailing: IconButton(
|
||||
onPressed: () => {
|
||||
Navigator.push(
|
||||
onPressed: () => Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) => const CreateGameView(),
|
||||
),
|
||||
)
|
||||
},
|
||||
),
|
||||
icon: const Icon(CupertinoIcons.add)),
|
||||
),
|
||||
child: CupertinoPageScaffold(
|
||||
@@ -128,7 +143,7 @@ class _MainMenuViewState extends State<MainMenuView> {
|
||||
final String gameTitle = gameManager
|
||||
.gameList[index].gameTitle;
|
||||
return await _showDeleteGamePopup(
|
||||
gameTitle);
|
||||
context, gameTitle);
|
||||
},
|
||||
onDismissed: (direction) {
|
||||
gameManager
|
||||
@@ -204,40 +219,144 @@ class _MainMenuViewState extends State<MainMenuView> {
|
||||
return AppLocalizations.of(context).unlimited;
|
||||
}
|
||||
|
||||
/// Handles the feedback dialog when the conditions for rating are met.
|
||||
/// It shows a dialog asking the user if they like the app,
|
||||
/// and based on their response, it either opens the rating dialog or an email client for feedback.
|
||||
Future<void> _handleFeedbackDialog(BuildContext context) async {
|
||||
final String emailSubject = AppLocalizations.of(context).email_subject;
|
||||
final String emailBody = AppLocalizations.of(context).email_body;
|
||||
|
||||
final Uri emailUri = Uri(
|
||||
scheme: 'mailto',
|
||||
path: Constants.EMAIL,
|
||||
query: 'subject=$emailSubject'
|
||||
'&body=$emailBody',
|
||||
);
|
||||
|
||||
PreRatingDialogDecision preRatingDecision =
|
||||
await _showPreRatingDialog(context);
|
||||
BadRatingDialogDecision badRatingDecision = BadRatingDialogDecision.cancel;
|
||||
|
||||
// so that the bad rating dialog is not shown immediately
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
|
||||
switch (preRatingDecision) {
|
||||
case PreRatingDialogDecision.yes:
|
||||
if (context.mounted) Constants.rateMyApp.showStarRateDialog(context);
|
||||
break;
|
||||
case PreRatingDialogDecision.no:
|
||||
if (context.mounted) {
|
||||
badRatingDecision = await _showBadRatingDialog(context);
|
||||
}
|
||||
if (badRatingDecision == BadRatingDialogDecision.email) {
|
||||
if (context.mounted) {
|
||||
launchUrl(emailUri);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PreRatingDialogDecision.cancel:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Shows a confirmation dialog to delete all game sessions.
|
||||
/// Returns true if the user confirms the deletion, false otherwise.
|
||||
/// [gameTitle] is the title of the game session to be deleted.
|
||||
Future<bool> _showDeleteGamePopup(String gameTitle) async {
|
||||
bool? shouldDelete = await showCupertinoDialog<bool>(
|
||||
Future<bool> _showDeleteGamePopup(
|
||||
BuildContext context, String gameTitle) async {
|
||||
return await showCupertinoDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
builder: (BuildContext context) {
|
||||
return CupertinoAlertDialog(
|
||||
title: Text(AppLocalizations.of(context).delete_game_title),
|
||||
content: Text(
|
||||
AppLocalizations.of(context).delete_game_message(gameTitle)),
|
||||
title: Text(
|
||||
AppLocalizations.of(context).delete_game_title,
|
||||
),
|
||||
content: Text(AppLocalizations.of(context)
|
||||
.delete_game_message(gameTitle)),
|
||||
actions: [
|
||||
CupertinoDialogAction(
|
||||
onPressed: () {
|
||||
Navigator.pop(context, false);
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
child: Text(AppLocalizations.of(context).cancel),
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
isDestructiveAction: true,
|
||||
isDefaultAction: true,
|
||||
onPressed: () {
|
||||
Navigator.pop(context, true);
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
child: Text(
|
||||
AppLocalizations.of(context).delete,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold, color: Colors.red),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
)
|
||||
]);
|
||||
},
|
||||
) ??
|
||||
false;
|
||||
return shouldDelete;
|
||||
}
|
||||
|
||||
/// Shows a dialog asking the user if they like the app.
|
||||
/// Returns the user's decision as an integer.
|
||||
/// - PRE_RATING_DIALOG_YES: User likes the app and wants to rate it.
|
||||
/// - PRE_RATING_DIALOG_NO: User does not like the app and wants to provide feedback.
|
||||
/// - PRE_RATING_DIALOG_CANCEL: User cancels the dialog.
|
||||
Future<PreRatingDialogDecision> _showPreRatingDialog(
|
||||
BuildContext context) async {
|
||||
return await showCupertinoDialog<PreRatingDialogDecision>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => CupertinoAlertDialog(
|
||||
title: Text(AppLocalizations.of(context).pre_rating_title),
|
||||
content:
|
||||
Text(AppLocalizations.of(context).pre_rating_message),
|
||||
actions: [
|
||||
CupertinoDialogAction(
|
||||
onPressed: () => Navigator.of(context)
|
||||
.pop(PreRatingDialogDecision.yes),
|
||||
isDefaultAction: true,
|
||||
child: Text(AppLocalizations.of(context).yes),
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop(PreRatingDialogDecision.no),
|
||||
child: Text(AppLocalizations.of(context).no),
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
isDestructiveAction: true,
|
||||
child: Text(AppLocalizations.of(context).cancel),
|
||||
)
|
||||
],
|
||||
)) ??
|
||||
PreRatingDialogDecision.cancel;
|
||||
}
|
||||
|
||||
/// Shows a dialog asking the user for feedback if they do not like the app.
|
||||
/// Returns the user's decision as an integer.
|
||||
/// - BAD_RATING_DIALOG_EMAIL: User wants to send an email with feedback.
|
||||
/// - BAD_RATING_DIALOG_CANCEL: User cancels the dialog.
|
||||
Future<BadRatingDialogDecision> _showBadRatingDialog(
|
||||
BuildContext context) async {
|
||||
return await showCupertinoDialog<BadRatingDialogDecision>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => CupertinoAlertDialog(
|
||||
title: Text(AppLocalizations.of(context).bad_rating_title),
|
||||
content:
|
||||
Text(AppLocalizations.of(context).bad_rating_message),
|
||||
actions: [
|
||||
CupertinoDialogAction(
|
||||
isDefaultAction: true,
|
||||
onPressed: () => Navigator.of(context)
|
||||
.pop(BadRatingDialogDecision.email),
|
||||
child: Text(AppLocalizations.of(context).contact_email),
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
isDestructiveAction: true,
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(AppLocalizations.of(context).cancel))
|
||||
],
|
||||
)) ??
|
||||
BadRatingDialogDecision.cancel;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:cabo_counter/l10n/app_localizations.dart';
|
||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
||||
import 'package:cabo_counter/core/custom_theme.dart';
|
||||
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class ModeSelectionMenu extends StatelessWidget {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:cabo_counter/core/custom_theme.dart';
|
||||
import 'package:cabo_counter/data/game_session.dart';
|
||||
import 'package:cabo_counter/l10n/app_localizations.dart';
|
||||
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
|
||||
import 'package:cabo_counter/services/local_storage_service.dart';
|
||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import 'package:cabo_counter/l10n/app_localizations.dart';
|
||||
import 'package:cabo_counter/core/constants.dart';
|
||||
import 'package:cabo_counter/core/custom_theme.dart';
|
||||
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
|
||||
import 'package:cabo_counter/presentation/widgets/custom_form_row.dart';
|
||||
import 'package:cabo_counter/presentation/widgets/stepper.dart';
|
||||
import 'package:cabo_counter/presentation/widgets/custom_stepper.dart';
|
||||
import 'package:cabo_counter/services/config_service.dart';
|
||||
import 'package:cabo_counter/services/local_storage_service.dart';
|
||||
import 'package:cabo_counter/services/version_service.dart';
|
||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
@@ -53,7 +54,7 @@ class _SettingsViewState extends State<SettingsView> {
|
||||
CustomFormRow(
|
||||
prefixText: 'Cabo-Strafe',
|
||||
prefixIcon: CupertinoIcons.bolt_fill,
|
||||
suffixWidget: Stepper(
|
||||
suffixWidget: CustomStepper(
|
||||
key: _stepperKey1,
|
||||
initialValue: ConfigService.caboPenalty,
|
||||
minValue: 0,
|
||||
@@ -70,7 +71,7 @@ class _SettingsViewState extends State<SettingsView> {
|
||||
CustomFormRow(
|
||||
prefixText: 'Punkte-Limit',
|
||||
prefixIcon: FontAwesomeIcons.bullseye,
|
||||
suffixWidget: Stepper(
|
||||
suffixWidget: CustomStepper(
|
||||
key: _stepperKey2,
|
||||
initialValue: ConfigService.pointLimit,
|
||||
minValue: 30,
|
||||
@@ -93,7 +94,6 @@ class _SettingsViewState extends State<SettingsView> {
|
||||
setState(() {
|
||||
_stepperKey1 = UniqueKey();
|
||||
_stepperKey2 = UniqueKey();
|
||||
print('Config reset to default');
|
||||
});
|
||||
},
|
||||
)
|
||||
@@ -142,17 +142,25 @@ class _SettingsViewState extends State<SettingsView> {
|
||||
margin: EdgeInsets.zero,
|
||||
children: [
|
||||
CustomFormRow(
|
||||
prefixText: AppLocalizations.of(context).create_issue,
|
||||
prefixIcon: FontAwesomeIcons.github,
|
||||
onPressed: () => launchUrl(Uri.parse(
|
||||
'https://github.com/flixcoo/Cabo-Counter/issues')),
|
||||
prefixText: AppLocalizations.of(context).wiki,
|
||||
prefixIcon: CupertinoIcons.book,
|
||||
onPressed: () =>
|
||||
launchUrl(Uri.parse(Constants.GITHUB_WIKI_LINK)),
|
||||
suffixWidget: const CupertinoListTileChevron(),
|
||||
),
|
||||
CustomFormRow(
|
||||
prefixText: AppLocalizations.of(context).wiki,
|
||||
prefixIcon: CupertinoIcons.book,
|
||||
onPressed: () => launchUrl(Uri.parse(
|
||||
'https://github.com/flixcoo/Cabo-Counter/wiki')),
|
||||
prefixText:
|
||||
AppLocalizations.of(context).privacy_policy,
|
||||
prefixIcon: CupertinoIcons.doc_append,
|
||||
onPressed: () => launchUrl(
|
||||
Uri.parse(Constants.PRIVACY_POLICY_LINK)),
|
||||
suffixWidget: const CupertinoListTileChevron(),
|
||||
),
|
||||
CustomFormRow(
|
||||
prefixText: AppLocalizations.of(context).error_found,
|
||||
prefixIcon: FontAwesomeIcons.github,
|
||||
onPressed: () => launchUrl(
|
||||
Uri.parse(Constants.GITHUB_ISSUES_LINK)),
|
||||
suffixWidget: const CupertinoListTileChevron(),
|
||||
),
|
||||
CustomFormRow(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:cabo_counter/l10n/app_localizations.dart';
|
||||
import 'package:cabo_counter/presentation/views/information_view.dart';
|
||||
import 'package:cabo_counter/core/custom_theme.dart';
|
||||
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
|
||||
import 'package:cabo_counter/presentation/views/about_view.dart';
|
||||
import 'package:cabo_counter/presentation/views/main_menu_view.dart';
|
||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class TabView extends StatefulWidget {
|
||||
@@ -39,7 +39,7 @@ class _TabViewState extends State<TabView> {
|
||||
if (index == 0) {
|
||||
return const MainMenuView();
|
||||
} else {
|
||||
return const InformationView();
|
||||
return const AboutView();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:cabo_counter/presentation/widgets/stepper.dart';
|
||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
||||
import 'package:cabo_counter/core/custom_theme.dart';
|
||||
import 'package:cabo_counter/presentation/widgets/custom_stepper.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class CustomFormRow extends StatefulWidget {
|
||||
@@ -43,7 +43,7 @@ class _CustomFormRowState extends State<CustomFormRow> {
|
||||
Text(widget.prefixText),
|
||||
],
|
||||
),
|
||||
padding: suffixWidget is Stepper
|
||||
padding: suffixWidget is CustomStepper
|
||||
? const EdgeInsets.fromLTRB(15, 0, 0, 0)
|
||||
: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
||||
child: suffixWidget,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
||||
import 'package:cabo_counter/core/custom_theme.dart';
|
||||
import 'package:flutter/cupertino.dart'; // Für iOS-Style
|
||||
|
||||
class Stepper extends StatefulWidget {
|
||||
class CustomStepper extends StatefulWidget {
|
||||
final int minValue;
|
||||
final int maxValue;
|
||||
final int? initialValue;
|
||||
final int step;
|
||||
final ValueChanged<int> onChanged;
|
||||
const Stepper({
|
||||
const CustomStepper({
|
||||
super.key,
|
||||
required this.minValue,
|
||||
required this.maxValue,
|
||||
@@ -18,10 +18,10 @@ class Stepper extends StatefulWidget {
|
||||
|
||||
@override
|
||||
// ignore: library_private_types_in_public_api
|
||||
_StepperState createState() => _StepperState();
|
||||
_CustomStepperState createState() => _CustomStepperState();
|
||||
}
|
||||
|
||||
class _StepperState extends State<Stepper> {
|
||||
class _CustomStepperState extends State<CustomStepper> {
|
||||
late int _value;
|
||||
|
||||
@override
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:cabo_counter/utility/globals.dart';
|
||||
import 'package:cabo_counter/core/constants.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
class VersionService {
|
||||
@@ -19,7 +19,7 @@ class VersionService {
|
||||
if (_version == '-.-.-') {
|
||||
return getVersionNumber();
|
||||
}
|
||||
return '${Globals.appDevPhase} $_version';
|
||||
return '${Constants.appDevPhase} $_version';
|
||||
}
|
||||
|
||||
static String getBuildNumber() {
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
class Globals {
|
||||
static String appDevPhase = 'Beta';
|
||||
}
|
||||
@@ -2,7 +2,7 @@ name: cabo_counter
|
||||
description: "Mobile app for the card game Cabo"
|
||||
publish_to: 'none'
|
||||
|
||||
version: 0.4.0+382
|
||||
version: 0.4.0+467
|
||||
|
||||
environment:
|
||||
sdk: ^3.5.4
|
||||
@@ -27,6 +27,7 @@ dependencies:
|
||||
intl: any
|
||||
syncfusion_flutter_charts: ^30.1.37
|
||||
uuid: ^4.5.1
|
||||
rate_my_app: ^2.3.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user