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
|
prefer_const_literals_to_create_immutables: true
|
||||||
unnecessary_const: true
|
unnecessary_const: true
|
||||||
lines_longer_than_80_chars: false
|
lines_longer_than_80_chars: false
|
||||||
|
constant_identifier_names: false
|
||||||
# Additional information about this file can be found at
|
|
||||||
# https://dart.dev/guides/language/analysis-options
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
arb-dir: lib/l10n
|
arb-dir: lib/l10n/arb
|
||||||
template-arb-file: app_de.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
|
nullable-getter: false
|
||||||
output-localization-file: app_localizations.dart
|
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",
|
"overview": "Übersicht",
|
||||||
"new_game": "Neues Spiel",
|
"new_game": "Neues Spiel",
|
||||||
"game_title": "Titel des Spiels",
|
"game_title": "Titel des Spiels",
|
||||||
@@ -103,6 +113,7 @@
|
|||||||
"create_issue": "Issue erstellen",
|
"create_issue": "Issue erstellen",
|
||||||
"wiki": "Wiki",
|
"wiki": "Wiki",
|
||||||
"app_version": "App-Version",
|
"app_version": "App-Version",
|
||||||
|
"privacy_policy": "Datenschutzerklärung",
|
||||||
"build": "Build-Nr.",
|
"build": "Build-Nr.",
|
||||||
"loading": "Lädt...",
|
"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",
|
"overview": "Overview",
|
||||||
"new_game": "New Game",
|
"new_game": "New Game",
|
||||||
"game_title": "Game Title",
|
"game_title": "Game Title",
|
||||||
@@ -103,6 +113,7 @@
|
|||||||
"create_issue": "Create Issue",
|
"create_issue": "Create Issue",
|
||||||
"wiki": "Wiki",
|
"wiki": "Wiki",
|
||||||
"app_version": "App Version",
|
"app_version": "App Version",
|
||||||
|
"privacy_policy": "Privacy Policy",
|
||||||
"loading": "Loading...",
|
"loading": "Loading...",
|
||||||
"build": "Build No.",
|
"build": "Build No.",
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ import 'app_localizations_en.dart';
|
|||||||
/// `supportedLocales` list. For example:
|
/// `supportedLocales` list. For example:
|
||||||
///
|
///
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// import 'l10n/app_localizations.dart';
|
/// import 'generated/app_localizations.dart';
|
||||||
///
|
///
|
||||||
/// return MaterialApp(
|
/// return MaterialApp(
|
||||||
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
|
/// 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.'**
|
/// **'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);
|
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.
|
/// No description provided for @overview.
|
||||||
///
|
///
|
||||||
/// In de, this message translates to:
|
/// In de, this message translates to:
|
||||||
@@ -566,6 +620,12 @@ abstract class AppLocalizations {
|
|||||||
/// **'App-Version'**
|
/// **'App-Version'**
|
||||||
String get 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.
|
/// No description provided for @build.
|
||||||
///
|
///
|
||||||
/// In de, this message translates to:
|
/// 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.';
|
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
|
@override
|
||||||
String get overview => 'Übersicht';
|
String get overview => 'Übersicht';
|
||||||
|
|
||||||
@@ -256,6 +285,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get app_version => 'App-Version';
|
String get app_version => 'App-Version';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get privacy_policy => 'Datenschutzerklärung';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get build => 'Build-Nr.';
|
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.';
|
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
|
@override
|
||||||
String get overview => 'Overview';
|
String get overview => 'Overview';
|
||||||
|
|
||||||
@@ -253,6 +282,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get app_version => 'App Version';
|
String get app_version => 'App Version';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get privacy_policy => 'Privacy Policy';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get build => 'Build No.';
|
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/presentation/views/tab_view.dart';
|
||||||
import 'package:cabo_counter/services/config_service.dart';
|
import 'package:cabo_counter/services/config_service.dart';
|
||||||
import 'package:cabo_counter/services/local_storage_service.dart';
|
import 'package:cabo_counter/services/local_storage_service.dart';
|
||||||
import 'package:cabo_counter/services/version_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/cupertino.dart';
|
||||||
import 'package:flutter/services.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/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class InformationView extends StatelessWidget {
|
class AboutView extends StatelessWidget {
|
||||||
const InformationView({super.key});
|
const AboutView({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
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(
|
||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(horizontal: 20, vertical: 30),
|
const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 200,
|
height: 200,
|
||||||
child: Image.asset('assets/cabo_counter-logo_rounded.png'),
|
child: Image.asset('assets/cabo_counter-logo_rounded.png'),
|
||||||
@@ -54,15 +60,15 @@ class InformationView extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
launchUrl(Uri.parse('https://www.instagram.com/fx.kr')),
|
launchUrl(Uri.parse(Constants.INSTAGRAM_LINK)),
|
||||||
icon: const Icon(FontAwesomeIcons.instagram)),
|
icon: const Icon(FontAwesomeIcons.instagram)),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => launchUrl(
|
onPressed: () =>
|
||||||
Uri.parse('mailto:felix.kirchner.fk@gmail.com')),
|
launchUrl(Uri.parse('mailto:${Constants.EMAIL}')),
|
||||||
icon: const Icon(CupertinoIcons.envelope)),
|
icon: const Icon(CupertinoIcons.envelope)),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
launchUrl(Uri.parse('https://www.github.com/flixcoo')),
|
launchUrl(Uri.parse(Constants.GITHUB_LINK)),
|
||||||
icon: const Icon(FontAwesomeIcons.github)),
|
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_manager.dart';
|
||||||
import 'package:cabo_counter/data/game_session.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/create_game_view.dart';
|
||||||
import 'package:cabo_counter/presentation/views/graph_view.dart';
|
import 'package:cabo_counter/presentation/views/graph_view.dart';
|
||||||
import 'package:cabo_counter/presentation/views/round_view.dart';
|
import 'package:cabo_counter/presentation/views/round_view.dart';
|
||||||
import 'package:cabo_counter/services/local_storage_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/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@@ -235,7 +235,8 @@ class _ActiveGameViewState extends State<ActiveGameView> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
AppLocalizations.of(context).end_game,
|
AppLocalizations.of(context).end_game,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold, color: Colors.red),
|
fontWeight: FontWeight.bold,
|
||||||
|
color: CupertinoColors.destructiveRed),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
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_manager.dart';
|
||||||
import 'package:cabo_counter/data/game_session.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/active_game_view.dart';
|
||||||
import 'package:cabo_counter/presentation/views/mode_selection_view.dart';
|
import 'package:cabo_counter/presentation/views/mode_selection_view.dart';
|
||||||
import 'package:cabo_counter/services/config_service.dart';
|
import 'package:cabo_counter/services/config_service.dart';
|
||||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
enum CreateStatus {
|
enum CreateStatus {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:cabo_counter/data/game_session.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:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncfusion_flutter_charts/charts.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/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/active_game_view.dart';
|
||||||
import 'package:cabo_counter/presentation/views/create_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/presentation/views/settings_view.dart';
|
||||||
import 'package:cabo_counter/services/config_service.dart';
|
import 'package:cabo_counter/services/config_service.dart';
|
||||||
import 'package:cabo_counter/services/local_storage_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/cupertino.dart';
|
||||||
import 'package:flutter/material.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 {
|
class MainMenuView extends StatefulWidget {
|
||||||
const MainMenuView({super.key});
|
const MainMenuView({super.key});
|
||||||
@@ -29,6 +35,17 @@ class _MainMenuViewState extends State<MainMenuView> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
gameManager.addListener(_updateView);
|
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() {
|
void _updateView() {
|
||||||
@@ -57,14 +74,12 @@ class _MainMenuViewState extends State<MainMenuView> {
|
|||||||
icon: const Icon(CupertinoIcons.settings, size: 30)),
|
icon: const Icon(CupertinoIcons.settings, size: 30)),
|
||||||
middle: const Text('Cabo Counter'),
|
middle: const Text('Cabo Counter'),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
onPressed: () => {
|
onPressed: () => Navigator.push(
|
||||||
Navigator.push(
|
context,
|
||||||
context,
|
CupertinoPageRoute(
|
||||||
CupertinoPageRoute(
|
builder: (context) => const CreateGameView(),
|
||||||
builder: (context) => const CreateGameView(),
|
),
|
||||||
),
|
),
|
||||||
)
|
|
||||||
},
|
|
||||||
icon: const Icon(CupertinoIcons.add)),
|
icon: const Icon(CupertinoIcons.add)),
|
||||||
),
|
),
|
||||||
child: CupertinoPageScaffold(
|
child: CupertinoPageScaffold(
|
||||||
@@ -128,7 +143,7 @@ class _MainMenuViewState extends State<MainMenuView> {
|
|||||||
final String gameTitle = gameManager
|
final String gameTitle = gameManager
|
||||||
.gameList[index].gameTitle;
|
.gameList[index].gameTitle;
|
||||||
return await _showDeleteGamePopup(
|
return await _showDeleteGamePopup(
|
||||||
gameTitle);
|
context, gameTitle);
|
||||||
},
|
},
|
||||||
onDismissed: (direction) {
|
onDismissed: (direction) {
|
||||||
gameManager
|
gameManager
|
||||||
@@ -204,40 +219,144 @@ class _MainMenuViewState extends State<MainMenuView> {
|
|||||||
return AppLocalizations.of(context).unlimited;
|
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.
|
/// Shows a confirmation dialog to delete all game sessions.
|
||||||
/// Returns true if the user confirms the deletion, false otherwise.
|
/// Returns true if the user confirms the deletion, false otherwise.
|
||||||
/// [gameTitle] is the title of the game session to be deleted.
|
/// [gameTitle] is the title of the game session to be deleted.
|
||||||
Future<bool> _showDeleteGamePopup(String gameTitle) async {
|
Future<bool> _showDeleteGamePopup(
|
||||||
bool? shouldDelete = await showCupertinoDialog<bool>(
|
BuildContext context, String gameTitle) async {
|
||||||
|
return await showCupertinoDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (BuildContext context) {
|
||||||
return CupertinoAlertDialog(
|
return CupertinoAlertDialog(
|
||||||
title: Text(AppLocalizations.of(context).delete_game_title),
|
title: Text(
|
||||||
content: Text(
|
AppLocalizations.of(context).delete_game_title,
|
||||||
AppLocalizations.of(context).delete_game_message(gameTitle)),
|
|
||||||
actions: [
|
|
||||||
CupertinoDialogAction(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pop(context, false);
|
|
||||||
},
|
|
||||||
child: Text(AppLocalizations.of(context).cancel),
|
|
||||||
),
|
),
|
||||||
CupertinoDialogAction(
|
content: Text(AppLocalizations.of(context)
|
||||||
onPressed: () {
|
.delete_game_message(gameTitle)),
|
||||||
Navigator.pop(context, true);
|
actions: [
|
||||||
},
|
CupertinoDialogAction(
|
||||||
child: Text(
|
onPressed: () {
|
||||||
AppLocalizations.of(context).delete,
|
Navigator.of(context).pop(false);
|
||||||
style: const TextStyle(
|
},
|
||||||
fontWeight: FontWeight.bold, color: Colors.red),
|
child: Text(AppLocalizations.of(context).cancel),
|
||||||
),
|
),
|
||||||
),
|
CupertinoDialogAction(
|
||||||
],
|
isDestructiveAction: true,
|
||||||
);
|
isDefaultAction: true,
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop(true);
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context).delete,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]);
|
||||||
},
|
},
|
||||||
) ??
|
) ??
|
||||||
false;
|
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
|
@override
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:cabo_counter/l10n/app_localizations.dart';
|
import 'package:cabo_counter/core/custom_theme.dart';
|
||||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
import 'package:cabo_counter/l10n/generated/app_localizations.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
class ModeSelectionMenu extends StatelessWidget {
|
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/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/services/local_storage_service.dart';
|
||||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.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/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/config_service.dart';
|
||||||
import 'package:cabo_counter/services/local_storage_service.dart';
|
import 'package:cabo_counter/services/local_storage_service.dart';
|
||||||
import 'package:cabo_counter/services/version_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/cupertino.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
@@ -53,7 +54,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
CustomFormRow(
|
CustomFormRow(
|
||||||
prefixText: 'Cabo-Strafe',
|
prefixText: 'Cabo-Strafe',
|
||||||
prefixIcon: CupertinoIcons.bolt_fill,
|
prefixIcon: CupertinoIcons.bolt_fill,
|
||||||
suffixWidget: Stepper(
|
suffixWidget: CustomStepper(
|
||||||
key: _stepperKey1,
|
key: _stepperKey1,
|
||||||
initialValue: ConfigService.caboPenalty,
|
initialValue: ConfigService.caboPenalty,
|
||||||
minValue: 0,
|
minValue: 0,
|
||||||
@@ -70,7 +71,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
CustomFormRow(
|
CustomFormRow(
|
||||||
prefixText: 'Punkte-Limit',
|
prefixText: 'Punkte-Limit',
|
||||||
prefixIcon: FontAwesomeIcons.bullseye,
|
prefixIcon: FontAwesomeIcons.bullseye,
|
||||||
suffixWidget: Stepper(
|
suffixWidget: CustomStepper(
|
||||||
key: _stepperKey2,
|
key: _stepperKey2,
|
||||||
initialValue: ConfigService.pointLimit,
|
initialValue: ConfigService.pointLimit,
|
||||||
minValue: 30,
|
minValue: 30,
|
||||||
@@ -93,7 +94,6 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
_stepperKey1 = UniqueKey();
|
_stepperKey1 = UniqueKey();
|
||||||
_stepperKey2 = UniqueKey();
|
_stepperKey2 = UniqueKey();
|
||||||
print('Config reset to default');
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -142,17 +142,25 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
children: [
|
children: [
|
||||||
CustomFormRow(
|
CustomFormRow(
|
||||||
prefixText: AppLocalizations.of(context).create_issue,
|
prefixText: AppLocalizations.of(context).wiki,
|
||||||
prefixIcon: FontAwesomeIcons.github,
|
prefixIcon: CupertinoIcons.book,
|
||||||
onPressed: () => launchUrl(Uri.parse(
|
onPressed: () =>
|
||||||
'https://github.com/flixcoo/Cabo-Counter/issues')),
|
launchUrl(Uri.parse(Constants.GITHUB_WIKI_LINK)),
|
||||||
suffixWidget: const CupertinoListTileChevron(),
|
suffixWidget: const CupertinoListTileChevron(),
|
||||||
),
|
),
|
||||||
CustomFormRow(
|
CustomFormRow(
|
||||||
prefixText: AppLocalizations.of(context).wiki,
|
prefixText:
|
||||||
prefixIcon: CupertinoIcons.book,
|
AppLocalizations.of(context).privacy_policy,
|
||||||
onPressed: () => launchUrl(Uri.parse(
|
prefixIcon: CupertinoIcons.doc_append,
|
||||||
'https://github.com/flixcoo/Cabo-Counter/wiki')),
|
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(),
|
suffixWidget: const CupertinoListTileChevron(),
|
||||||
),
|
),
|
||||||
CustomFormRow(
|
CustomFormRow(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:cabo_counter/l10n/app_localizations.dart';
|
import 'package:cabo_counter/core/custom_theme.dart';
|
||||||
import 'package:cabo_counter/presentation/views/information_view.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/presentation/views/main_menu_view.dart';
|
||||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
class TabView extends StatefulWidget {
|
class TabView extends StatefulWidget {
|
||||||
@@ -39,7 +39,7 @@ class _TabViewState extends State<TabView> {
|
|||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return const MainMenuView();
|
return const MainMenuView();
|
||||||
} else {
|
} else {
|
||||||
return const InformationView();
|
return const AboutView();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:cabo_counter/presentation/widgets/stepper.dart';
|
import 'package:cabo_counter/core/custom_theme.dart';
|
||||||
import 'package:cabo_counter/utility/custom_theme.dart';
|
import 'package:cabo_counter/presentation/widgets/custom_stepper.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
class CustomFormRow extends StatefulWidget {
|
class CustomFormRow extends StatefulWidget {
|
||||||
@@ -43,7 +43,7 @@ class _CustomFormRowState extends State<CustomFormRow> {
|
|||||||
Text(widget.prefixText),
|
Text(widget.prefixText),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
padding: suffixWidget is Stepper
|
padding: suffixWidget is CustomStepper
|
||||||
? const EdgeInsets.fromLTRB(15, 0, 0, 0)
|
? const EdgeInsets.fromLTRB(15, 0, 0, 0)
|
||||||
: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
||||||
child: suffixWidget,
|
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
|
import 'package:flutter/cupertino.dart'; // Für iOS-Style
|
||||||
|
|
||||||
class Stepper extends StatefulWidget {
|
class CustomStepper extends StatefulWidget {
|
||||||
final int minValue;
|
final int minValue;
|
||||||
final int maxValue;
|
final int maxValue;
|
||||||
final int? initialValue;
|
final int? initialValue;
|
||||||
final int step;
|
final int step;
|
||||||
final ValueChanged<int> onChanged;
|
final ValueChanged<int> onChanged;
|
||||||
const Stepper({
|
const CustomStepper({
|
||||||
super.key,
|
super.key,
|
||||||
required this.minValue,
|
required this.minValue,
|
||||||
required this.maxValue,
|
required this.maxValue,
|
||||||
@@ -18,10 +18,10 @@ class Stepper extends StatefulWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
// ignore: library_private_types_in_public_api
|
// 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;
|
late int _value;
|
||||||
|
|
||||||
@override
|
@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';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
|
||||||
class VersionService {
|
class VersionService {
|
||||||
@@ -19,7 +19,7 @@ class VersionService {
|
|||||||
if (_version == '-.-.-') {
|
if (_version == '-.-.-') {
|
||||||
return getVersionNumber();
|
return getVersionNumber();
|
||||||
}
|
}
|
||||||
return '${Globals.appDevPhase} $_version';
|
return '${Constants.appDevPhase} $_version';
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getBuildNumber() {
|
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"
|
description: "Mobile app for the card game Cabo"
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
version: 0.4.0+382
|
version: 0.4.0+467
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.4
|
sdk: ^3.5.4
|
||||||
@@ -27,6 +27,7 @@ dependencies:
|
|||||||
intl: any
|
intl: any
|
||||||
syncfusion_flutter_charts: ^30.1.37
|
syncfusion_flutter_charts: ^30.1.37
|
||||||
uuid: ^4.5.1
|
uuid: ^4.5.1
|
||||||
|
rate_my_app: ^2.3.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Reference in New Issue
Block a user