Added comments
This commit is contained in:
@@ -1,19 +1,41 @@
|
|||||||
import 'package:rate_my_app/rate_my_app.dart';
|
import 'package:rate_my_app/rate_my_app.dart';
|
||||||
|
|
||||||
|
/// A utility class that holds constant values and configuration settings
|
||||||
|
/// used throughout the application, such as external links, email addresses,
|
||||||
|
/// and timing parameters for UI elements.
|
||||||
|
///
|
||||||
|
/// This class also provides an instance of [RateMyApp] for managing
|
||||||
|
/// in-app rating prompts.
|
||||||
class Constants {
|
class Constants {
|
||||||
|
/// Indicates the current development phase of the app
|
||||||
static const String appDevPhase = 'Beta';
|
static const String appDevPhase = 'Beta';
|
||||||
|
|
||||||
|
/// Links to various social media profiles and resources related to the app.
|
||||||
|
/// URL to my Instagram profile
|
||||||
static const String kInstagramLink = 'https://instagram.felixkirchner.de';
|
static const String kInstagramLink = 'https://instagram.felixkirchner.de';
|
||||||
|
|
||||||
|
/// URL to my GitHub profile
|
||||||
static const String kGithubLink = 'https://github.felixkirchner.de';
|
static const String kGithubLink = 'https://github.felixkirchner.de';
|
||||||
|
|
||||||
|
/// URL to the GitHub issues page for reporting bugs or requesting features.
|
||||||
static const String kGithubIssuesLink =
|
static const String kGithubIssuesLink =
|
||||||
'https://cabo-counter-issues.felixkirchner.de';
|
'https://cabo-counter-issues.felixkirchner.de';
|
||||||
|
|
||||||
|
/// URL to the GitHub wiki for additional documentation and guides.
|
||||||
static const String kGithubWikiLink =
|
static const String kGithubWikiLink =
|
||||||
'https://cabo-counter-wiki.felixkirchner.de';
|
'https://cabo-counter-wiki.felixkirchner.de';
|
||||||
|
|
||||||
|
/// Official email address for user inquiries and support.
|
||||||
static const String kEmail = 'cabocounter@felixkirchner.de';
|
static const String kEmail = 'cabocounter@felixkirchner.de';
|
||||||
|
|
||||||
|
/// URL to the app's privacy policy page.
|
||||||
static const String kPrivacyPolicyLink =
|
static const String kPrivacyPolicyLink =
|
||||||
'https://cabo-counter-datenschutz.felixkirchner.de';
|
'https://cabo-counter-datenschutz.felixkirchner.de';
|
||||||
static const String kImprintLink = 'https://impressum.felixkirchner.de';
|
|
||||||
|
|
||||||
|
/// URL to the app's imprint page, containing legal information.
|
||||||
|
static const String kLegalLink = 'https://impressum.felixkirchner.de';
|
||||||
|
|
||||||
|
/// Instance of [RateMyApp] configured to prompt users for app store ratings.
|
||||||
static RateMyApp rateMyApp = RateMyApp(
|
static RateMyApp rateMyApp = RateMyApp(
|
||||||
appStoreIdentifier: '6747105718',
|
appStoreIdentifier: '6747105718',
|
||||||
minDays: 15,
|
minDays: 15,
|
||||||
|
|||||||
@@ -1,13 +1,29 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
class CustomTheme {
|
class CustomTheme {
|
||||||
|
/// Main Theme of the App
|
||||||
|
/// Primary white color mainly used for text
|
||||||
static Color white = CupertinoColors.white;
|
static Color white = CupertinoColors.white;
|
||||||
|
|
||||||
|
/// Red color, typically used for destructive actions or error states
|
||||||
static Color red = CupertinoColors.destructiveRed;
|
static Color red = CupertinoColors.destructiveRed;
|
||||||
|
|
||||||
|
/// Primary color of the app, used for buttons, highlights, and interactive elements
|
||||||
static Color primaryColor = CupertinoColors.systemGreen;
|
static Color primaryColor = CupertinoColors.systemGreen;
|
||||||
|
|
||||||
|
/// Background color for the main app scaffold and views
|
||||||
static Color backgroundColor = const Color(0xFF101010);
|
static Color backgroundColor = const Color(0xFF101010);
|
||||||
|
|
||||||
|
/// Background color for main UI elements like cards or containers.
|
||||||
static Color mainElementBackgroundColor = CupertinoColors.darkBackgroundGray;
|
static Color mainElementBackgroundColor = CupertinoColors.darkBackgroundGray;
|
||||||
|
|
||||||
|
/// Background color for player tiles in lists.
|
||||||
static Color playerTileColor = CupertinoColors.secondaryLabel;
|
static Color playerTileColor = CupertinoColors.secondaryLabel;
|
||||||
|
|
||||||
|
/// Background color for buttons and interactive controls.
|
||||||
static Color buttonBackgroundColor = const Color(0xFF202020);
|
static Color buttonBackgroundColor = const Color(0xFF202020);
|
||||||
|
|
||||||
|
/// Color used to highlight the kamikaze button and players
|
||||||
static Color kamikazeColor = CupertinoColors.systemYellow;
|
static Color kamikazeColor = CupertinoColors.systemYellow;
|
||||||
|
|
||||||
// Line Colors for GraphView
|
// Line Colors for GraphView
|
||||||
@@ -18,25 +34,33 @@ class CustomTheme {
|
|||||||
static final Color graphColor5 = primaryColor;
|
static final Color graphColor5 = primaryColor;
|
||||||
|
|
||||||
// Colors for PointsView
|
// Colors for PointsView
|
||||||
|
/// Color used to indicate a loss of points in the UI.
|
||||||
static Color pointLossColor = primaryColor;
|
static Color pointLossColor = primaryColor;
|
||||||
|
|
||||||
|
/// Color used to indicate a gain of points in the UI.
|
||||||
static const Color pointGainColor = Color(0xFFF44336);
|
static const Color pointGainColor = Color(0xFFF44336);
|
||||||
|
|
||||||
|
// Text Styles
|
||||||
|
/// Text style for mode titles, typically used in headers or section titles.
|
||||||
static TextStyle modeTitle = TextStyle(
|
static TextStyle modeTitle = TextStyle(
|
||||||
color: primaryColor,
|
color: primaryColor,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Default text style for mode descriptions.
|
||||||
static const TextStyle modeDescription = TextStyle(
|
static const TextStyle modeDescription = TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Text style for titles of sections of [CupertinoListTile].
|
||||||
static TextStyle rowTitle = TextStyle(
|
static TextStyle rowTitle = TextStyle(
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: primaryColor,
|
color: primaryColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Text style for round titles, used for prominent display of the round title
|
||||||
static TextStyle roundTitle = TextStyle(
|
static TextStyle roundTitle = TextStyle(
|
||||||
fontSize: 60,
|
fontSize: 60,
|
||||||
color: white,
|
color: white,
|
||||||
|
|||||||
@@ -77,17 +77,6 @@ class GameSession extends ChangeNotifier {
|
|||||||
roundList =
|
roundList =
|
||||||
(json['roundList'] as List).map((e) => Round.fromJson(e)).toList();
|
(json['roundList'] as List).map((e) => Round.fromJson(e)).toList();
|
||||||
|
|
||||||
/// Returns the length of the longest player name.
|
|
||||||
int getMaxLengthOfPlayerNames() {
|
|
||||||
int length = 0;
|
|
||||||
for (String player in players) {
|
|
||||||
if (player.length >= length) {
|
|
||||||
length = player.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assigns 50 points to all players except the kamikaze player.
|
/// Assigns 50 points to all players except the kamikaze player.
|
||||||
/// [kamikazePlayerIndex] is the index of the kamikaze player.
|
/// [kamikazePlayerIndex] is the index of the kamikaze player.
|
||||||
void applyKamikaze(int roundNum, int kamikazePlayerIndex) {
|
void applyKamikaze(int roundNum, int kamikazePlayerIndex) {
|
||||||
@@ -242,8 +231,8 @@ class GameSession extends ChangeNotifier {
|
|||||||
/// It then checks if any player has exceeded 100 points. If so, it sets
|
/// It then checks if any player has exceeded 100 points. If so, it sets
|
||||||
/// isGameFinished to true and calls the _setWinner() method to determine
|
/// isGameFinished to true and calls the _setWinner() method to determine
|
||||||
/// the winner.
|
/// the winner.
|
||||||
/// It returns a list of players indices who reached 100 points in the current
|
/// It returns a list of players indices who reached 100 points (bonus player)
|
||||||
/// round for the [RoundView] to show a popup
|
/// in the current round for the [RoundView] to show a popup
|
||||||
List<int> updatePoints() {
|
List<int> updatePoints() {
|
||||||
List<int> bonusPlayers = [];
|
List<int> bonusPlayers = [];
|
||||||
_sumPoints();
|
_sumPoints();
|
||||||
|
|||||||
@@ -9,8 +9,11 @@ import 'package:flutter/services.dart';
|
|||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
// Ensure the app runs in portrait mode only
|
||||||
await SystemChrome.setPreferredOrientations(
|
await SystemChrome.setPreferredOrientations(
|
||||||
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
||||||
|
|
||||||
|
// Initialize services
|
||||||
await ConfigService.initConfig();
|
await ConfigService.initConfig();
|
||||||
await VersionService.init();
|
await VersionService.init();
|
||||||
runApp(const App());
|
runApp(const App());
|
||||||
@@ -38,6 +41,9 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
||||||
|
/// Every time the app goes into the background or is closed,
|
||||||
|
/// save the current game sessions to local storage.
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
if (state == AppLifecycleState.paused ||
|
if (state == AppLifecycleState.paused ||
|
||||||
state == AppLifecycleState.detached) {
|
state == AppLifecycleState.detached) {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class AboutView extends StatelessWidget {
|
|||||||
sizeStyle: CupertinoButtonSize.medium,
|
sizeStyle: CupertinoButtonSize.medium,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
child: Text(AppLocalizations.of(context).imprint),
|
child: Text(AppLocalizations.of(context).imprint),
|
||||||
onPressed: () => launchUrl(Uri.parse(Constants.kImprintLink)),
|
onPressed: () => launchUrl(Uri.parse(Constants.kLegalLink)),
|
||||||
),
|
),
|
||||||
CupertinoButton(
|
CupertinoButton(
|
||||||
sizeStyle: CupertinoButtonSize.medium,
|
sizeStyle: CupertinoButtonSize.medium,
|
||||||
|
|||||||
@@ -3,8 +3,13 @@ import 'package:cabo_counter/l10n/generated/app_localizations.dart'
|
|||||||
show AppLocalizations;
|
show AppLocalizations;
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
/// A view that displays the details of a specific open source software license.
|
/// Displays the details of a specific open source software license in a Cupertino-style view.
|
||||||
/// It shows the title and the full license text in a scrollable view.
|
///
|
||||||
|
/// This view presents the license title and its full text in a scrollable layout.
|
||||||
|
///
|
||||||
|
/// Required parameters:
|
||||||
|
/// - [title]: The name of the license.
|
||||||
|
/// - [license]: The full license text to display.
|
||||||
class LicenseDetailView extends StatelessWidget {
|
class LicenseDetailView extends StatelessWidget {
|
||||||
final String title, license;
|
final String title, license;
|
||||||
const LicenseDetailView(
|
const LicenseDetailView(
|
||||||
|
|||||||
@@ -6,8 +6,14 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
|
||||||
/// A view that displays a list of the open source software licenses used in the app.
|
/// Displays a list of open source software licenses used in the app.
|
||||||
/// It allows users to tap on a license to view its details in a separate screen.
|
///
|
||||||
|
/// Users can tap on a license to view its details on a separate screen.
|
||||||
|
/// This view uses a Cupertino design and supports localization.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
/// - [LicenseDetailView] for displaying license details.
|
||||||
|
/// - [ossLicenses] for the list of licenses.
|
||||||
class LicenseView extends StatelessWidget {
|
class LicenseView extends StatelessWidget {
|
||||||
const LicenseView({super.key});
|
const LicenseView({super.key});
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,13 @@ import 'package:confetti/confetti.dart';
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// Displays the active game view, showing game details, player rankings, rounds, and statistics.
|
||||||
|
///
|
||||||
|
/// This view allows users to interact with an ongoing game session, including viewing player scores,
|
||||||
|
/// navigating through rounds, ending or deleting the game, exporting game data, and starting a new game
|
||||||
|
/// with the same settings. It also provides visual feedback such as confetti animation when the game ends.
|
||||||
|
///
|
||||||
|
/// The widget listens to changes in the provided [GameSession] and updates the UI accordingly.
|
||||||
class ActiveGameView extends StatefulWidget {
|
class ActiveGameView extends StatefulWidget {
|
||||||
final GameSession gameSession;
|
final GameSession gameSession;
|
||||||
const ActiveGameView({super.key, required this.gameSession});
|
const ActiveGameView({super.key, required this.gameSession});
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ import 'package:cabo_counter/l10n/generated/app_localizations.dart';
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:syncfusion_flutter_charts/charts.dart';
|
import 'package:syncfusion_flutter_charts/charts.dart';
|
||||||
|
|
||||||
|
/// A widget that displays the cumulative scoring history of a game session as a line graph.
|
||||||
|
///
|
||||||
|
/// The [GraphView] visualizes the progression of each player's score over multiple rounds
|
||||||
|
/// using a line chart. It supports dynamic coloring for each player, axis formatting,
|
||||||
|
/// and handles cases where insufficient data is available to render the graph.
|
||||||
class GraphView extends StatefulWidget {
|
class GraphView extends StatefulWidget {
|
||||||
final GameSession gameSession;
|
final GameSession gameSession;
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ enum GameMode {
|
|||||||
unlimited,
|
unlimited,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A stateless widget that displays a menu for selecting the game mode.
|
||||||
|
///
|
||||||
|
/// The [ModeSelectionMenu] allows the user to choose between different game modes:
|
||||||
|
/// - Point limit mode with a specified [pointLimit]
|
||||||
|
/// - Unlimited mode
|
||||||
|
/// - Optionally, no default mode if [showDeselection] is true
|
||||||
class ModeSelectionMenu extends StatelessWidget {
|
class ModeSelectionMenu extends StatelessWidget {
|
||||||
final int pointLimit;
|
final int pointLimit;
|
||||||
final bool showDeselection;
|
final bool showDeselection;
|
||||||
|
|||||||
@@ -4,6 +4,13 @@ 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';
|
||||||
|
|
||||||
|
/// Displays an overview of points for each player and round in the current game session.
|
||||||
|
///
|
||||||
|
/// The [PointsView] widget shows a table with all rounds and player scores,
|
||||||
|
/// including score updates and highlights for players who said "Cabo".
|
||||||
|
/// It uses a Cupertino-style layout and adapts to the number of players.
|
||||||
|
///
|
||||||
|
/// Requires a [GameSession] to provide player and round data.
|
||||||
class PointsView extends StatefulWidget {
|
class PointsView extends StatefulWidget {
|
||||||
final GameSession gameSession;
|
final GameSession gameSession;
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,19 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
|
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
|
||||||
|
/// A view for displaying and managing a single round
|
||||||
|
///
|
||||||
|
/// This widget allows users to input and review scores for each player in a round,
|
||||||
|
/// select the player who called CABO, and handle special cases such as Kamikaze rounds.
|
||||||
|
/// It manages the round state, validates input, and coordinates navigation between rounds.
|
||||||
|
///
|
||||||
|
/// Features:
|
||||||
|
/// - Rotates player order based on the previous round's winner.
|
||||||
|
/// - Supports Kamikaze rounds with dedicated UI and logic.
|
||||||
|
/// - Handles score input, validation, and updates to the game session.
|
||||||
|
/// - Displays bonus point popups when applicable.
|
||||||
|
///
|
||||||
|
/// Requires a [GameSession] and the current [roundNumber].
|
||||||
class RoundView extends StatefulWidget {
|
class RoundView extends StatefulWidget {
|
||||||
final GameSession gameSession;
|
final GameSession gameSession;
|
||||||
final int roundNumber;
|
final int roundNumber;
|
||||||
|
|||||||
@@ -20,6 +20,12 @@ enum CreateStatus {
|
|||||||
noPlayerName,
|
noPlayerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A view for creating a new game session in the Cabo Counter app.
|
||||||
|
///
|
||||||
|
/// The [CreateGameView] allows users to input a game title, select a game mode,
|
||||||
|
/// add and reorder player names, and validate all required fields before
|
||||||
|
/// starting a new game. It provides feedback dialogs for missing or invalid
|
||||||
|
/// input and navigates to the active game view upon successful creation.
|
||||||
class CreateGameView extends StatefulWidget {
|
class CreateGameView extends StatefulWidget {
|
||||||
final GameMode gameMode;
|
final GameMode gameMode;
|
||||||
final String? gameTitle;
|
final String? gameTitle;
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ enum PreRatingDialogDecision { yes, no, cancel }
|
|||||||
|
|
||||||
enum BadRatingDialogDecision { email, cancel }
|
enum BadRatingDialogDecision { email, cancel }
|
||||||
|
|
||||||
|
/// Home screen of the app that displays a list of game sessions.
|
||||||
|
///
|
||||||
|
/// The [MainMenuView] is the main entry point for the app's home screen.
|
||||||
|
/// It displays a list of existing game sessions, allows users to create new games,
|
||||||
|
/// access settings, and handles user feedback dialogs for app rating and support.
|
||||||
class MainMenuView extends StatefulWidget {
|
class MainMenuView extends StatefulWidget {
|
||||||
const MainMenuView({super.key});
|
const MainMenuView({super.key});
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ 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';
|
||||||
|
|
||||||
|
/// Settings and information page for the app.
|
||||||
|
///
|
||||||
|
/// [SettingsView] is a settings page for the app, allowing users to configure game options,
|
||||||
|
/// manage game data (import, export, delete), and view app information.
|
||||||
class SettingsView extends StatefulWidget {
|
class SettingsView extends StatefulWidget {
|
||||||
const SettingsView({super.key});
|
const SettingsView({super.key});
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,15 @@ import 'package:cabo_counter/presentation/views/about/about_view.dart';
|
|||||||
import 'package:cabo_counter/presentation/views/home/main_menu_view.dart';
|
import 'package:cabo_counter/presentation/views/home/main_menu_view.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
/// A view that provides a tabbed interface for navigating between the main menu and the about section.
|
/// TabBar for navigating between the main menu and about section.
|
||||||
|
///
|
||||||
|
/// [TabView] is a [StatefulWidget] that provides a tabbed interface for navigating
|
||||||
|
/// between the main menu and the about section of the app. It uses a
|
||||||
|
/// [CupertinoTabScaffold] with two tabs:
|
||||||
|
/// - Home (MainMenuView)
|
||||||
|
/// - About (AboutView)
|
||||||
|
///
|
||||||
|
/// The tab labels are provided via localization.
|
||||||
class TabView extends StatefulWidget {
|
class TabView extends StatefulWidget {
|
||||||
const TabView({super.key});
|
const TabView({super.key});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import 'package:cabo_counter/core/custom_theme.dart';
|
import 'package:cabo_counter/core/custom_theme.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
/// A customizable button widget using Cupertino style.
|
||||||
|
///
|
||||||
|
/// Displays a button with a child widget and optional callback.
|
||||||
|
/// The button uses a medium size, rounded corners, and a custom background color.
|
||||||
class CustomButton extends StatelessWidget {
|
class CustomButton extends StatelessWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback? onPressed;
|
||||||
|
|||||||
@@ -2,6 +2,11 @@ import 'package:cabo_counter/core/custom_theme.dart';
|
|||||||
import 'package:cabo_counter/presentation/widgets/custom_stepper.dart';
|
import 'package:cabo_counter/presentation/widgets/custom_stepper.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
/// A customizable form row widget with a prefix icon, text, and optional suffix widget.
|
||||||
|
///
|
||||||
|
/// Displays a row with an icon and text on the left side.
|
||||||
|
/// Optionally, a suffix widget (e.g. a stepper) can be shown on the right side.
|
||||||
|
/// The row is styled as a [CupertinoButton] and can react to taps.
|
||||||
class CustomFormRow extends StatefulWidget {
|
class CustomFormRow extends StatefulWidget {
|
||||||
final String prefixText;
|
final String prefixText;
|
||||||
final IconData prefixIcon;
|
final IconData prefixIcon;
|
||||||
|
|||||||
@@ -1,6 +1,17 @@
|
|||||||
import 'package:cabo_counter/core/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
|
||||||
|
|
||||||
|
/// A custom stepper widget for incrementing and decrementing a value.
|
||||||
|
///
|
||||||
|
/// The [CustomStepper] widget allows increasing and decreasing a value
|
||||||
|
/// within a defined range ([minValue] to [maxValue]) in fixed steps.
|
||||||
|
///
|
||||||
|
/// Properties:
|
||||||
|
/// - [minValue]: The minimum value.
|
||||||
|
/// - [maxValue]: The maximum value.
|
||||||
|
/// - [initialValue]: The initial value (optional, defaults to [minValue]).
|
||||||
|
/// - [step]: The step size.
|
||||||
|
/// - [onChanged]: Callback triggered when the value changes.
|
||||||
class CustomStepper extends StatefulWidget {
|
class CustomStepper extends StatefulWidget {
|
||||||
final int minValue;
|
final int minValue;
|
||||||
final int maxValue;
|
final int maxValue;
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import 'package:cabo_counter/presentation/views/home/active_game/mode_selection_view.dart';
|
import 'package:cabo_counter/presentation/views/home/active_game/mode_selection_view.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
/// This class handles the configuration settings for the app.
|
/// A service class for managing and persisting app configuration settings using `SharedPreferences`.
|
||||||
/// It uses SharedPreferences to store and retrieve the personal configuration of the app.
|
///
|
||||||
/// Currently it provides methods to initialize, get, and set the point limit and cabo penalty.
|
/// Provides methods to initialize, retrieve, update, and reset configuration values such as point limit,
|
||||||
|
/// cabo penalty, and game mode. Ensures that user preferences are stored locally and persist across app restarts.
|
||||||
class ConfigService {
|
class ConfigService {
|
||||||
|
// Keys for the stored values
|
||||||
static const String _keyPointLimit = 'pointLimit';
|
static const String _keyPointLimit = 'pointLimit';
|
||||||
static const String _keyCaboPenalty = 'caboPenalty';
|
static const String _keyCaboPenalty = 'caboPenalty';
|
||||||
static const String _keyGameMode = 'gameMode';
|
static const String _keyGameMode = 'gameMode';
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ class LocalStorageService {
|
|||||||
try {
|
try {
|
||||||
final file = await _getFilePath();
|
final file = await _getFilePath();
|
||||||
|
|
||||||
|
// Check if the file exists
|
||||||
if (!await file.exists()) {
|
if (!await file.exists()) {
|
||||||
print(
|
print(
|
||||||
'[local_storage_service.dart] Es existiert noch keine Datei mit Spieldaten');
|
'[local_storage_service.dart] Es existiert noch keine Datei mit Spieldaten');
|
||||||
@@ -65,11 +66,13 @@ class LocalStorageService {
|
|||||||
'[local_storage_service.dart] Es existiert bereits eine Datei mit Spieldaten');
|
'[local_storage_service.dart] Es existiert bereits eine Datei mit Spieldaten');
|
||||||
final jsonString = await file.readAsString();
|
final jsonString = await file.readAsString();
|
||||||
|
|
||||||
|
// Check if the file is empty
|
||||||
if (jsonString.isEmpty) {
|
if (jsonString.isEmpty) {
|
||||||
print('[local_storage_service.dart] Die gefundene Datei ist leer');
|
print('[local_storage_service.dart] Die gefundene Datei ist leer');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate the JSON schema
|
||||||
if (!await _validateJsonSchema(jsonString, true)) {
|
if (!await _validateJsonSchema(jsonString, true)) {
|
||||||
print(
|
print(
|
||||||
'[local_storage_service.dart] Die Datei konnte nicht validiert werden');
|
'[local_storage_service.dart] Die Datei konnte nicht validiert werden');
|
||||||
@@ -148,7 +151,6 @@ class LocalStorageService {
|
|||||||
/// Opens the file picker to import a JSON file and loads the game data from it.
|
/// Opens the file picker to import a JSON file and loads the game data from it.
|
||||||
static Future<ImportStatus> importJsonFile() async {
|
static Future<ImportStatus> importJsonFile() async {
|
||||||
final path = await FilePicker.platform.pickFiles(
|
final path = await FilePicker.platform.pickFiles(
|
||||||
dialogTitle: 'Wähle eine Datei mit Spieldaten aus',
|
|
||||||
type: FileType.custom,
|
type: FileType.custom,
|
||||||
allowedExtensions: ['json'],
|
allowedExtensions: ['json'],
|
||||||
);
|
);
|
||||||
@@ -162,9 +164,8 @@ class LocalStorageService {
|
|||||||
try {
|
try {
|
||||||
final jsonString = await _readFileContent(path.files.single);
|
final jsonString = await _readFileContent(path.files.single);
|
||||||
|
|
||||||
|
// Checks if the JSON String is in the gameList format
|
||||||
if (await _validateJsonSchema(jsonString, true)) {
|
if (await _validateJsonSchema(jsonString, true)) {
|
||||||
// Checks if the JSON String is in the gameList format
|
|
||||||
|
|
||||||
final jsonData = json.decode(jsonString) as List<dynamic>;
|
final jsonData = json.decode(jsonString) as List<dynamic>;
|
||||||
List<GameSession> importedList = jsonData
|
List<GameSession> importedList = jsonData
|
||||||
.map((jsonItem) =>
|
.map((jsonItem) =>
|
||||||
|
|||||||
@@ -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.5.8+670
|
version: 0.5.8+671
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.4
|
sdk: ^3.5.4
|
||||||
|
|||||||
@@ -62,10 +62,6 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
group('Helper Functions', () {
|
group('Helper Functions', () {
|
||||||
test('getMaxLengthOfPlayerNames', () {
|
|
||||||
expect(session.getMaxLengthOfPlayerNames(), equals(7)); // Charlie (7)
|
|
||||||
});
|
|
||||||
|
|
||||||
test('increaseRound', () {
|
test('increaseRound', () {
|
||||||
expect(session.roundNumber, 1);
|
expect(session.roundNumber, 1);
|
||||||
session.increaseRound();
|
session.increaseRound();
|
||||||
|
|||||||
Reference in New Issue
Block a user