diff --git a/.gitea/ISSUE_TEMPLATE/BUG_REPORT.md b/.gitea/ISSUE_TEMPLATE/BUG_REPORT.md deleted file mode 100644 index 10f8648..0000000 --- a/.gitea/ISSUE_TEMPLATE/BUG_REPORT.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: Bug report -about: Erstelle eine Meldung für etwas, das nicht Funktioniert, wie es soll. -title: '' -labels: 'Task/Bug' -assignees: '' - ---- - -# Bug Report - -## Beschreibung -[Eine klare und prägnante Beschreibung des Bugs] - -## Schritte zur Reproduktion -1. Schritt 1 -2. Schritt 2 -3. ... - -## Erwartetes Verhalten -[Was hätte passieren sollen] - -## Tatsächliches Verhalten -[Was tatsächlich passiert ist] - -## Screenshots/Protokolle -[Falls zutreffend, füge Screenshots, Error Logs oder Stack Traces hinzu] - -## Umgebung -- Plattform: Android, iOS, Web -- OS: [z. B. iOS 18.5, Android 14] -- Flutter Version: [z.B. 3.35.6] - -## Verwandte Issues -[Verweisen Sie auf ähnliche Issues oder PRs] \ No newline at end of file diff --git a/.gitea/ISSUE_TEMPLATE/ENHANCEMENT.md b/.gitea/ISSUE_TEMPLATE/ENHANCEMENT.md deleted file mode 100644 index 49442d1..0000000 --- a/.gitea/ISSUE_TEMPLATE/ENHANCEMENT.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: Enhancement -about: Enhancements for current features -title: '' -labels: 'Task\Enhancement' -assignees: '' - ---- - -# Enhancement - -## Aktuelles Verhalten -[Beschreibe die bestehende Funktionalität] - -## Einschränkungen/Probleme -[Was sind die aktuellen Mängel?] - -## Vorgeschlagene Verbesserung -[Wie kann das Problem bzw. die Einschränkung verbessert werden?] - -## Zugehörige Issues -[Links zu verwandten oder blockierenden Issues] \ No newline at end of file diff --git a/.gitea/ISSUE_TEMPLATE/FEATURE.md b/.gitea/ISSUE_TEMPLATE/FEATURE.md deleted file mode 100644 index 01e7a5f..0000000 --- a/.gitea/ISSUE_TEMPLATE/FEATURE.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Feature -about: Neues Feature für die App -title: '' -labels: 'Task\Feature' -assignees: '' - ---- - -# Feature - -## Beschreibung -[Ausführliche Erläuterung der vorgeschlagenen Funktion] - -## Vorgeschlagene Lösung -[Beschreibe, wie die Feature funktionieren soll] - -## Zugehörige Issues -[Links zu verwandten oder blockierenden Issues] \ No newline at end of file diff --git a/.gitea/PULL_REQUEST_TEMPLATE.md b/.gitea/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 7ae0f8a..0000000 --- a/.gitea/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,16 +0,0 @@ -# [PR Titel] - -**Zugehörige Issue(s):** -Closes `` - -## Beschreibung -*Eine klare und prägnante Übersicht über die vorgenommenen Änderungen. Erläutere nicht nur das was gemacht wurde, sondern auch warum.* - -## Änderungen -- [ ] Neue Funktion X hinzugefügt -- [ ] Bug in Komponente Y behoben -- [ ] Modul Z für bessere Leistung refactored -- [ ] Dependencies aktualisiert - -## Zusätzliche Anmerkungen -*Gibt es zusätzlichen Kontext, Einschränkungen oder Informationen, die Reviewer wissen sollten?* diff --git a/.gitea/issue_template/bug.yaml b/.gitea/issue_template/bug.yaml new file mode 100644 index 0000000..2709da1 --- /dev/null +++ b/.gitea/issue_template/bug.yaml @@ -0,0 +1,53 @@ +name: Bug Report +about: Erstelle eine Bug Report +labels: 'Task/Bug' +title: '' +body: + - type: textarea + id: description + attributes: + label: Beschreibung + description: Beschreibe klar und pregnant das Fehlerverhalten + placeholder: | + - Was genau ist das unerwünschte Verhalten? + - Welche Auswirkungen hat der Fehler? + validations: + required: true + + - type: textarea + id: reproduce + attributes: + label: Schritte zur Reproduktion + description: Beschreibe, wie der Fehler reproduziert werden kann + placeholder: | + - 1. Schritt 1 + - 2. Schritt 2 + - 3. ... + + - type: dropdown + id: enviroment + attributes: + label: Umgebung + description: Gebe an, auf welchen Platformen dieser Fehler auftritt + list: false + multiple: true + options: ['Android', 'iOS'] + + - type: textarea + id: solution + attributes: + label: Lösungsidee + description: Beschreibe, wie das Problem bzw. gelöst werden kann + placeholder: | + - Button X ändern, sodass ... + - Funktion X so erweitern, dass ... + - Design anpassen, sodass ... + + - type: textarea + attributes: + label: Verwandte Issues + description: Verweise auf ähnliche Issues oder PRs + placeholder: | + - Knüpft an Issue #35 an + - Ersetzt Issue #12 + - Brauch Implementierung von #43 \ No newline at end of file diff --git a/.gitea/issue_template/enhancement.yaml b/.gitea/issue_template/enhancement.yaml new file mode 100644 index 0000000..34c3551 --- /dev/null +++ b/.gitea/issue_template/enhancement.yaml @@ -0,0 +1,36 @@ +name: Enhancement +about: Erstelle ein Enhancement-Ticket +labels: 'Task/Enhancement' +title: '' +body: + - type: textarea + id: description + attributes: + label: Aktuelles Verhalten + description: Beschreibe, wie die Funktionalität aktuell gestaltet ist + placeholder: | + - Aktuell macht Button X folgendes ... + - Das Problem ist, dass ... + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Vorgeschlagene Verbesserung + description: Beschreibe, wie das Problem bzw. die Einschränkung verbessert werden kann + placeholder: | + - Button X ändern, sodass ... + - Funktion X so erweitern, dass ... + - Design anpassen, sodass ... + validations: + required: true + + - type: textarea + attributes: + label: Zugehörige Issues + description: Links zu verwandten oder blockierenden Issues + placeholder: | + - Knüpft an Issue #35 an + - Ersetzt Issue #12 + - Brauch Implementierung von #43 \ No newline at end of file diff --git a/.gitea/issue_template/feature.yaml b/.gitea/issue_template/feature.yaml new file mode 100644 index 0000000..ae3b592 --- /dev/null +++ b/.gitea/issue_template/feature.yaml @@ -0,0 +1,36 @@ +name: Feature +about: Erstelle ein Feature-Ticket +labels: 'Task/Feature' +title: '' +body: + - type: textarea + id: description + attributes: + label: Beschreibung + description: Ausführliche Erläuterung der vorgeschlagenen Funktion + placeholder: | + - Welchen Zweck erfüllt das Feature? + - Welches Problem löst das Feature? + - Wer profitiert davon? + - Warum ist es wichtig? + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Vorgeschlagene Lösung + description: Beschreibe, wie das Feature funktionieren soll + placeholder: | + - Neues Widget, das folgendermaßen aussieht ... + - Neue Ansicht, die folgende Inhalte hat + - Neue Funktionsweise von Komponente XY + + - type: textarea + attributes: + label: Zugehörige Issues + description: Links zu verwandten oder blockierenden Issues + placeholder: | + - Knüpft an Issue #35 an + - Ersetzt Issue #12 + - Brauch Implementierung von #43 \ No newline at end of file diff --git a/.gitea/pull_request_template.yaml b/.gitea/pull_request_template.yaml new file mode 100644 index 0000000..f5f9642 --- /dev/null +++ b/.gitea/pull_request_template.yaml @@ -0,0 +1,47 @@ +name: Pull Request +about: Vorlage für Pull Requests +title: "WIP: [Name des Issues]" + +body: + - type: input + id: related_issue + attributes: + label: Zugehörige Issue(s) + description: Issues welche mit diesem Pull Request geschlossen werden sollen + placeholder: "Closes #123" + validations: + required: true + + - type: textarea + id: description + attributes: + label: Beschreibung + description: | + Eine klare und prägnante Zusammenfassung aller vorgenommenen Änderungen. + placeholder: | + Was wurde geändert? + validations: + required: true + + - type: textarea + id: changes + attributes: + label: Änderungen + description: Liste alle Änderungen detailiert auf, die in diesem Pull Request vorgenommen wurden. + placeholder: | + - Neue Funktion X hinzugefügt + - Bug in Komponente X behoben + - Modul X für bessere Leistung refactored + - Dependencies aktualisiert + + - type: textarea + id: additional_notes + attributes: + label: Zusätzliche Anmerkungen + description: | + Gibt es zusätzlichen Kontext, Einschränkungen oder Informationen, + die Reviewer wissen sollten? + placeholder: | + - Bekannte Einschränkungen + - Offene TODOs + - Hinweise für Reviewer diff --git a/.gitignore b/.gitignore index e000548..6faa982 100644 --- a/.gitignore +++ b/.gitignore @@ -150,25 +150,9 @@ app.*.symbols .gclient_previous_custom_vars .gclient_previous_sync_commits -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.build/ -.buildlog/ -.history -.svn/ .swiftpm/ migrate_working_dir/ -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line @@ -176,17 +160,8 @@ migrate_working_dir/ #.vscode/ # Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.pub-cache/ -.pub/ /build/ -# Symbolication related -app.*.symbols # Obfuscation related app.*.map.json @@ -195,3 +170,6 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release +/devtools_options.yaml + +untranslated_messages.json \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 4cded1b..3c48c4a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ + + + + + + + + + + diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index ab39a10..43394ed 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -18,7 +18,7 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.7.3" apply false + id("com.android.application") version "8.9.1" apply false id("org.jetbrains.kotlin.android") version "2.1.0" apply false } diff --git a/assets/schema.json b/assets/schema.json index c80915c..b3a8a2c 100644 --- a/assets/schema.json +++ b/assets/schema.json @@ -2,178 +2,103 @@ "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { - "games": { + "players": { "type": "array", - "items": [ - { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "createdAt": { - "type": "string" - }, - "name": { - "type": "string" - }, - "players": { - "type": [ - "array", - "null" - ], - "properties": { - "id": { - "type": "string" - }, - "createdAt": { - "type": "string" - }, - "name": { - "type": "string" - } - }, - "required": [ - "id", - "createdAt", - "name" - ] - } + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" }, - "group": { - "type": [ - "object", - "null" - ], - "properties": { - "id": { - "type": "string" - }, - "createdAt": { - "type": "string" - }, - "name": { - "type": "string" - }, - "members": { - "type": "array", - "items": [ - { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "createdAt": { - "type": "string" - }, - "name": { - "type": "string" - } - }, - "required": [ - "id", - "createdAt", - "name" - ] - } - ] - } - }, - "required": [ - "id", - "createdAt", - "name", - "members" - ] + "createdAt": { + "type": "string" }, - "winner": { - "type": ["object","null"] - }, - "required": [ - "id", - "createdAt", - "name" - ] - } - ] + "name": { + "type": "string" + } + }, + "required": [ + "id", + "createdAt", + "name" + ] + } }, "groups": { "type": "array", - "items": [ - { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "createdAt": { - "type": "string" - }, - "name": { - "type": "string" - }, - "members": { - "type": "array", - "items": [ - { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "createdAt": { - "type": "string" - }, - "name": { - "type": "string" - } - }, - "required": [ - "id", - "createdAt", - "name" - ] - } - ] - } + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" }, - "required": [ - "id", - "createdAt", - "name", - "members" - ] - } - ] + "name": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "memberIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "name", + "createdAt", + "memberIds" + ] + } }, - "players": { + "matches": { "type": "array", - "items": [ - { - "type": [ - "object", - "null" - ], - "properties": { - "id": { - "type": "string" - }, - "createdAt": { - "type": "string" - }, - "name": { + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "groupId": { + "anyOf": [ + {"type": "string"}, + {"type": "null"} + ] + }, + "playerIds": { + "type": "array", + "items": { "type": "string" } }, - "required": [ - "id", - "createdAt", - "name" - ] - } - ] + "winnerId": { + "anyOf": [ + {"type": "string"}, + {"type": "null"} + ] + } + }, + "required": [ + "id", + "name", + "createdAt", + "groupId", + "playerIds" + ] + } } - } -} - + }, + "required": [ + "players", + "groups", + "matches" + ] +} \ No newline at end of file diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 048157d..8db75d8 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -24,6 +24,11 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + LSApplicationQueriesSchemes + + https + http + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -31,8 +36,6 @@ UISupportedInterfaceOrientations UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad @@ -46,4 +49,4 @@ UIApplicationSupportsIndirectInputEvents - + \ No newline at end of file diff --git a/l10n.yaml b/l10n.yaml new file mode 100644 index 0000000..e72b308 --- /dev/null +++ b/l10n.yaml @@ -0,0 +1,6 @@ +arb-dir: lib/l10n/arb +template-arb-file: app_en.arb +output-localization-file: app_localizations.dart +output-dir: lib/l10n/generated +nullable-getter: false +untranslated-messages-file: lib/l10n/untranslated_messages.json \ No newline at end of file diff --git a/lib/core/adaptive_page_route.dart b/lib/core/adaptive_page_route.dart new file mode 100644 index 0000000..ba68557 --- /dev/null +++ b/lib/core/adaptive_page_route.dart @@ -0,0 +1,19 @@ +import 'dart:io'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +Route adaptivePageRoute({ + required Widget Function(BuildContext) builder, + bool fullscreenDialog = false, +}) { + if (Platform.isIOS) { + return CupertinoPageRoute( + builder: builder, + fullscreenDialog: fullscreenDialog, + ); + } + return MaterialPageRoute( + builder: builder, + fullscreenDialog: fullscreenDialog, + ); +} diff --git a/lib/core/constants.dart b/lib/core/constants.dart new file mode 100644 index 0000000..8d3c8cc --- /dev/null +++ b/lib/core/constants.dart @@ -0,0 +1,6 @@ +class Constants { + Constants._(); // Private constructor to prevent instantiation + + /// Minimum duration of all app skeletons + static Duration minimumSkeletonDuration = const Duration(milliseconds: 250); +} diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index 5930901..a6c6376 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -1,35 +1,59 @@ import 'package:flutter/material.dart'; class CustomTheme { + CustomTheme._(); // Private constructor to prevent instantiation + + // ==================== Colors ==================== static Color primaryColor = const Color(0xFF7505E4); static Color secondaryColor = const Color(0xFFAFA2FF); static Color backgroundColor = const Color(0xFF0B0B0B); static Color boxColor = const Color(0xFF101010); static Color onBoxColor = const Color(0xFF181818); static Color boxBorder = const Color(0xFF272727); + static const Color textColor = Colors.white; + // ==================== Border Radius ==================== + static const double standardBorderRadius = 12.0; + static BorderRadius get standardBorderRadiusAll => + BorderRadius.circular(standardBorderRadius); + + // ==================== Padding & Margins ==================== + static const EdgeInsets standardMargin = EdgeInsets.symmetric( + horizontal: 12, + vertical: 10, + ); + static const EdgeInsets tileMargin = EdgeInsets.symmetric( + horizontal: 12, + vertical: 5, + ); + + // ==================== Decorations ==================== static BoxDecoration standardBoxDecoration = BoxDecoration( color: boxColor, border: Border.all(color: boxBorder), - borderRadius: BorderRadius.circular(12), + borderRadius: standardBorderRadiusAll, ); static BoxDecoration highlightedBoxDecoration = BoxDecoration( color: boxColor, border: Border.all(color: primaryColor), - borderRadius: BorderRadius.circular(12), + borderRadius: standardBorderRadiusAll, boxShadow: [BoxShadow(color: primaryColor.withAlpha(120), blurRadius: 12)], ); + // ==================== App Bar Theme ==================== static AppBarTheme appBarTheme = AppBarTheme( backgroundColor: backgroundColor, - foregroundColor: Colors.white, + foregroundColor: textColor, elevation: 0, + scrolledUnderElevation: 0, + centerTitle: true, titleTextStyle: const TextStyle( - color: Colors.white, + color: textColor, fontSize: 20, fontWeight: FontWeight.bold, + overflow: TextOverflow.ellipsis, ), - iconTheme: const IconThemeData(color: Colors.white), + iconTheme: const IconThemeData(color: textColor), ); } diff --git a/lib/core/enums.dart b/lib/core/enums.dart index af1f4a6..17a01f6 100644 --- a/lib/core/enums.dart +++ b/lib/core/enums.dart @@ -1,4 +1,10 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; + /// Button types used for styling the [CustomWidthButton] +/// - [ButtonType.primary]: Primary button style. +/// - [ButtonType.secondary]: Secondary button style. +/// - [ButtonType.tertiary]: Tertiary button style. enum ButtonType { primary, secondary, tertiary } /// Result types for import operations in the [SettingsView] @@ -23,9 +29,24 @@ enum ImportResult { /// - [ExportResult.unknownException]: An exception occurred during export. enum ExportResult { success, canceled, unknownException } -/// Different rulesets available for games -/// - [Ruleset.singleWinner]: The game is won by a single player -/// - [Ruleset.singleLoser]: The game is lost by a single player +/// Different rulesets available for matches +/// - [Ruleset.singleWinner]: The match is won by a single player +/// - [Ruleset.singleLoser]: The match is lost by a single player /// - [Ruleset.mostPoints]: The player with the most points wins. -/// - [Ruleset.lastPoints]: The player with the fewest points wins. -enum Ruleset { singleWinner, singleLoser, mostPoints, lastPoints } +/// - [Ruleset.leastPoints]: The player with the fewest points wins. +enum Ruleset { singleWinner, singleLoser, mostPoints, leastPoints } + +/// Translates a [Ruleset] enum value to its corresponding localized string. +String translateRulesetToString(Ruleset ruleset, BuildContext context) { + final loc = AppLocalizations.of(context); + switch (ruleset) { + case Ruleset.singleWinner: + return loc.single_winner; + case Ruleset.singleLoser: + return loc.single_loser; + case Ruleset.mostPoints: + return loc.most_points; + case Ruleset.leastPoints: + return loc.least_points; + } +} diff --git a/lib/data/dao/game_dao.dart b/lib/data/dao/game_dao.dart deleted file mode 100644 index c941499..0000000 --- a/lib/data/dao/game_dao.dart +++ /dev/null @@ -1,320 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/db/tables/game_table.dart'; -import 'package:game_tracker/data/dto/game.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/player.dart'; - -part 'game_dao.g.dart'; - -@DriftAccessor(tables: [GameTable]) -class GameDao extends DatabaseAccessor with _$GameDaoMixin { - GameDao(super.db); - - /// Retrieves all games from the database. - Future> getAllGames() async { - final query = select(gameTable); - final result = await query.get(); - - return Future.wait( - result.map((row) async { - final group = await db.groupGameDao.getGroupOfGame(gameId: row.id); - final players = await db.playerGameDao.getPlayersOfGame(gameId: row.id); - final winner = row.winnerId != null - ? await db.playerDao.getPlayerById(playerId: row.winnerId!) - : null; - return Game( - id: row.id, - name: row.name, - group: group, - players: players, - createdAt: row.createdAt, - winner: winner, - ); - }), - ); - } - - /// Retrieves a [Game] by its [gameId]. - Future getGameById({required String gameId}) async { - final query = select(gameTable)..where((g) => g.id.equals(gameId)); - final result = await query.getSingle(); - - List? players; - if (await db.playerGameDao.gameHasPlayers(gameId: gameId)) { - players = await db.playerGameDao.getPlayersOfGame(gameId: gameId); - } - Group? group; - if (await db.groupGameDao.gameHasGroup(gameId: gameId)) { - group = await db.groupGameDao.getGroupOfGame(gameId: gameId); - } - Player? winner; - if (result.winnerId != null) { - winner = await db.playerDao.getPlayerById(playerId: result.winnerId!); - } - - return Game( - id: result.id, - name: result.name, - players: players, - group: group, - winner: winner, - createdAt: result.createdAt, - ); - } - - /// Adds a new [Game] to the database. - /// Also adds associated players and group if they exist. - Future addGame({required Game game}) async { - await db.transaction(() async { - await into(gameTable).insert( - GameTableCompanion.insert( - id: game.id, - name: game.name, - winnerId: Value(game.winner?.id), - createdAt: game.createdAt, - ), - mode: InsertMode.insertOrReplace, - ); - - if (game.players != null) { - await db.playerDao.addPlayersAsList(players: game.players!); - for (final p in game.players ?? []) { - await db.playerGameDao.addPlayerToGame( - gameId: game.id, - playerId: p.id, - ); - } - } - - if (game.group != null) { - await db.groupDao.addGroup(group: game.group!); - await db.groupGameDao.addGroupToGame( - gameId: game.id, - groupId: game.group!.id, - ); - } - }); - } - - /// Adds multiple [Game]s to the database in a batch operation. - /// Also adds associated players and groups if they exist. - /// If the [games] list is empty, the method returns immediately. - Future addGamesAsList({required List games}) async { - if (games.isEmpty) return; - await db.transaction(() async { - // Add all games in batch - await db.batch( - (b) => b.insertAll( - gameTable, - games - .map( - (game) => GameTableCompanion.insert( - id: game.id, - name: game.name, - createdAt: game.createdAt, - winnerId: Value(game.winner?.id), - ), - ) - .toList(), - mode: InsertMode.insertOrReplace, - ), - ); - - // Add all groups of the games in batch - await db.batch( - (b) => b.insertAll( - db.groupTable, - games - .where((game) => game.group != null) - .map( - (game) => GroupTableCompanion.insert( - id: game.group!.id, - name: game.group!.name, - createdAt: game.group!.createdAt, - ), - ) - .toList(), - mode: InsertMode.insertOrReplace, - ), - ); - - // Add all players of the games in batch (unique) - final uniquePlayers = {}; - for (final game in games) { - if (game.players != null) { - for (final p in game.players!) { - uniquePlayers[p.id] = p; - } - } - // Also include members of groups - if (game.group != null) { - for (final m in game.group!.members) { - uniquePlayers[m.id] = m; - } - } - } - - if (uniquePlayers.isNotEmpty) { - await db.batch( - (b) => b.insertAll( - db.playerTable, - uniquePlayers.values - .map( - (p) => PlayerTableCompanion.insert( - id: p.id, - name: p.name, - createdAt: p.createdAt, - ), - ) - .toList(), - mode: InsertMode.insertOrReplace, - ), - ); - } - - // Add all player-game associations in batch - await db.batch((b) { - for (final game in games) { - if (game.players != null) { - for (final p in game.players ?? []) { - b.insert( - db.playerGameTable, - PlayerGameTableCompanion.insert( - gameId: game.id, - playerId: p.id, - ), - mode: InsertMode.insertOrReplace, - ); - } - } - } - }); - - // Add all player-group associations in batch - await db.batch((b) { - for (final game in games) { - if (game.group != null) { - for (final m in game.group!.members) { - b.insert( - db.playerGroupTable, - PlayerGroupTableCompanion.insert( - playerId: m.id, - groupId: game.group!.id, - ), - mode: InsertMode.insertOrReplace, - ); - } - } - } - }); - - // Add all group-game associations in batch - await db.batch((b) { - for (final game in games) { - if (game.group != null) { - b.insert( - db.groupGameTable, - GroupGameTableCompanion.insert( - gameId: game.id, - groupId: game.group!.id, - ), - mode: InsertMode.insertOrReplace, - ); - } - } - }); - }); - } - - /// Deletes the game with the given [gameId] from the database. - /// Returns `true` if more than 0 rows were affected, otherwise `false`. - Future deleteGame({required String gameId}) async { - final query = delete(gameTable)..where((g) => g.id.equals(gameId)); - final rowsAffected = await query.go(); - return rowsAffected > 0; - } - - /// Retrieves the number of games in the database. - Future getGameCount() async { - final count = - await (selectOnly(gameTable)..addColumns([gameTable.id.count()])) - .map((row) => row.read(gameTable.id.count())) - .getSingle(); - return count ?? 0; - } - - /// Checks if a game with the given [gameId] exists in the database. - /// Returns `true` if the game exists, otherwise `false`. - Future gameExists({required String gameId}) async { - final query = select(gameTable)..where((g) => g.id.equals(gameId)); - final result = await query.getSingleOrNull(); - return result != null; - } - - /// Deletes all games from the database. - /// Returns `true` if more than 0 rows were affected, otherwise `false`. - Future deleteAllGames() async { - final query = delete(gameTable); - final rowsAffected = await query.go(); - return rowsAffected > 0; - } - - /// Sets the winner of the game with the given [gameId] to the player with - /// the given [winnerId]. - /// Returns `true` if more than 0 rows were affected, otherwise `false`. - Future setWinner({ - required String gameId, - required String winnerId, - }) async { - final query = update(gameTable)..where((g) => g.id.equals(gameId)); - final rowsAffected = await query.write( - GameTableCompanion(winnerId: Value(winnerId)), - ); - return rowsAffected > 0; - } - - /// Retrieves the winner of the game with the given [gameId]. - /// Returns the [Player] who won the game, or `null` if no winner is set. - Future getWinner({required String gameId}) async { - final query = select(gameTable)..where((g) => g.id.equals(gameId)); - final result = await query.getSingleOrNull(); - if (result == null || result.winnerId == null) { - return null; - } - final winner = await db.playerDao.getPlayerById(playerId: result.winnerId!); - return winner; - } - - /// Removes the winner of the game with the given [gameId]. - /// Returns `true` if more than 0 rows were affected, otherwise `false`. - Future removeWinner({required String gameId}) async { - final query = update(gameTable)..where((g) => g.id.equals(gameId)); - final rowsAffected = await query.write( - const GameTableCompanion(winnerId: Value(null)), - ); - return rowsAffected > 0; - } - - /// Checks if the game with the given [gameId] has a winner set. - /// Returns `true` if a winner is set, otherwise `false`. - Future hasWinner({required String gameId}) async { - final query = select(gameTable) - ..where((g) => g.id.equals(gameId) & g.winnerId.isNotNull()); - final result = await query.getSingleOrNull(); - return result != null; - } - - /// Changes the title of the game with the given [gameId] to [newName]. - /// Returns `true` if more than 0 rows were affected, otherwise `false`. - Future updateGameName({ - required String gameId, - required String newName, - }) async { - final query = update(gameTable)..where((g) => g.id.equals(gameId)); - final rowsAffected = await query.write( - GameTableCompanion(name: Value(newName)), - ); - return rowsAffected > 0; - } -} diff --git a/lib/data/dao/game_dao.g.dart b/lib/data/dao/game_dao.g.dart deleted file mode 100644 index b5a29fe..0000000 --- a/lib/data/dao/game_dao.g.dart +++ /dev/null @@ -1,8 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'game_dao.dart'; - -// ignore_for_file: type=lint -mixin _$GameDaoMixin on DatabaseAccessor { - $GameTableTable get gameTable => attachedDatabase.gameTable; -} diff --git a/lib/data/dao/group_dao.dart b/lib/data/dao/group_dao.dart index 643bc88..98c602a 100644 --- a/lib/data/dao/group_dao.dart +++ b/lib/data/dao/group_dao.dart @@ -1,12 +1,13 @@ import 'package:drift/drift.dart'; import 'package:game_tracker/data/db/database.dart'; import 'package:game_tracker/data/db/tables/group_table.dart'; +import 'package:game_tracker/data/db/tables/player_group_table.dart'; import 'package:game_tracker/data/dto/group.dart'; import 'package:game_tracker/data/dto/player.dart'; part 'group_dao.g.dart'; -@DriftAccessor(tables: [GroupTable]) +@DriftAccessor(tables: [GroupTable, PlayerGroupTable]) class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { GroupDao(super.db); @@ -94,6 +95,8 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { } // Insert unique groups in batch + // Using insertOrIgnore to avoid triggering cascade deletes on + // player_group associations when groups already exist await db.batch( (b) => b.insertAll( groupTable, @@ -106,7 +109,7 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { ), ) .toList(), - mode: InsertMode.insertOrReplace, + mode: InsertMode.insertOrIgnore, ), ); @@ -119,6 +122,8 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { } if (uniquePlayers.isNotEmpty) { + // Using insertOrIgnore to avoid triggering cascade deletes on + // player_group associations when players already exist await db.batch( (b) => b.insertAll( db.playerTable, @@ -131,7 +136,7 @@ class GroupDao extends DatabaseAccessor with _$GroupDaoMixin { ), ) .toList(), - mode: InsertMode.insertOrReplace, + mode: InsertMode.insertOrIgnore, ), ); } diff --git a/lib/data/dao/group_dao.g.dart b/lib/data/dao/group_dao.g.dart index 4a09208..b9534b4 100644 --- a/lib/data/dao/group_dao.g.dart +++ b/lib/data/dao/group_dao.g.dart @@ -5,4 +5,7 @@ part of 'group_dao.dart'; // ignore_for_file: type=lint mixin _$GroupDaoMixin on DatabaseAccessor { $GroupTableTable get groupTable => attachedDatabase.groupTable; + $PlayerTableTable get playerTable => attachedDatabase.playerTable; + $PlayerGroupTableTable get playerGroupTable => + attachedDatabase.playerGroupTable; } diff --git a/lib/data/dao/group_game_dao.dart b/lib/data/dao/group_game_dao.dart deleted file mode 100644 index da95607..0000000 --- a/lib/data/dao/group_game_dao.dart +++ /dev/null @@ -1,98 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/db/tables/group_game_table.dart'; -import 'package:game_tracker/data/dto/group.dart'; - -part 'group_game_dao.g.dart'; - -@DriftAccessor(tables: [GroupGameTable]) -class GroupGameDao extends DatabaseAccessor - with _$GroupGameDaoMixin { - GroupGameDao(super.db); - - /// Associates a group with a game by inserting a record into the - /// [GroupGameTable]. - Future addGroupToGame({ - required String gameId, - required String groupId, - }) async { - if (await gameHasGroup(gameId: gameId)) { - throw Exception('Game already has a group'); - } - await into(groupGameTable).insert( - GroupGameTableCompanion.insert(groupId: groupId, gameId: gameId), - mode: InsertMode.insertOrReplace, - ); - } - - /// Retrieves the [Group] associated with the given [gameId]. - /// Returns `null` if no group is found. - Future getGroupOfGame({required String gameId}) async { - final result = await (select( - groupGameTable, - )..where((g) => g.gameId.equals(gameId))).getSingleOrNull(); - - if (result == null) { - return null; - } - - final group = await db.groupDao.getGroupById(groupId: result.groupId); - return group; - } - - /// Checks if there is a group associated with the given [gameId]. - /// Returns `true` if there is a group, otherwise `false`. - Future gameHasGroup({required String gameId}) async { - final count = - await (selectOnly(groupGameTable) - ..where(groupGameTable.gameId.equals(gameId)) - ..addColumns([groupGameTable.groupId.count()])) - .map((row) => row.read(groupGameTable.groupId.count())) - .getSingle(); - return (count ?? 0) > 0; - } - - /// Checks if a specific group is associated with a specific game. - /// Returns `true` if the group is in the game, otherwise `false`. - Future isGroupInGame({ - required String gameId, - required String groupId, - }) async { - final count = - await (selectOnly(groupGameTable) - ..where( - groupGameTable.gameId.equals(gameId) & - groupGameTable.groupId.equals(groupId), - ) - ..addColumns([groupGameTable.groupId.count()])) - .map((row) => row.read(groupGameTable.groupId.count())) - .getSingle(); - return (count ?? 0) > 0; - } - - /// Removes the association of a group from a game based on [groupId] and - /// [gameId]. - /// Returns `true` if more than 0 rows were affected, otherwise `false`. - Future removeGroupFromGame({ - required String gameId, - required String groupId, - }) async { - final query = delete(groupGameTable) - ..where((g) => g.gameId.equals(gameId) & g.groupId.equals(groupId)); - final rowsAffected = await query.go(); - return rowsAffected > 0; - } - - /// Updates the group associated with a game to [newGroupId] based on - /// [gameId]. - /// Returns `true` if more than 0 rows were affected, otherwise `false`. - Future updateGroupOfGame({ - required String gameId, - required String newGroupId, - }) async { - final updatedRows = - await (update(groupGameTable)..where((g) => g.gameId.equals(gameId))) - .write(GroupGameTableCompanion(groupId: Value(newGroupId))); - return updatedRows > 0; - } -} diff --git a/lib/data/dao/group_game_dao.g.dart b/lib/data/dao/group_game_dao.g.dart deleted file mode 100644 index 735a35f..0000000 --- a/lib/data/dao/group_game_dao.g.dart +++ /dev/null @@ -1,10 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'group_game_dao.dart'; - -// ignore_for_file: type=lint -mixin _$GroupGameDaoMixin on DatabaseAccessor { - $GroupTableTable get groupTable => attachedDatabase.groupTable; - $GameTableTable get gameTable => attachedDatabase.gameTable; - $GroupGameTableTable get groupGameTable => attachedDatabase.groupGameTable; -} diff --git a/lib/data/dao/group_match_dao.dart b/lib/data/dao/group_match_dao.dart new file mode 100644 index 0000000..d428fb5 --- /dev/null +++ b/lib/data/dao/group_match_dao.dart @@ -0,0 +1,98 @@ +import 'package:drift/drift.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/data/db/tables/group_match_table.dart'; +import 'package:game_tracker/data/dto/group.dart'; + +part 'group_match_dao.g.dart'; + +@DriftAccessor(tables: [GroupMatchTable]) +class GroupMatchDao extends DatabaseAccessor + with _$GroupMatchDaoMixin { + GroupMatchDao(super.db); + + /// Associates a group with a match by inserting a record into the + /// [GroupMatchTable]. + Future addGroupToMatch({ + required String matchId, + required String groupId, + }) async { + if (await matchHasGroup(matchId: matchId)) { + throw Exception('Match already has a group'); + } + await into(groupMatchTable).insert( + GroupMatchTableCompanion.insert(groupId: groupId, matchId: matchId), + mode: InsertMode.insertOrIgnore, + ); + } + + /// Retrieves the [Group] associated with the given [matchId]. + /// Returns `null` if no group is found. + Future getGroupOfMatch({required String matchId}) async { + final result = await (select( + groupMatchTable, + )..where((g) => g.matchId.equals(matchId))).getSingleOrNull(); + + if (result == null) { + return null; + } + + final group = await db.groupDao.getGroupById(groupId: result.groupId); + return group; + } + + /// Checks if there is a group associated with the given [matchId]. + /// Returns `true` if there is a group, otherwise `false`. + Future matchHasGroup({required String matchId}) async { + final count = + await (selectOnly(groupMatchTable) + ..where(groupMatchTable.matchId.equals(matchId)) + ..addColumns([groupMatchTable.groupId.count()])) + .map((row) => row.read(groupMatchTable.groupId.count())) + .getSingle(); + return (count ?? 0) > 0; + } + + /// Checks if a specific group is associated with a specific match. + /// Returns `true` if the group is in the match, otherwise `false`. + Future isGroupInMatch({ + required String matchId, + required String groupId, + }) async { + final count = + await (selectOnly(groupMatchTable) + ..where( + groupMatchTable.matchId.equals(matchId) & + groupMatchTable.groupId.equals(groupId), + ) + ..addColumns([groupMatchTable.groupId.count()])) + .map((row) => row.read(groupMatchTable.groupId.count())) + .getSingle(); + return (count ?? 0) > 0; + } + + /// Removes the association of a group from a match based on [groupId] and + /// [matchId]. + /// Returns `true` if more than 0 rows were affected, otherwise `false`. + Future removeGroupFromMatch({ + required String matchId, + required String groupId, + }) async { + final query = delete(groupMatchTable) + ..where((g) => g.matchId.equals(matchId) & g.groupId.equals(groupId)); + final rowsAffected = await query.go(); + return rowsAffected > 0; + } + + /// Updates the group associated with a match to [newGroupId] based on + /// [matchId]. + /// Returns `true` if more than 0 rows were affected, otherwise `false`. + Future updateGroupOfMatch({ + required String matchId, + required String newGroupId, + }) async { + final updatedRows = + await (update(groupMatchTable)..where((g) => g.matchId.equals(matchId))) + .write(GroupMatchTableCompanion(groupId: Value(newGroupId))); + return updatedRows > 0; + } +} diff --git a/lib/data/dao/group_match_dao.g.dart b/lib/data/dao/group_match_dao.g.dart new file mode 100644 index 0000000..5cc0b82 --- /dev/null +++ b/lib/data/dao/group_match_dao.g.dart @@ -0,0 +1,10 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'group_match_dao.dart'; + +// ignore_for_file: type=lint +mixin _$GroupMatchDaoMixin on DatabaseAccessor { + $GroupTableTable get groupTable => attachedDatabase.groupTable; + $MatchTableTable get matchTable => attachedDatabase.matchTable; + $GroupMatchTableTable get groupMatchTable => attachedDatabase.groupMatchTable; +} diff --git a/lib/data/dao/match_dao.dart b/lib/data/dao/match_dao.dart new file mode 100644 index 0000000..160686a --- /dev/null +++ b/lib/data/dao/match_dao.dart @@ -0,0 +1,326 @@ +import 'package:drift/drift.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/data/db/tables/match_table.dart'; +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/match.dart'; +import 'package:game_tracker/data/dto/player.dart'; + +part 'match_dao.g.dart'; + +@DriftAccessor(tables: [MatchTable]) +class MatchDao extends DatabaseAccessor with _$MatchDaoMixin { + MatchDao(super.db); + + /// Retrieves all matches from the database. + Future> getAllMatches() async { + final query = select(matchTable); + final result = await query.get(); + + return Future.wait( + result.map((row) async { + final group = await db.groupMatchDao.getGroupOfMatch(matchId: row.id); + final players = await db.playerMatchDao.getPlayersOfMatch( + matchId: row.id, + ); + final winner = row.winnerId != null + ? await db.playerDao.getPlayerById(playerId: row.winnerId!) + : null; + return Match( + id: row.id, + name: row.name, + group: group, + players: players, + createdAt: row.createdAt, + winner: winner, + ); + }), + ); + } + + /// Retrieves a [Match] by its [matchId]. + Future getMatchById({required String matchId}) async { + final query = select(matchTable)..where((g) => g.id.equals(matchId)); + final result = await query.getSingle(); + + List? players; + if (await db.playerMatchDao.matchHasPlayers(matchId: matchId)) { + players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId); + } + Group? group; + if (await db.groupMatchDao.matchHasGroup(matchId: matchId)) { + group = await db.groupMatchDao.getGroupOfMatch(matchId: matchId); + } + Player? winner; + if (result.winnerId != null) { + winner = await db.playerDao.getPlayerById(playerId: result.winnerId!); + } + + return Match( + id: result.id, + name: result.name, + players: players, + group: group, + winner: winner, + createdAt: result.createdAt, + ); + } + + /// Adds a new [Match] to the database. Also adds players and group + /// associations. This method assumes that the players and groups added to + /// this match are already present in the database. + Future addMatch({required Match match}) async { + await db.transaction(() async { + await into(matchTable).insert( + MatchTableCompanion.insert( + id: match.id, + name: match.name, + winnerId: Value(match.winner?.id), + createdAt: match.createdAt, + ), + mode: InsertMode.insertOrReplace, + ); + + if (match.players != null) { + for (final p in match.players ?? []) { + await db.playerMatchDao.addPlayerToMatch( + matchId: match.id, + playerId: p.id, + ); + } + } + + if (match.group != null) { + await db.groupMatchDao.addGroupToMatch( + matchId: match.id, + groupId: match.group!.id, + ); + } + }); + } + + /// Adds multiple [Match]s to the database in a batch operation. + /// Also adds associated players and groups if they exist. + /// If the [matches] list is empty, the method returns immediately. + /// This Method should only be used to import matches from a different device. + Future addMatchAsList({required List matches}) async { + if (matches.isEmpty) return; + await db.transaction(() async { + // Add all matches in batch + await db.batch( + (b) => b.insertAll( + matchTable, + matches + .map( + (match) => MatchTableCompanion.insert( + id: match.id, + name: match.name, + createdAt: match.createdAt, + winnerId: Value(match.winner?.id), + ), + ) + .toList(), + mode: InsertMode.insertOrReplace, + ), + ); + + // Add all groups of the matches in batch + // Using insertOrIgnore to avoid overwriting existing groups (which would + // trigger cascade deletes on player_group associations) + await db.batch( + (b) => b.insertAll( + db.groupTable, + matches + .where((match) => match.group != null) + .map( + (matches) => GroupTableCompanion.insert( + id: matches.group!.id, + name: matches.group!.name, + createdAt: matches.group!.createdAt, + ), + ) + .toList(), + mode: InsertMode.insertOrIgnore, + ), + ); + + // Add all players of the matches in batch (unique) + final uniquePlayers = {}; + for (final match in matches) { + if (match.players != null) { + for (final p in match.players!) { + uniquePlayers[p.id] = p; + } + } + // Also include members of groups + if (match.group != null) { + for (final m in match.group!.members) { + uniquePlayers[m.id] = m; + } + } + } + + if (uniquePlayers.isNotEmpty) { + // Using insertOrIgnore to avoid triggering cascade deletes on + // player_group/player_match associations when players already exist + await db.batch( + (b) => b.insertAll( + db.playerTable, + uniquePlayers.values + .map( + (p) => PlayerTableCompanion.insert( + id: p.id, + name: p.name, + createdAt: p.createdAt, + ), + ) + .toList(), + mode: InsertMode.insertOrIgnore, + ), + ); + } + + // Add all player-match associations in batch + await db.batch((b) { + for (final match in matches) { + if (match.players != null) { + for (final p in match.players ?? []) { + b.insert( + db.playerMatchTable, + PlayerMatchTableCompanion.insert( + matchId: match.id, + playerId: p.id, + ), + mode: InsertMode.insertOrIgnore, + ); + } + } + } + }); + + // Add all player-group associations in batch + await db.batch((b) { + for (final match in matches) { + if (match.group != null) { + for (final m in match.group!.members) { + b.insert( + db.playerGroupTable, + PlayerGroupTableCompanion.insert( + playerId: m.id, + groupId: match.group!.id, + ), + mode: InsertMode.insertOrIgnore, + ); + } + } + } + }); + + // Add all group-match associations in batch + await db.batch((b) { + for (final match in matches) { + if (match.group != null) { + b.insert( + db.groupMatchTable, + GroupMatchTableCompanion.insert( + matchId: match.id, + groupId: match.group!.id, + ), + mode: InsertMode.insertOrIgnore, + ); + } + } + }); + }); + } + + /// Deletes the match with the given [matchId] from the database. + /// Returns `true` if more than 0 rows were affected, otherwise `false`. + Future deleteMatch({required String matchId}) async { + final query = delete(matchTable)..where((g) => g.id.equals(matchId)); + final rowsAffected = await query.go(); + return rowsAffected > 0; + } + + /// Retrieves the number of matches in the database. + Future getMatchCount() async { + final count = + await (selectOnly(matchTable)..addColumns([matchTable.id.count()])) + .map((row) => row.read(matchTable.id.count())) + .getSingle(); + return count ?? 0; + } + + /// Checks if a match with the given [matchId] exists in the database. + /// Returns `true` if the match exists, otherwise `false`. + Future matchExists({required String matchId}) async { + final query = select(matchTable)..where((g) => g.id.equals(matchId)); + final result = await query.getSingleOrNull(); + return result != null; + } + + /// Deletes all matches from the database. + /// Returns `true` if more than 0 rows were affected, otherwise `false`. + Future deleteAllMatches() async { + final query = delete(matchTable); + final rowsAffected = await query.go(); + return rowsAffected > 0; + } + + /// Sets the winner of the match with the given [matchId] to the player with + /// the given [winnerId]. + /// Returns `true` if more than 0 rows were affected, otherwise `false`. + Future setWinner({ + required String matchId, + required String winnerId, + }) async { + final query = update(matchTable)..where((g) => g.id.equals(matchId)); + final rowsAffected = await query.write( + MatchTableCompanion(winnerId: Value(winnerId)), + ); + return rowsAffected > 0; + } + + /// Retrieves the winner of the match with the given [matchId]. + /// Returns the [Player] who won the match, or `null` if no winner is set. + Future getWinner({required String matchId}) async { + final query = select(matchTable)..where((g) => g.id.equals(matchId)); + final result = await query.getSingleOrNull(); + if (result == null || result.winnerId == null) { + return null; + } + final winner = await db.playerDao.getPlayerById(playerId: result.winnerId!); + return winner; + } + + /// Removes the winner of the match with the given [matchId]. + /// Returns `true` if more than 0 rows were affected, otherwise `false`. + Future removeWinner({required String matchId}) async { + final query = update(matchTable)..where((g) => g.id.equals(matchId)); + final rowsAffected = await query.write( + const MatchTableCompanion(winnerId: Value(null)), + ); + return rowsAffected > 0; + } + + /// Checks if the match with the given [matchId] has a winner set. + /// Returns `true` if a winner is set, otherwise `false`. + Future hasWinner({required String matchId}) async { + final query = select(matchTable) + ..where((g) => g.id.equals(matchId) & g.winnerId.isNotNull()); + final result = await query.getSingleOrNull(); + return result != null; + } + + /// Changes the title of the match with the given [matchId] to [newName]. + /// Returns `true` if more than 0 rows were affected, otherwise `false`. + Future updateMatchName({ + required String matchId, + required String newName, + }) async { + final query = update(matchTable)..where((g) => g.id.equals(matchId)); + final rowsAffected = await query.write( + MatchTableCompanion(name: Value(newName)), + ); + return rowsAffected > 0; + } +} diff --git a/lib/data/dao/match_dao.g.dart b/lib/data/dao/match_dao.g.dart new file mode 100644 index 0000000..a9f6f4c --- /dev/null +++ b/lib/data/dao/match_dao.g.dart @@ -0,0 +1,8 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'match_dao.dart'; + +// ignore_for_file: type=lint +mixin _$MatchDaoMixin on DatabaseAccessor { + $MatchTableTable get matchTable => attachedDatabase.matchTable; +} diff --git a/lib/data/dao/player_dao.dart b/lib/data/dao/player_dao.dart index 8a58504..c8db800 100644 --- a/lib/data/dao/player_dao.dart +++ b/lib/data/dao/player_dao.dart @@ -50,6 +50,8 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { } /// Adds multiple [players] to the database in a batch operation. + /// Uses insertOrIgnore to avoid triggering cascade deletes on + /// player_group associations when players already exist. Future addPlayersAsList({required List players}) async { if (players.isEmpty) return false; @@ -65,7 +67,7 @@ class PlayerDao extends DatabaseAccessor with _$PlayerDaoMixin { ), ) .toList(), - mode: InsertMode.insertOrReplace, + mode: InsertMode.insertOrIgnore, ), ); diff --git a/lib/data/dao/player_game_dao.dart b/lib/data/dao/player_game_dao.dart deleted file mode 100644 index b7f253f..0000000 --- a/lib/data/dao/player_game_dao.dart +++ /dev/null @@ -1,128 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/db/tables/player_game_table.dart'; -import 'package:game_tracker/data/dto/player.dart'; - -part 'player_game_dao.g.dart'; - -@DriftAccessor(tables: [PlayerGameTable]) -class PlayerGameDao extends DatabaseAccessor - with _$PlayerGameDaoMixin { - PlayerGameDao(super.db); - - /// Associates a player with a game by inserting a record into the - /// [PlayerGameTable]. - Future addPlayerToGame({ - required String gameId, - required String playerId, - }) async { - await into(playerGameTable).insert( - PlayerGameTableCompanion.insert(playerId: playerId, gameId: gameId), - mode: InsertMode.insertOrReplace, - ); - } - - /// Retrieves a list of [Player]s associated with the given [gameId]. - /// Returns null if no players are found. - Future?> getPlayersOfGame({required String gameId}) async { - final result = await (select( - playerGameTable, - )..where((p) => p.gameId.equals(gameId))).get(); - - if (result.isEmpty) return null; - - final futures = result.map( - (row) => db.playerDao.getPlayerById(playerId: row.playerId), - ); - final players = await Future.wait(futures); - return players; - } - - /// Checks if there are any players associated with the given [gameId]. - /// Returns `true` if there are players, otherwise `false`. - Future gameHasPlayers({required String gameId}) async { - final count = - await (selectOnly(playerGameTable) - ..where(playerGameTable.gameId.equals(gameId)) - ..addColumns([playerGameTable.playerId.count()])) - .map((row) => row.read(playerGameTable.playerId.count())) - .getSingle(); - return (count ?? 0) > 0; - } - - /// Checks if a specific player is associated with a specific game. - /// Returns `true` if the player is in the game, otherwise `false`. - Future isPlayerInGame({ - required String gameId, - required String playerId, - }) async { - final count = - await (selectOnly(playerGameTable) - ..where(playerGameTable.gameId.equals(gameId)) - ..where(playerGameTable.playerId.equals(playerId)) - ..addColumns([playerGameTable.playerId.count()])) - .map((row) => row.read(playerGameTable.playerId.count())) - .getSingle(); - return (count ?? 0) > 0; - } - - /// Removes the association of a player with a game by deleting the record - /// from the [PlayerGameTable]. - /// Returns `true` if more than 0 rows were affected, otherwise `false`. - Future removePlayerFromGame({ - required String gameId, - required String playerId, - }) async { - final query = delete(playerGameTable) - ..where((pg) => pg.gameId.equals(gameId)) - ..where((pg) => pg.playerId.equals(playerId)); - final rowsAffected = await query.go(); - return rowsAffected > 0; - } - - /// Updates the players associated with a game based on the provided - /// [newPlayer] list. It adds new players and removes players that are no - /// longer associated with the game. - Future updatePlayersFromGame({ - required String gameId, - required List newPlayer, - }) async { - final currentPlayers = await getPlayersOfGame(gameId: gameId); - // Create sets of player IDs for easy comparison - final currentPlayerIds = currentPlayers?.map((p) => p.id).toSet() ?? {}; - final newPlayerIdsSet = newPlayer.map((p) => p.id).toSet(); - - // Determine players to add and remove - final playersToAdd = newPlayerIdsSet.difference(currentPlayerIds); - final playersToRemove = currentPlayerIds.difference(newPlayerIdsSet); - - db.transaction(() async { - // Remove old players - if (playersToRemove.isNotEmpty) { - await (delete(playerGameTable)..where( - (pg) => - pg.gameId.equals(gameId) & - pg.playerId.isIn(playersToRemove.toList()), - )) - .go(); - } - - // Add new players - if (playersToAdd.isNotEmpty) { - final inserts = playersToAdd - .map( - (id) => - PlayerGameTableCompanion.insert(playerId: id, gameId: gameId), - ) - .toList(); - await Future.wait( - inserts.map( - (c) => into( - playerGameTable, - ).insert(c, mode: InsertMode.insertOrReplace), - ), - ); - } - }); - } -} diff --git a/lib/data/dao/player_game_dao.g.dart b/lib/data/dao/player_game_dao.g.dart deleted file mode 100644 index 4d0a192..0000000 --- a/lib/data/dao/player_game_dao.g.dart +++ /dev/null @@ -1,10 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'player_game_dao.dart'; - -// ignore_for_file: type=lint -mixin _$PlayerGameDaoMixin on DatabaseAccessor { - $PlayerTableTable get playerTable => attachedDatabase.playerTable; - $GameTableTable get gameTable => attachedDatabase.gameTable; - $PlayerGameTableTable get playerGameTable => attachedDatabase.playerGameTable; -} diff --git a/lib/data/dao/player_group_dao.dart b/lib/data/dao/player_group_dao.dart index 8cf96c2..db45735 100644 --- a/lib/data/dao/player_group_dao.dart +++ b/lib/data/dao/player_group_dao.dart @@ -1,11 +1,12 @@ import 'package:drift/drift.dart'; import 'package:game_tracker/data/db/database.dart'; import 'package:game_tracker/data/db/tables/player_group_table.dart'; +import 'package:game_tracker/data/db/tables/player_table.dart'; import 'package:game_tracker/data/dto/player.dart'; part 'player_group_dao.g.dart'; -@DriftAccessor(tables: [PlayerGroupTable]) +@DriftAccessor(tables: [PlayerGroupTable, PlayerTable]) class PlayerGroupDao extends DatabaseAccessor with _$PlayerGroupDaoMixin { PlayerGroupDao(super.db); diff --git a/lib/data/dao/player_match_dao.dart b/lib/data/dao/player_match_dao.dart new file mode 100644 index 0000000..7ebaee6 --- /dev/null +++ b/lib/data/dao/player_match_dao.dart @@ -0,0 +1,130 @@ +import 'package:drift/drift.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/data/db/tables/player_match_table.dart'; +import 'package:game_tracker/data/dto/player.dart'; + +part 'player_match_dao.g.dart'; + +@DriftAccessor(tables: [PlayerMatchTable]) +class PlayerMatchDao extends DatabaseAccessor + with _$PlayerMatchDaoMixin { + PlayerMatchDao(super.db); + + /// Associates a player with a match by inserting a record into the + /// [PlayerMatchTable]. + Future addPlayerToMatch({ + required String matchId, + required String playerId, + }) async { + await into(playerMatchTable).insert( + PlayerMatchTableCompanion.insert(playerId: playerId, matchId: matchId), + mode: InsertMode.insertOrIgnore, + ); + } + + /// Retrieves a list of [Player]s associated with the given [matchId]. + /// Returns null if no players are found. + Future?> getPlayersOfMatch({required String matchId}) async { + final result = await (select( + playerMatchTable, + )..where((p) => p.matchId.equals(matchId))).get(); + + if (result.isEmpty) return null; + + final futures = result.map( + (row) => db.playerDao.getPlayerById(playerId: row.playerId), + ); + final players = await Future.wait(futures); + return players; + } + + /// Checks if there are any players associated with the given [matchId]. + /// Returns `true` if there are players, otherwise `false`. + Future matchHasPlayers({required String matchId}) async { + final count = + await (selectOnly(playerMatchTable) + ..where(playerMatchTable.matchId.equals(matchId)) + ..addColumns([playerMatchTable.playerId.count()])) + .map((row) => row.read(playerMatchTable.playerId.count())) + .getSingle(); + return (count ?? 0) > 0; + } + + /// Checks if a specific player is associated with a specific match. + /// Returns `true` if the player is in the match, otherwise `false`. + Future isPlayerInMatch({ + required String matchId, + required String playerId, + }) async { + final count = + await (selectOnly(playerMatchTable) + ..where(playerMatchTable.matchId.equals(matchId)) + ..where(playerMatchTable.playerId.equals(playerId)) + ..addColumns([playerMatchTable.playerId.count()])) + .map((row) => row.read(playerMatchTable.playerId.count())) + .getSingle(); + return (count ?? 0) > 0; + } + + /// Removes the association of a player with a match by deleting the record + /// from the [PlayerMatchTable]. + /// Returns `true` if more than 0 rows were affected, otherwise `false`. + Future removePlayerFromMatch({ + required String matchId, + required String playerId, + }) async { + final query = delete(playerMatchTable) + ..where((pg) => pg.matchId.equals(matchId)) + ..where((pg) => pg.playerId.equals(playerId)); + final rowsAffected = await query.go(); + return rowsAffected > 0; + } + + /// Updates the players associated with a match based on the provided + /// [newPlayer] list. It adds new players and removes players that are no + /// longer associated with the match. + Future updatePlayersFromMatch({ + required String matchId, + required List newPlayer, + }) async { + final currentPlayers = await getPlayersOfMatch(matchId: matchId); + // Create sets of player IDs for easy comparison + final currentPlayerIds = currentPlayers?.map((p) => p.id).toSet() ?? {}; + final newPlayerIdsSet = newPlayer.map((p) => p.id).toSet(); + + // Determine players to add and remove + final playersToAdd = newPlayerIdsSet.difference(currentPlayerIds); + final playersToRemove = currentPlayerIds.difference(newPlayerIdsSet); + + db.transaction(() async { + // Remove old players + if (playersToRemove.isNotEmpty) { + await (delete(playerMatchTable)..where( + (pg) => + pg.matchId.equals(matchId) & + pg.playerId.isIn(playersToRemove.toList()), + )) + .go(); + } + + // Add new players + if (playersToAdd.isNotEmpty) { + final inserts = playersToAdd + .map( + (id) => PlayerMatchTableCompanion.insert( + playerId: id, + matchId: matchId, + ), + ) + .toList(); + await Future.wait( + inserts.map( + (c) => into( + playerMatchTable, + ).insert(c, mode: InsertMode.insertOrIgnore), + ), + ); + } + }); + } +} diff --git a/lib/data/dao/player_match_dao.g.dart b/lib/data/dao/player_match_dao.g.dart new file mode 100644 index 0000000..bcc8ef7 --- /dev/null +++ b/lib/data/dao/player_match_dao.g.dart @@ -0,0 +1,11 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'player_match_dao.dart'; + +// ignore_for_file: type=lint +mixin _$PlayerMatchDaoMixin on DatabaseAccessor { + $PlayerTableTable get playerTable => attachedDatabase.playerTable; + $MatchTableTable get matchTable => attachedDatabase.matchTable; + $PlayerMatchTableTable get playerMatchTable => + attachedDatabase.playerMatchTable; +} diff --git a/lib/data/db/database.dart b/lib/data/db/database.dart index 704e1f0..e6c322f 100644 --- a/lib/data/db/database.dart +++ b/lib/data/db/database.dart @@ -1,16 +1,16 @@ import 'package:drift/drift.dart'; import 'package:drift_flutter/drift_flutter.dart'; -import 'package:game_tracker/data/dao/game_dao.dart'; import 'package:game_tracker/data/dao/group_dao.dart'; -import 'package:game_tracker/data/dao/group_game_dao.dart'; +import 'package:game_tracker/data/dao/group_match_dao.dart'; +import 'package:game_tracker/data/dao/match_dao.dart'; import 'package:game_tracker/data/dao/player_dao.dart'; -import 'package:game_tracker/data/dao/player_game_dao.dart'; import 'package:game_tracker/data/dao/player_group_dao.dart'; -import 'package:game_tracker/data/db/tables/game_table.dart'; -import 'package:game_tracker/data/db/tables/group_game_table.dart'; +import 'package:game_tracker/data/dao/player_match_dao.dart'; +import 'package:game_tracker/data/db/tables/group_match_table.dart'; import 'package:game_tracker/data/db/tables/group_table.dart'; -import 'package:game_tracker/data/db/tables/player_game_table.dart'; +import 'package:game_tracker/data/db/tables/match_table.dart'; import 'package:game_tracker/data/db/tables/player_group_table.dart'; +import 'package:game_tracker/data/db/tables/player_match_table.dart'; import 'package:game_tracker/data/db/tables/player_table.dart'; import 'package:path_provider/path_provider.dart'; @@ -20,18 +20,18 @@ part 'database.g.dart'; tables: [ PlayerTable, GroupTable, - GameTable, + MatchTable, PlayerGroupTable, - PlayerGameTable, - GroupGameTable, + PlayerMatchTable, + GroupMatchTable, ], daos: [ PlayerDao, GroupDao, - GameDao, + MatchDao, PlayerGroupDao, - PlayerGameDao, - GroupGameDao, + PlayerMatchDao, + GroupMatchDao, ], ) class AppDatabase extends _$AppDatabase { diff --git a/lib/data/db/database.g.dart b/lib/data/db/database.g.dart index f211d0c..6bc493c 100644 --- a/lib/data/db/database.g.dart +++ b/lib/data/db/database.g.dart @@ -521,12 +521,12 @@ class GroupTableCompanion extends UpdateCompanion { } } -class $GameTableTable extends GameTable - with TableInfo<$GameTableTable, GameTableData> { +class $MatchTableTable extends MatchTable + with TableInfo<$MatchTableTable, MatchTableData> { @override final GeneratedDatabase attachedDatabase; final String? _alias; - $GameTableTable(this.attachedDatabase, [this._alias]); + $MatchTableTable(this.attachedDatabase, [this._alias]); static const VerificationMeta _idMeta = const VerificationMeta('id'); @override late final GeneratedColumn id = GeneratedColumn( @@ -573,10 +573,10 @@ class $GameTableTable extends GameTable String get aliasedName => _alias ?? actualTableName; @override String get actualTableName => $name; - static const String $name = 'game_table'; + static const String $name = 'match_table'; @override VerificationContext validateIntegrity( - Insertable instance, { + Insertable instance, { bool isInserting = false, }) { final context = VerificationContext(); @@ -614,9 +614,9 @@ class $GameTableTable extends GameTable @override Set get $primaryKey => {id}; @override - GameTableData map(Map data, {String? tablePrefix}) { + MatchTableData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return GameTableData( + return MatchTableData( id: attachedDatabase.typeMapping.read( DriftSqlType.string, data['${effectivePrefix}id'], @@ -637,17 +637,17 @@ class $GameTableTable extends GameTable } @override - $GameTableTable createAlias(String alias) { - return $GameTableTable(attachedDatabase, alias); + $MatchTableTable createAlias(String alias) { + return $MatchTableTable(attachedDatabase, alias); } } -class GameTableData extends DataClass implements Insertable { +class MatchTableData extends DataClass implements Insertable { final String id; final String name; final String? winnerId; final DateTime createdAt; - const GameTableData({ + const MatchTableData({ required this.id, required this.name, this.winnerId, @@ -665,8 +665,8 @@ class GameTableData extends DataClass implements Insertable { return map; } - GameTableCompanion toCompanion(bool nullToAbsent) { - return GameTableCompanion( + MatchTableCompanion toCompanion(bool nullToAbsent) { + return MatchTableCompanion( id: Value(id), name: Value(name), winnerId: winnerId == null && nullToAbsent @@ -676,12 +676,12 @@ class GameTableData extends DataClass implements Insertable { ); } - factory GameTableData.fromJson( + factory MatchTableData.fromJson( Map json, { ValueSerializer? serializer, }) { serializer ??= driftRuntimeOptions.defaultSerializer; - return GameTableData( + return MatchTableData( id: serializer.fromJson(json['id']), name: serializer.fromJson(json['name']), winnerId: serializer.fromJson(json['winnerId']), @@ -699,19 +699,19 @@ class GameTableData extends DataClass implements Insertable { }; } - GameTableData copyWith({ + MatchTableData copyWith({ String? id, String? name, Value winnerId = const Value.absent(), DateTime? createdAt, - }) => GameTableData( + }) => MatchTableData( id: id ?? this.id, name: name ?? this.name, winnerId: winnerId.present ? winnerId.value : this.winnerId, createdAt: createdAt ?? this.createdAt, ); - GameTableData copyWithCompanion(GameTableCompanion data) { - return GameTableData( + MatchTableData copyWithCompanion(MatchTableCompanion data) { + return MatchTableData( id: data.id.present ? data.id.value : this.id, name: data.name.present ? data.name.value : this.name, winnerId: data.winnerId.present ? data.winnerId.value : this.winnerId, @@ -721,7 +721,7 @@ class GameTableData extends DataClass implements Insertable { @override String toString() { - return (StringBuffer('GameTableData(') + return (StringBuffer('MatchTableData(') ..write('id: $id, ') ..write('name: $name, ') ..write('winnerId: $winnerId, ') @@ -735,27 +735,27 @@ class GameTableData extends DataClass implements Insertable { @override bool operator ==(Object other) => identical(this, other) || - (other is GameTableData && + (other is MatchTableData && other.id == this.id && other.name == this.name && other.winnerId == this.winnerId && other.createdAt == this.createdAt); } -class GameTableCompanion extends UpdateCompanion { +class MatchTableCompanion extends UpdateCompanion { final Value id; final Value name; final Value winnerId; final Value createdAt; final Value rowid; - const GameTableCompanion({ + const MatchTableCompanion({ this.id = const Value.absent(), this.name = const Value.absent(), this.winnerId = const Value.absent(), this.createdAt = const Value.absent(), this.rowid = const Value.absent(), }); - GameTableCompanion.insert({ + MatchTableCompanion.insert({ required String id, required String name, this.winnerId = const Value.absent(), @@ -764,7 +764,7 @@ class GameTableCompanion extends UpdateCompanion { }) : id = Value(id), name = Value(name), createdAt = Value(createdAt); - static Insertable custom({ + static Insertable custom({ Expression? id, Expression? name, Expression? winnerId, @@ -780,14 +780,14 @@ class GameTableCompanion extends UpdateCompanion { }); } - GameTableCompanion copyWith({ + MatchTableCompanion copyWith({ Value? id, Value? name, Value? winnerId, Value? createdAt, Value? rowid, }) { - return GameTableCompanion( + return MatchTableCompanion( id: id ?? this.id, name: name ?? this.name, winnerId: winnerId ?? this.winnerId, @@ -819,7 +819,7 @@ class GameTableCompanion extends UpdateCompanion { @override String toString() { - return (StringBuffer('GameTableCompanion(') + return (StringBuffer('MatchTableCompanion(') ..write('id: $id, ') ..write('name: $name, ') ..write('winnerId: $winnerId, ') @@ -1055,12 +1055,12 @@ class PlayerGroupTableCompanion extends UpdateCompanion { } } -class $PlayerGameTableTable extends PlayerGameTable - with TableInfo<$PlayerGameTableTable, PlayerGameTableData> { +class $PlayerMatchTableTable extends PlayerMatchTable + with TableInfo<$PlayerMatchTableTable, PlayerMatchTableData> { @override final GeneratedDatabase attachedDatabase; final String? _alias; - $PlayerGameTableTable(this.attachedDatabase, [this._alias]); + $PlayerMatchTableTable(this.attachedDatabase, [this._alias]); static const VerificationMeta _playerIdMeta = const VerificationMeta( 'playerId', ); @@ -1075,28 +1075,30 @@ class $PlayerGameTableTable extends PlayerGameTable 'REFERENCES player_table (id) ON DELETE CASCADE', ), ); - static const VerificationMeta _gameIdMeta = const VerificationMeta('gameId'); + static const VerificationMeta _matchIdMeta = const VerificationMeta( + 'matchId', + ); @override - late final GeneratedColumn gameId = GeneratedColumn( - 'game_id', + late final GeneratedColumn matchId = GeneratedColumn( + 'match_id', aliasedName, false, type: DriftSqlType.string, requiredDuringInsert: true, defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES game_table (id) ON DELETE CASCADE', + 'REFERENCES match_table (id) ON DELETE CASCADE', ), ); @override - List get $columns => [playerId, gameId]; + List get $columns => [playerId, matchId]; @override String get aliasedName => _alias ?? actualTableName; @override String get actualTableName => $name; - static const String $name = 'player_game_table'; + static const String $name = 'player_match_table'; @override VerificationContext validateIntegrity( - Insertable instance, { + Insertable instance, { bool isInserting = false, }) { final context = VerificationContext(); @@ -1109,68 +1111,68 @@ class $PlayerGameTableTable extends PlayerGameTable } else if (isInserting) { context.missing(_playerIdMeta); } - if (data.containsKey('game_id')) { + if (data.containsKey('match_id')) { context.handle( - _gameIdMeta, - gameId.isAcceptableOrUnknown(data['game_id']!, _gameIdMeta), + _matchIdMeta, + matchId.isAcceptableOrUnknown(data['match_id']!, _matchIdMeta), ); } else if (isInserting) { - context.missing(_gameIdMeta); + context.missing(_matchIdMeta); } return context; } @override - Set get $primaryKey => {playerId, gameId}; + Set get $primaryKey => {playerId, matchId}; @override - PlayerGameTableData map(Map data, {String? tablePrefix}) { + PlayerMatchTableData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return PlayerGameTableData( + return PlayerMatchTableData( playerId: attachedDatabase.typeMapping.read( DriftSqlType.string, data['${effectivePrefix}player_id'], )!, - gameId: attachedDatabase.typeMapping.read( + matchId: attachedDatabase.typeMapping.read( DriftSqlType.string, - data['${effectivePrefix}game_id'], + data['${effectivePrefix}match_id'], )!, ); } @override - $PlayerGameTableTable createAlias(String alias) { - return $PlayerGameTableTable(attachedDatabase, alias); + $PlayerMatchTableTable createAlias(String alias) { + return $PlayerMatchTableTable(attachedDatabase, alias); } } -class PlayerGameTableData extends DataClass - implements Insertable { +class PlayerMatchTableData extends DataClass + implements Insertable { final String playerId; - final String gameId; - const PlayerGameTableData({required this.playerId, required this.gameId}); + final String matchId; + const PlayerMatchTableData({required this.playerId, required this.matchId}); @override Map toColumns(bool nullToAbsent) { final map = {}; map['player_id'] = Variable(playerId); - map['game_id'] = Variable(gameId); + map['match_id'] = Variable(matchId); return map; } - PlayerGameTableCompanion toCompanion(bool nullToAbsent) { - return PlayerGameTableCompanion( + PlayerMatchTableCompanion toCompanion(bool nullToAbsent) { + return PlayerMatchTableCompanion( playerId: Value(playerId), - gameId: Value(gameId), + matchId: Value(matchId), ); } - factory PlayerGameTableData.fromJson( + factory PlayerMatchTableData.fromJson( Map json, { ValueSerializer? serializer, }) { serializer ??= driftRuntimeOptions.defaultSerializer; - return PlayerGameTableData( + return PlayerMatchTableData( playerId: serializer.fromJson(json['playerId']), - gameId: serializer.fromJson(json['gameId']), + matchId: serializer.fromJson(json['matchId']), ); } @override @@ -1178,76 +1180,76 @@ class PlayerGameTableData extends DataClass serializer ??= driftRuntimeOptions.defaultSerializer; return { 'playerId': serializer.toJson(playerId), - 'gameId': serializer.toJson(gameId), + 'matchId': serializer.toJson(matchId), }; } - PlayerGameTableData copyWith({String? playerId, String? gameId}) => - PlayerGameTableData( + PlayerMatchTableData copyWith({String? playerId, String? matchId}) => + PlayerMatchTableData( playerId: playerId ?? this.playerId, - gameId: gameId ?? this.gameId, + matchId: matchId ?? this.matchId, ); - PlayerGameTableData copyWithCompanion(PlayerGameTableCompanion data) { - return PlayerGameTableData( + PlayerMatchTableData copyWithCompanion(PlayerMatchTableCompanion data) { + return PlayerMatchTableData( playerId: data.playerId.present ? data.playerId.value : this.playerId, - gameId: data.gameId.present ? data.gameId.value : this.gameId, + matchId: data.matchId.present ? data.matchId.value : this.matchId, ); } @override String toString() { - return (StringBuffer('PlayerGameTableData(') + return (StringBuffer('PlayerMatchTableData(') ..write('playerId: $playerId, ') - ..write('gameId: $gameId') + ..write('matchId: $matchId') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(playerId, gameId); + int get hashCode => Object.hash(playerId, matchId); @override bool operator ==(Object other) => identical(this, other) || - (other is PlayerGameTableData && + (other is PlayerMatchTableData && other.playerId == this.playerId && - other.gameId == this.gameId); + other.matchId == this.matchId); } -class PlayerGameTableCompanion extends UpdateCompanion { +class PlayerMatchTableCompanion extends UpdateCompanion { final Value playerId; - final Value gameId; + final Value matchId; final Value rowid; - const PlayerGameTableCompanion({ + const PlayerMatchTableCompanion({ this.playerId = const Value.absent(), - this.gameId = const Value.absent(), + this.matchId = const Value.absent(), this.rowid = const Value.absent(), }); - PlayerGameTableCompanion.insert({ + PlayerMatchTableCompanion.insert({ required String playerId, - required String gameId, + required String matchId, this.rowid = const Value.absent(), }) : playerId = Value(playerId), - gameId = Value(gameId); - static Insertable custom({ + matchId = Value(matchId); + static Insertable custom({ Expression? playerId, - Expression? gameId, + Expression? matchId, Expression? rowid, }) { return RawValuesInsertable({ if (playerId != null) 'player_id': playerId, - if (gameId != null) 'game_id': gameId, + if (matchId != null) 'match_id': matchId, if (rowid != null) 'rowid': rowid, }); } - PlayerGameTableCompanion copyWith({ + PlayerMatchTableCompanion copyWith({ Value? playerId, - Value? gameId, + Value? matchId, Value? rowid, }) { - return PlayerGameTableCompanion( + return PlayerMatchTableCompanion( playerId: playerId ?? this.playerId, - gameId: gameId ?? this.gameId, + matchId: matchId ?? this.matchId, rowid: rowid ?? this.rowid, ); } @@ -1258,8 +1260,8 @@ class PlayerGameTableCompanion extends UpdateCompanion { if (playerId.present) { map['player_id'] = Variable(playerId.value); } - if (gameId.present) { - map['game_id'] = Variable(gameId.value); + if (matchId.present) { + map['match_id'] = Variable(matchId.value); } if (rowid.present) { map['rowid'] = Variable(rowid.value); @@ -1269,21 +1271,21 @@ class PlayerGameTableCompanion extends UpdateCompanion { @override String toString() { - return (StringBuffer('PlayerGameTableCompanion(') + return (StringBuffer('PlayerMatchTableCompanion(') ..write('playerId: $playerId, ') - ..write('gameId: $gameId, ') + ..write('matchId: $matchId, ') ..write('rowid: $rowid') ..write(')')) .toString(); } } -class $GroupGameTableTable extends GroupGameTable - with TableInfo<$GroupGameTableTable, GroupGameTableData> { +class $GroupMatchTableTable extends GroupMatchTable + with TableInfo<$GroupMatchTableTable, GroupMatchTableData> { @override final GeneratedDatabase attachedDatabase; final String? _alias; - $GroupGameTableTable(this.attachedDatabase, [this._alias]); + $GroupMatchTableTable(this.attachedDatabase, [this._alias]); static const VerificationMeta _groupIdMeta = const VerificationMeta( 'groupId', ); @@ -1298,28 +1300,30 @@ class $GroupGameTableTable extends GroupGameTable 'REFERENCES group_table (id) ON DELETE CASCADE', ), ); - static const VerificationMeta _gameIdMeta = const VerificationMeta('gameId'); + static const VerificationMeta _matchIdMeta = const VerificationMeta( + 'matchId', + ); @override - late final GeneratedColumn gameId = GeneratedColumn( - 'game_id', + late final GeneratedColumn matchId = GeneratedColumn( + 'match_id', aliasedName, false, type: DriftSqlType.string, requiredDuringInsert: true, defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES game_table (id) ON DELETE CASCADE', + 'REFERENCES match_table (id) ON DELETE CASCADE', ), ); @override - List get $columns => [groupId, gameId]; + List get $columns => [groupId, matchId]; @override String get aliasedName => _alias ?? actualTableName; @override String get actualTableName => $name; - static const String $name = 'group_game_table'; + static const String $name = 'group_match_table'; @override VerificationContext validateIntegrity( - Insertable instance, { + Insertable instance, { bool isInserting = false, }) { final context = VerificationContext(); @@ -1332,68 +1336,68 @@ class $GroupGameTableTable extends GroupGameTable } else if (isInserting) { context.missing(_groupIdMeta); } - if (data.containsKey('game_id')) { + if (data.containsKey('match_id')) { context.handle( - _gameIdMeta, - gameId.isAcceptableOrUnknown(data['game_id']!, _gameIdMeta), + _matchIdMeta, + matchId.isAcceptableOrUnknown(data['match_id']!, _matchIdMeta), ); } else if (isInserting) { - context.missing(_gameIdMeta); + context.missing(_matchIdMeta); } return context; } @override - Set get $primaryKey => {groupId, gameId}; + Set get $primaryKey => {groupId, matchId}; @override - GroupGameTableData map(Map data, {String? tablePrefix}) { + GroupMatchTableData map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return GroupGameTableData( + return GroupMatchTableData( groupId: attachedDatabase.typeMapping.read( DriftSqlType.string, data['${effectivePrefix}group_id'], )!, - gameId: attachedDatabase.typeMapping.read( + matchId: attachedDatabase.typeMapping.read( DriftSqlType.string, - data['${effectivePrefix}game_id'], + data['${effectivePrefix}match_id'], )!, ); } @override - $GroupGameTableTable createAlias(String alias) { - return $GroupGameTableTable(attachedDatabase, alias); + $GroupMatchTableTable createAlias(String alias) { + return $GroupMatchTableTable(attachedDatabase, alias); } } -class GroupGameTableData extends DataClass - implements Insertable { +class GroupMatchTableData extends DataClass + implements Insertable { final String groupId; - final String gameId; - const GroupGameTableData({required this.groupId, required this.gameId}); + final String matchId; + const GroupMatchTableData({required this.groupId, required this.matchId}); @override Map toColumns(bool nullToAbsent) { final map = {}; map['group_id'] = Variable(groupId); - map['game_id'] = Variable(gameId); + map['match_id'] = Variable(matchId); return map; } - GroupGameTableCompanion toCompanion(bool nullToAbsent) { - return GroupGameTableCompanion( + GroupMatchTableCompanion toCompanion(bool nullToAbsent) { + return GroupMatchTableCompanion( groupId: Value(groupId), - gameId: Value(gameId), + matchId: Value(matchId), ); } - factory GroupGameTableData.fromJson( + factory GroupMatchTableData.fromJson( Map json, { ValueSerializer? serializer, }) { serializer ??= driftRuntimeOptions.defaultSerializer; - return GroupGameTableData( + return GroupMatchTableData( groupId: serializer.fromJson(json['groupId']), - gameId: serializer.fromJson(json['gameId']), + matchId: serializer.fromJson(json['matchId']), ); } @override @@ -1401,76 +1405,76 @@ class GroupGameTableData extends DataClass serializer ??= driftRuntimeOptions.defaultSerializer; return { 'groupId': serializer.toJson(groupId), - 'gameId': serializer.toJson(gameId), + 'matchId': serializer.toJson(matchId), }; } - GroupGameTableData copyWith({String? groupId, String? gameId}) => - GroupGameTableData( + GroupMatchTableData copyWith({String? groupId, String? matchId}) => + GroupMatchTableData( groupId: groupId ?? this.groupId, - gameId: gameId ?? this.gameId, + matchId: matchId ?? this.matchId, ); - GroupGameTableData copyWithCompanion(GroupGameTableCompanion data) { - return GroupGameTableData( + GroupMatchTableData copyWithCompanion(GroupMatchTableCompanion data) { + return GroupMatchTableData( groupId: data.groupId.present ? data.groupId.value : this.groupId, - gameId: data.gameId.present ? data.gameId.value : this.gameId, + matchId: data.matchId.present ? data.matchId.value : this.matchId, ); } @override String toString() { - return (StringBuffer('GroupGameTableData(') + return (StringBuffer('GroupMatchTableData(') ..write('groupId: $groupId, ') - ..write('gameId: $gameId') + ..write('matchId: $matchId') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(groupId, gameId); + int get hashCode => Object.hash(groupId, matchId); @override bool operator ==(Object other) => identical(this, other) || - (other is GroupGameTableData && + (other is GroupMatchTableData && other.groupId == this.groupId && - other.gameId == this.gameId); + other.matchId == this.matchId); } -class GroupGameTableCompanion extends UpdateCompanion { +class GroupMatchTableCompanion extends UpdateCompanion { final Value groupId; - final Value gameId; + final Value matchId; final Value rowid; - const GroupGameTableCompanion({ + const GroupMatchTableCompanion({ this.groupId = const Value.absent(), - this.gameId = const Value.absent(), + this.matchId = const Value.absent(), this.rowid = const Value.absent(), }); - GroupGameTableCompanion.insert({ + GroupMatchTableCompanion.insert({ required String groupId, - required String gameId, + required String matchId, this.rowid = const Value.absent(), }) : groupId = Value(groupId), - gameId = Value(gameId); - static Insertable custom({ + matchId = Value(matchId); + static Insertable custom({ Expression? groupId, - Expression? gameId, + Expression? matchId, Expression? rowid, }) { return RawValuesInsertable({ if (groupId != null) 'group_id': groupId, - if (gameId != null) 'game_id': gameId, + if (matchId != null) 'match_id': matchId, if (rowid != null) 'rowid': rowid, }); } - GroupGameTableCompanion copyWith({ + GroupMatchTableCompanion copyWith({ Value? groupId, - Value? gameId, + Value? matchId, Value? rowid, }) { - return GroupGameTableCompanion( + return GroupMatchTableCompanion( groupId: groupId ?? this.groupId, - gameId: gameId ?? this.gameId, + matchId: matchId ?? this.matchId, rowid: rowid ?? this.rowid, ); } @@ -1481,8 +1485,8 @@ class GroupGameTableCompanion extends UpdateCompanion { if (groupId.present) { map['group_id'] = Variable(groupId.value); } - if (gameId.present) { - map['game_id'] = Variable(gameId.value); + if (matchId.present) { + map['match_id'] = Variable(matchId.value); } if (rowid.present) { map['rowid'] = Variable(rowid.value); @@ -1492,9 +1496,9 @@ class GroupGameTableCompanion extends UpdateCompanion { @override String toString() { - return (StringBuffer('GroupGameTableCompanion(') + return (StringBuffer('GroupMatchTableCompanion(') ..write('groupId: $groupId, ') - ..write('gameId: $gameId, ') + ..write('matchId: $matchId, ') ..write('rowid: $rowid') ..write(')')) .toString(); @@ -1506,22 +1510,26 @@ abstract class _$AppDatabase extends GeneratedDatabase { $AppDatabaseManager get managers => $AppDatabaseManager(this); late final $PlayerTableTable playerTable = $PlayerTableTable(this); late final $GroupTableTable groupTable = $GroupTableTable(this); - late final $GameTableTable gameTable = $GameTableTable(this); + late final $MatchTableTable matchTable = $MatchTableTable(this); late final $PlayerGroupTableTable playerGroupTable = $PlayerGroupTableTable( this, ); - late final $PlayerGameTableTable playerGameTable = $PlayerGameTableTable( + late final $PlayerMatchTableTable playerMatchTable = $PlayerMatchTableTable( + this, + ); + late final $GroupMatchTableTable groupMatchTable = $GroupMatchTableTable( this, ); - late final $GroupGameTableTable groupGameTable = $GroupGameTableTable(this); late final PlayerDao playerDao = PlayerDao(this as AppDatabase); late final GroupDao groupDao = GroupDao(this as AppDatabase); - late final GameDao gameDao = GameDao(this as AppDatabase); + late final MatchDao matchDao = MatchDao(this as AppDatabase); late final PlayerGroupDao playerGroupDao = PlayerGroupDao( this as AppDatabase, ); - late final PlayerGameDao playerGameDao = PlayerGameDao(this as AppDatabase); - late final GroupGameDao groupGameDao = GroupGameDao(this as AppDatabase); + late final PlayerMatchDao playerMatchDao = PlayerMatchDao( + this as AppDatabase, + ); + late final GroupMatchDao groupMatchDao = GroupMatchDao(this as AppDatabase); @override Iterable> get allTables => allSchemaEntities.whereType>(); @@ -1529,10 +1537,10 @@ abstract class _$AppDatabase extends GeneratedDatabase { List get allSchemaEntities => [ playerTable, groupTable, - gameTable, + matchTable, playerGroupTable, - playerGameTable, - groupGameTable, + playerMatchTable, + groupMatchTable, ]; @override StreamQueryUpdateRules get streamUpdateRules => const StreamQueryUpdateRules([ @@ -1555,28 +1563,28 @@ abstract class _$AppDatabase extends GeneratedDatabase { 'player_table', limitUpdateKind: UpdateKind.delete, ), - result: [TableUpdate('player_game_table', kind: UpdateKind.delete)], + result: [TableUpdate('player_match_table', kind: UpdateKind.delete)], ), WritePropagation( on: TableUpdateQuery.onTableName( - 'game_table', + 'match_table', limitUpdateKind: UpdateKind.delete, ), - result: [TableUpdate('player_game_table', kind: UpdateKind.delete)], + result: [TableUpdate('player_match_table', kind: UpdateKind.delete)], ), WritePropagation( on: TableUpdateQuery.onTableName( 'group_table', limitUpdateKind: UpdateKind.delete, ), - result: [TableUpdate('group_game_table', kind: UpdateKind.delete)], + result: [TableUpdate('group_match_table', kind: UpdateKind.delete)], ), WritePropagation( on: TableUpdateQuery.onTableName( - 'game_table', + 'match_table', limitUpdateKind: UpdateKind.delete, ), - result: [TableUpdate('group_game_table', kind: UpdateKind.delete)], + result: [TableUpdate('group_match_table', kind: UpdateKind.delete)], ), ]); } @@ -1623,23 +1631,23 @@ final class $$PlayerTableTableReferences ); } - static MultiTypedResultKey<$PlayerGameTableTable, List> - _playerGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( - db.playerGameTable, + static MultiTypedResultKey<$PlayerMatchTableTable, List> + _playerMatchTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.playerMatchTable, aliasName: $_aliasNameGenerator( db.playerTable.id, - db.playerGameTable.playerId, + db.playerMatchTable.playerId, ), ); - $$PlayerGameTableTableProcessedTableManager get playerGameTableRefs { - final manager = $$PlayerGameTableTableTableManager( + $$PlayerMatchTableTableProcessedTableManager get playerMatchTableRefs { + final manager = $$PlayerMatchTableTableTableManager( $_db, - $_db.playerGameTable, + $_db.playerMatchTable, ).filter((f) => f.playerId.id.sqlEquals($_itemColumn('id')!)); final cache = $_typedResult.readTableOrNull( - _playerGameTableRefsTable($_db), + _playerMatchTableRefsTable($_db), ); return ProcessedTableManager( manager.$state.copyWith(prefetchedData: cache), @@ -1696,22 +1704,22 @@ class $$PlayerTableTableFilterComposer return f(composer); } - Expression playerGameTableRefs( - Expression Function($$PlayerGameTableTableFilterComposer f) f, + Expression playerMatchTableRefs( + Expression Function($$PlayerMatchTableTableFilterComposer f) f, ) { - final $$PlayerGameTableTableFilterComposer composer = $composerBuilder( + final $$PlayerMatchTableTableFilterComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.id, - referencedTable: $db.playerGameTable, + referencedTable: $db.playerMatchTable, getReferencedColumn: (t) => t.playerId, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$PlayerGameTableTableFilterComposer( + }) => $$PlayerMatchTableTableFilterComposer( $db: $db, - $table: $db.playerGameTable, + $table: $db.playerMatchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -1790,22 +1798,22 @@ class $$PlayerTableTableAnnotationComposer return f(composer); } - Expression playerGameTableRefs( - Expression Function($$PlayerGameTableTableAnnotationComposer a) f, + Expression playerMatchTableRefs( + Expression Function($$PlayerMatchTableTableAnnotationComposer a) f, ) { - final $$PlayerGameTableTableAnnotationComposer composer = $composerBuilder( + final $$PlayerMatchTableTableAnnotationComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.id, - referencedTable: $db.playerGameTable, + referencedTable: $db.playerMatchTable, getReferencedColumn: (t) => t.playerId, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$PlayerGameTableTableAnnotationComposer( + }) => $$PlayerMatchTableTableAnnotationComposer( $db: $db, - $table: $db.playerGameTable, + $table: $db.playerMatchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -1831,7 +1839,7 @@ class $$PlayerTableTableTableManager PlayerTableData, PrefetchHooks Function({ bool playerGroupTableRefs, - bool playerGameTableRefs, + bool playerMatchTableRefs, }) > { $$PlayerTableTableTableManager(_$AppDatabase db, $PlayerTableTable table) @@ -1878,12 +1886,12 @@ class $$PlayerTableTableTableManager ) .toList(), prefetchHooksCallback: - ({playerGroupTableRefs = false, playerGameTableRefs = false}) { + ({playerGroupTableRefs = false, playerMatchTableRefs = false}) { return PrefetchHooks( db: db, explicitlyWatchedTables: [ if (playerGroupTableRefs) db.playerGroupTable, - if (playerGameTableRefs) db.playerGameTable, + if (playerMatchTableRefs) db.playerMatchTable, ], addJoins: null, getPrefetchedDataCallback: (items) async { @@ -1909,21 +1917,21 @@ class $$PlayerTableTableTableManager ), typedResults: items, ), - if (playerGameTableRefs) + if (playerMatchTableRefs) await $_getPrefetchedData< PlayerTableData, $PlayerTableTable, - PlayerGameTableData + PlayerMatchTableData >( currentTable: table, referencedTable: $$PlayerTableTableReferences - ._playerGameTableRefsTable(db), + ._playerMatchTableRefsTable(db), managerFromTypedResult: (p0) => $$PlayerTableTableReferences( db, table, p0, - ).playerGameTableRefs, + ).playerMatchTableRefs, referencedItemsForCurrentItem: (item, referencedItems) => referencedItems.where( (e) => e.playerId == item.id, @@ -1952,7 +1960,7 @@ typedef $$PlayerTableTableProcessedTableManager = PlayerTableData, PrefetchHooks Function({ bool playerGroupTableRefs, - bool playerGameTableRefs, + bool playerMatchTableRefs, }) >; typedef $$GroupTableTableCreateCompanionBuilder = @@ -1997,22 +2005,24 @@ final class $$GroupTableTableReferences ); } - static MultiTypedResultKey<$GroupGameTableTable, List> - _groupGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( - db.groupGameTable, + static MultiTypedResultKey<$GroupMatchTableTable, List> + _groupMatchTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.groupMatchTable, aliasName: $_aliasNameGenerator( db.groupTable.id, - db.groupGameTable.groupId, + db.groupMatchTable.groupId, ), ); - $$GroupGameTableTableProcessedTableManager get groupGameTableRefs { - final manager = $$GroupGameTableTableTableManager( + $$GroupMatchTableTableProcessedTableManager get groupMatchTableRefs { + final manager = $$GroupMatchTableTableTableManager( $_db, - $_db.groupGameTable, + $_db.groupMatchTable, ).filter((f) => f.groupId.id.sqlEquals($_itemColumn('id')!)); - final cache = $_typedResult.readTableOrNull(_groupGameTableRefsTable($_db)); + final cache = $_typedResult.readTableOrNull( + _groupMatchTableRefsTable($_db), + ); return ProcessedTableManager( manager.$state.copyWith(prefetchedData: cache), ); @@ -2068,22 +2078,22 @@ class $$GroupTableTableFilterComposer return f(composer); } - Expression groupGameTableRefs( - Expression Function($$GroupGameTableTableFilterComposer f) f, + Expression groupMatchTableRefs( + Expression Function($$GroupMatchTableTableFilterComposer f) f, ) { - final $$GroupGameTableTableFilterComposer composer = $composerBuilder( + final $$GroupMatchTableTableFilterComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.id, - referencedTable: $db.groupGameTable, + referencedTable: $db.groupMatchTable, getReferencedColumn: (t) => t.groupId, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$GroupGameTableTableFilterComposer( + }) => $$GroupMatchTableTableFilterComposer( $db: $db, - $table: $db.groupGameTable, + $table: $db.groupMatchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -2162,22 +2172,22 @@ class $$GroupTableTableAnnotationComposer return f(composer); } - Expression groupGameTableRefs( - Expression Function($$GroupGameTableTableAnnotationComposer a) f, + Expression groupMatchTableRefs( + Expression Function($$GroupMatchTableTableAnnotationComposer a) f, ) { - final $$GroupGameTableTableAnnotationComposer composer = $composerBuilder( + final $$GroupMatchTableTableAnnotationComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.id, - referencedTable: $db.groupGameTable, + referencedTable: $db.groupMatchTable, getReferencedColumn: (t) => t.groupId, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$GroupGameTableTableAnnotationComposer( + }) => $$GroupMatchTableTableAnnotationComposer( $db: $db, - $table: $db.groupGameTable, + $table: $db.groupMatchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -2203,7 +2213,7 @@ class $$GroupTableTableTableManager GroupTableData, PrefetchHooks Function({ bool playerGroupTableRefs, - bool groupGameTableRefs, + bool groupMatchTableRefs, }) > { $$GroupTableTableTableManager(_$AppDatabase db, $GroupTableTable table) @@ -2250,12 +2260,12 @@ class $$GroupTableTableTableManager ) .toList(), prefetchHooksCallback: - ({playerGroupTableRefs = false, groupGameTableRefs = false}) { + ({playerGroupTableRefs = false, groupMatchTableRefs = false}) { return PrefetchHooks( db: db, explicitlyWatchedTables: [ if (playerGroupTableRefs) db.playerGroupTable, - if (groupGameTableRefs) db.groupGameTable, + if (groupMatchTableRefs) db.groupMatchTable, ], addJoins: null, getPrefetchedDataCallback: (items) async { @@ -2281,21 +2291,21 @@ class $$GroupTableTableTableManager ), typedResults: items, ), - if (groupGameTableRefs) + if (groupMatchTableRefs) await $_getPrefetchedData< GroupTableData, $GroupTableTable, - GroupGameTableData + GroupMatchTableData >( currentTable: table, referencedTable: $$GroupTableTableReferences - ._groupGameTableRefsTable(db), + ._groupMatchTableRefsTable(db), managerFromTypedResult: (p0) => $$GroupTableTableReferences( db, table, p0, - ).groupGameTableRefs, + ).groupMatchTableRefs, referencedItemsForCurrentItem: (item, referencedItems) => referencedItems.where( (e) => e.groupId == item.id, @@ -2324,19 +2334,19 @@ typedef $$GroupTableTableProcessedTableManager = GroupTableData, PrefetchHooks Function({ bool playerGroupTableRefs, - bool groupGameTableRefs, + bool groupMatchTableRefs, }) >; -typedef $$GameTableTableCreateCompanionBuilder = - GameTableCompanion Function({ +typedef $$MatchTableTableCreateCompanionBuilder = + MatchTableCompanion Function({ required String id, required String name, Value winnerId, required DateTime createdAt, Value rowid, }); -typedef $$GameTableTableUpdateCompanionBuilder = - GameTableCompanion Function({ +typedef $$MatchTableTableUpdateCompanionBuilder = + MatchTableCompanion Function({ Value id, Value name, Value winnerId, @@ -2344,52 +2354,60 @@ typedef $$GameTableTableUpdateCompanionBuilder = Value rowid, }); -final class $$GameTableTableReferences - extends BaseReferences<_$AppDatabase, $GameTableTable, GameTableData> { - $$GameTableTableReferences(super.$_db, super.$_table, super.$_typedResult); +final class $$MatchTableTableReferences + extends BaseReferences<_$AppDatabase, $MatchTableTable, MatchTableData> { + $$MatchTableTableReferences(super.$_db, super.$_table, super.$_typedResult); - static MultiTypedResultKey<$PlayerGameTableTable, List> - _playerGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( - db.playerGameTable, - aliasName: $_aliasNameGenerator(db.gameTable.id, db.playerGameTable.gameId), + static MultiTypedResultKey<$PlayerMatchTableTable, List> + _playerMatchTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.playerMatchTable, + aliasName: $_aliasNameGenerator( + db.matchTable.id, + db.playerMatchTable.matchId, + ), ); - $$PlayerGameTableTableProcessedTableManager get playerGameTableRefs { - final manager = $$PlayerGameTableTableTableManager( + $$PlayerMatchTableTableProcessedTableManager get playerMatchTableRefs { + final manager = $$PlayerMatchTableTableTableManager( $_db, - $_db.playerGameTable, - ).filter((f) => f.gameId.id.sqlEquals($_itemColumn('id')!)); + $_db.playerMatchTable, + ).filter((f) => f.matchId.id.sqlEquals($_itemColumn('id')!)); final cache = $_typedResult.readTableOrNull( - _playerGameTableRefsTable($_db), + _playerMatchTableRefsTable($_db), ); return ProcessedTableManager( manager.$state.copyWith(prefetchedData: cache), ); } - static MultiTypedResultKey<$GroupGameTableTable, List> - _groupGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( - db.groupGameTable, - aliasName: $_aliasNameGenerator(db.gameTable.id, db.groupGameTable.gameId), + static MultiTypedResultKey<$GroupMatchTableTable, List> + _groupMatchTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable( + db.groupMatchTable, + aliasName: $_aliasNameGenerator( + db.matchTable.id, + db.groupMatchTable.matchId, + ), ); - $$GroupGameTableTableProcessedTableManager get groupGameTableRefs { - final manager = $$GroupGameTableTableTableManager( + $$GroupMatchTableTableProcessedTableManager get groupMatchTableRefs { + final manager = $$GroupMatchTableTableTableManager( $_db, - $_db.groupGameTable, - ).filter((f) => f.gameId.id.sqlEquals($_itemColumn('id')!)); + $_db.groupMatchTable, + ).filter((f) => f.matchId.id.sqlEquals($_itemColumn('id')!)); - final cache = $_typedResult.readTableOrNull(_groupGameTableRefsTable($_db)); + final cache = $_typedResult.readTableOrNull( + _groupMatchTableRefsTable($_db), + ); return ProcessedTableManager( manager.$state.copyWith(prefetchedData: cache), ); } } -class $$GameTableTableFilterComposer - extends Composer<_$AppDatabase, $GameTableTable> { - $$GameTableTableFilterComposer({ +class $$MatchTableTableFilterComposer + extends Composer<_$AppDatabase, $MatchTableTable> { + $$MatchTableTableFilterComposer({ required super.$db, required super.$table, super.joinBuilder, @@ -2416,22 +2434,22 @@ class $$GameTableTableFilterComposer builder: (column) => ColumnFilters(column), ); - Expression playerGameTableRefs( - Expression Function($$PlayerGameTableTableFilterComposer f) f, + Expression playerMatchTableRefs( + Expression Function($$PlayerMatchTableTableFilterComposer f) f, ) { - final $$PlayerGameTableTableFilterComposer composer = $composerBuilder( + final $$PlayerMatchTableTableFilterComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.id, - referencedTable: $db.playerGameTable, - getReferencedColumn: (t) => t.gameId, + referencedTable: $db.playerMatchTable, + getReferencedColumn: (t) => t.matchId, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$PlayerGameTableTableFilterComposer( + }) => $$PlayerMatchTableTableFilterComposer( $db: $db, - $table: $db.playerGameTable, + $table: $db.playerMatchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -2441,22 +2459,22 @@ class $$GameTableTableFilterComposer return f(composer); } - Expression groupGameTableRefs( - Expression Function($$GroupGameTableTableFilterComposer f) f, + Expression groupMatchTableRefs( + Expression Function($$GroupMatchTableTableFilterComposer f) f, ) { - final $$GroupGameTableTableFilterComposer composer = $composerBuilder( + final $$GroupMatchTableTableFilterComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.id, - referencedTable: $db.groupGameTable, - getReferencedColumn: (t) => t.gameId, + referencedTable: $db.groupMatchTable, + getReferencedColumn: (t) => t.matchId, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$GroupGameTableTableFilterComposer( + }) => $$GroupMatchTableTableFilterComposer( $db: $db, - $table: $db.groupGameTable, + $table: $db.groupMatchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -2467,9 +2485,9 @@ class $$GameTableTableFilterComposer } } -class $$GameTableTableOrderingComposer - extends Composer<_$AppDatabase, $GameTableTable> { - $$GameTableTableOrderingComposer({ +class $$MatchTableTableOrderingComposer + extends Composer<_$AppDatabase, $MatchTableTable> { + $$MatchTableTableOrderingComposer({ required super.$db, required super.$table, super.joinBuilder, @@ -2497,9 +2515,9 @@ class $$GameTableTableOrderingComposer ); } -class $$GameTableTableAnnotationComposer - extends Composer<_$AppDatabase, $GameTableTable> { - $$GameTableTableAnnotationComposer({ +class $$MatchTableTableAnnotationComposer + extends Composer<_$AppDatabase, $MatchTableTable> { + $$MatchTableTableAnnotationComposer({ required super.$db, required super.$table, super.joinBuilder, @@ -2518,22 +2536,22 @@ class $$GameTableTableAnnotationComposer GeneratedColumn get createdAt => $composableBuilder(column: $table.createdAt, builder: (column) => column); - Expression playerGameTableRefs( - Expression Function($$PlayerGameTableTableAnnotationComposer a) f, + Expression playerMatchTableRefs( + Expression Function($$PlayerMatchTableTableAnnotationComposer a) f, ) { - final $$PlayerGameTableTableAnnotationComposer composer = $composerBuilder( + final $$PlayerMatchTableTableAnnotationComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.id, - referencedTable: $db.playerGameTable, - getReferencedColumn: (t) => t.gameId, + referencedTable: $db.playerMatchTable, + getReferencedColumn: (t) => t.matchId, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$PlayerGameTableTableAnnotationComposer( + }) => $$PlayerMatchTableTableAnnotationComposer( $db: $db, - $table: $db.playerGameTable, + $table: $db.playerMatchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -2543,22 +2561,22 @@ class $$GameTableTableAnnotationComposer return f(composer); } - Expression groupGameTableRefs( - Expression Function($$GroupGameTableTableAnnotationComposer a) f, + Expression groupMatchTableRefs( + Expression Function($$GroupMatchTableTableAnnotationComposer a) f, ) { - final $$GroupGameTableTableAnnotationComposer composer = $composerBuilder( + final $$GroupMatchTableTableAnnotationComposer composer = $composerBuilder( composer: this, getCurrentColumn: (t) => t.id, - referencedTable: $db.groupGameTable, - getReferencedColumn: (t) => t.gameId, + referencedTable: $db.groupMatchTable, + getReferencedColumn: (t) => t.matchId, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$GroupGameTableTableAnnotationComposer( + }) => $$GroupMatchTableTableAnnotationComposer( $db: $db, - $table: $db.groupGameTable, + $table: $db.groupMatchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -2569,35 +2587,35 @@ class $$GameTableTableAnnotationComposer } } -class $$GameTableTableTableManager +class $$MatchTableTableTableManager extends RootTableManager< _$AppDatabase, - $GameTableTable, - GameTableData, - $$GameTableTableFilterComposer, - $$GameTableTableOrderingComposer, - $$GameTableTableAnnotationComposer, - $$GameTableTableCreateCompanionBuilder, - $$GameTableTableUpdateCompanionBuilder, - (GameTableData, $$GameTableTableReferences), - GameTableData, + $MatchTableTable, + MatchTableData, + $$MatchTableTableFilterComposer, + $$MatchTableTableOrderingComposer, + $$MatchTableTableAnnotationComposer, + $$MatchTableTableCreateCompanionBuilder, + $$MatchTableTableUpdateCompanionBuilder, + (MatchTableData, $$MatchTableTableReferences), + MatchTableData, PrefetchHooks Function({ - bool playerGameTableRefs, - bool groupGameTableRefs, + bool playerMatchTableRefs, + bool groupMatchTableRefs, }) > { - $$GameTableTableTableManager(_$AppDatabase db, $GameTableTable table) + $$MatchTableTableTableManager(_$AppDatabase db, $MatchTableTable table) : super( TableManagerState( db: db, table: table, createFilteringComposer: () => - $$GameTableTableFilterComposer($db: db, $table: table), + $$MatchTableTableFilterComposer($db: db, $table: table), createOrderingComposer: () => - $$GameTableTableOrderingComposer($db: db, $table: table), + $$MatchTableTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => - $$GameTableTableAnnotationComposer($db: db, $table: table), + $$MatchTableTableAnnotationComposer($db: db, $table: table), updateCompanionCallback: ({ Value id = const Value.absent(), @@ -2605,7 +2623,7 @@ class $$GameTableTableTableManager Value winnerId = const Value.absent(), Value createdAt = const Value.absent(), Value rowid = const Value.absent(), - }) => GameTableCompanion( + }) => MatchTableCompanion( id: id, name: name, winnerId: winnerId, @@ -2619,7 +2637,7 @@ class $$GameTableTableTableManager Value winnerId = const Value.absent(), required DateTime createdAt, Value rowid = const Value.absent(), - }) => GameTableCompanion.insert( + }) => MatchTableCompanion.insert( id: id, name: name, winnerId: winnerId, @@ -2630,60 +2648,60 @@ class $$GameTableTableTableManager .map( (e) => ( e.readTable(table), - $$GameTableTableReferences(db, table, e), + $$MatchTableTableReferences(db, table, e), ), ) .toList(), prefetchHooksCallback: - ({playerGameTableRefs = false, groupGameTableRefs = false}) { + ({playerMatchTableRefs = false, groupMatchTableRefs = false}) { return PrefetchHooks( db: db, explicitlyWatchedTables: [ - if (playerGameTableRefs) db.playerGameTable, - if (groupGameTableRefs) db.groupGameTable, + if (playerMatchTableRefs) db.playerMatchTable, + if (groupMatchTableRefs) db.groupMatchTable, ], addJoins: null, getPrefetchedDataCallback: (items) async { return [ - if (playerGameTableRefs) + if (playerMatchTableRefs) await $_getPrefetchedData< - GameTableData, - $GameTableTable, - PlayerGameTableData + MatchTableData, + $MatchTableTable, + PlayerMatchTableData >( currentTable: table, - referencedTable: $$GameTableTableReferences - ._playerGameTableRefsTable(db), + referencedTable: $$MatchTableTableReferences + ._playerMatchTableRefsTable(db), managerFromTypedResult: (p0) => - $$GameTableTableReferences( + $$MatchTableTableReferences( db, table, p0, - ).playerGameTableRefs, + ).playerMatchTableRefs, referencedItemsForCurrentItem: (item, referencedItems) => referencedItems.where( - (e) => e.gameId == item.id, + (e) => e.matchId == item.id, ), typedResults: items, ), - if (groupGameTableRefs) + if (groupMatchTableRefs) await $_getPrefetchedData< - GameTableData, - $GameTableTable, - GroupGameTableData + MatchTableData, + $MatchTableTable, + GroupMatchTableData >( currentTable: table, - referencedTable: $$GameTableTableReferences - ._groupGameTableRefsTable(db), + referencedTable: $$MatchTableTableReferences + ._groupMatchTableRefsTable(db), managerFromTypedResult: (p0) => - $$GameTableTableReferences( + $$MatchTableTableReferences( db, table, p0, - ).groupGameTableRefs, + ).groupMatchTableRefs, referencedItemsForCurrentItem: (item, referencedItems) => referencedItems.where( - (e) => e.gameId == item.id, + (e) => e.matchId == item.id, ), typedResults: items, ), @@ -2695,21 +2713,21 @@ class $$GameTableTableTableManager ); } -typedef $$GameTableTableProcessedTableManager = +typedef $$MatchTableTableProcessedTableManager = ProcessedTableManager< _$AppDatabase, - $GameTableTable, - GameTableData, - $$GameTableTableFilterComposer, - $$GameTableTableOrderingComposer, - $$GameTableTableAnnotationComposer, - $$GameTableTableCreateCompanionBuilder, - $$GameTableTableUpdateCompanionBuilder, - (GameTableData, $$GameTableTableReferences), - GameTableData, + $MatchTableTable, + MatchTableData, + $$MatchTableTableFilterComposer, + $$MatchTableTableOrderingComposer, + $$MatchTableTableAnnotationComposer, + $$MatchTableTableCreateCompanionBuilder, + $$MatchTableTableUpdateCompanionBuilder, + (MatchTableData, $$MatchTableTableReferences), + MatchTableData, PrefetchHooks Function({ - bool playerGameTableRefs, - bool groupGameTableRefs, + bool playerMatchTableRefs, + bool groupMatchTableRefs, }) >; typedef $$PlayerGroupTableTableCreateCompanionBuilder = @@ -3077,27 +3095,27 @@ typedef $$PlayerGroupTableTableProcessedTableManager = PlayerGroupTableData, PrefetchHooks Function({bool playerId, bool groupId}) >; -typedef $$PlayerGameTableTableCreateCompanionBuilder = - PlayerGameTableCompanion Function({ +typedef $$PlayerMatchTableTableCreateCompanionBuilder = + PlayerMatchTableCompanion Function({ required String playerId, - required String gameId, + required String matchId, Value rowid, }); -typedef $$PlayerGameTableTableUpdateCompanionBuilder = - PlayerGameTableCompanion Function({ +typedef $$PlayerMatchTableTableUpdateCompanionBuilder = + PlayerMatchTableCompanion Function({ Value playerId, - Value gameId, + Value matchId, Value rowid, }); -final class $$PlayerGameTableTableReferences +final class $$PlayerMatchTableTableReferences extends BaseReferences< _$AppDatabase, - $PlayerGameTableTable, - PlayerGameTableData + $PlayerMatchTableTable, + PlayerMatchTableData > { - $$PlayerGameTableTableReferences( + $$PlayerMatchTableTableReferences( super.$_db, super.$_table, super.$_typedResult, @@ -3105,7 +3123,7 @@ final class $$PlayerGameTableTableReferences static $PlayerTableTable _playerIdTable(_$AppDatabase db) => db.playerTable.createAlias( - $_aliasNameGenerator(db.playerGameTable.playerId, db.playerTable.id), + $_aliasNameGenerator(db.playerMatchTable.playerId, db.playerTable.id), ); $$PlayerTableTableProcessedTableManager get playerId { @@ -3122,19 +3140,19 @@ final class $$PlayerGameTableTableReferences ); } - static $GameTableTable _gameIdTable(_$AppDatabase db) => - db.gameTable.createAlias( - $_aliasNameGenerator(db.playerGameTable.gameId, db.gameTable.id), + static $MatchTableTable _matchIdTable(_$AppDatabase db) => + db.matchTable.createAlias( + $_aliasNameGenerator(db.playerMatchTable.matchId, db.matchTable.id), ); - $$GameTableTableProcessedTableManager get gameId { - final $_column = $_itemColumn('game_id')!; + $$MatchTableTableProcessedTableManager get matchId { + final $_column = $_itemColumn('match_id')!; - final manager = $$GameTableTableTableManager( + final manager = $$MatchTableTableTableManager( $_db, - $_db.gameTable, + $_db.matchTable, ).filter((f) => f.id.sqlEquals($_column)); - final item = $_typedResult.readTableOrNull(_gameIdTable($_db)); + final item = $_typedResult.readTableOrNull(_matchIdTable($_db)); if (item == null) return manager; return ProcessedTableManager( manager.$state.copyWith(prefetchedData: [item]), @@ -3142,9 +3160,9 @@ final class $$PlayerGameTableTableReferences } } -class $$PlayerGameTableTableFilterComposer - extends Composer<_$AppDatabase, $PlayerGameTableTable> { - $$PlayerGameTableTableFilterComposer({ +class $$PlayerMatchTableTableFilterComposer + extends Composer<_$AppDatabase, $PlayerMatchTableTable> { + $$PlayerMatchTableTableFilterComposer({ required super.$db, required super.$table, super.joinBuilder, @@ -3174,20 +3192,20 @@ class $$PlayerGameTableTableFilterComposer return composer; } - $$GameTableTableFilterComposer get gameId { - final $$GameTableTableFilterComposer composer = $composerBuilder( + $$MatchTableTableFilterComposer get matchId { + final $$MatchTableTableFilterComposer composer = $composerBuilder( composer: this, - getCurrentColumn: (t) => t.gameId, - referencedTable: $db.gameTable, + getCurrentColumn: (t) => t.matchId, + referencedTable: $db.matchTable, getReferencedColumn: (t) => t.id, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$GameTableTableFilterComposer( + }) => $$MatchTableTableFilterComposer( $db: $db, - $table: $db.gameTable, + $table: $db.matchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -3198,9 +3216,9 @@ class $$PlayerGameTableTableFilterComposer } } -class $$PlayerGameTableTableOrderingComposer - extends Composer<_$AppDatabase, $PlayerGameTableTable> { - $$PlayerGameTableTableOrderingComposer({ +class $$PlayerMatchTableTableOrderingComposer + extends Composer<_$AppDatabase, $PlayerMatchTableTable> { + $$PlayerMatchTableTableOrderingComposer({ required super.$db, required super.$table, super.joinBuilder, @@ -3230,20 +3248,20 @@ class $$PlayerGameTableTableOrderingComposer return composer; } - $$GameTableTableOrderingComposer get gameId { - final $$GameTableTableOrderingComposer composer = $composerBuilder( + $$MatchTableTableOrderingComposer get matchId { + final $$MatchTableTableOrderingComposer composer = $composerBuilder( composer: this, - getCurrentColumn: (t) => t.gameId, - referencedTable: $db.gameTable, + getCurrentColumn: (t) => t.matchId, + referencedTable: $db.matchTable, getReferencedColumn: (t) => t.id, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$GameTableTableOrderingComposer( + }) => $$MatchTableTableOrderingComposer( $db: $db, - $table: $db.gameTable, + $table: $db.matchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -3254,9 +3272,9 @@ class $$PlayerGameTableTableOrderingComposer } } -class $$PlayerGameTableTableAnnotationComposer - extends Composer<_$AppDatabase, $PlayerGameTableTable> { - $$PlayerGameTableTableAnnotationComposer({ +class $$PlayerMatchTableTableAnnotationComposer + extends Composer<_$AppDatabase, $PlayerMatchTableTable> { + $$PlayerMatchTableTableAnnotationComposer({ required super.$db, required super.$table, super.joinBuilder, @@ -3286,20 +3304,20 @@ class $$PlayerGameTableTableAnnotationComposer return composer; } - $$GameTableTableAnnotationComposer get gameId { - final $$GameTableTableAnnotationComposer composer = $composerBuilder( + $$MatchTableTableAnnotationComposer get matchId { + final $$MatchTableTableAnnotationComposer composer = $composerBuilder( composer: this, - getCurrentColumn: (t) => t.gameId, - referencedTable: $db.gameTable, + getCurrentColumn: (t) => t.matchId, + referencedTable: $db.matchTable, getReferencedColumn: (t) => t.id, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$GameTableTableAnnotationComposer( + }) => $$MatchTableTableAnnotationComposer( $db: $db, - $table: $db.gameTable, + $table: $db.matchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -3310,63 +3328,63 @@ class $$PlayerGameTableTableAnnotationComposer } } -class $$PlayerGameTableTableTableManager +class $$PlayerMatchTableTableTableManager extends RootTableManager< _$AppDatabase, - $PlayerGameTableTable, - PlayerGameTableData, - $$PlayerGameTableTableFilterComposer, - $$PlayerGameTableTableOrderingComposer, - $$PlayerGameTableTableAnnotationComposer, - $$PlayerGameTableTableCreateCompanionBuilder, - $$PlayerGameTableTableUpdateCompanionBuilder, - (PlayerGameTableData, $$PlayerGameTableTableReferences), - PlayerGameTableData, - PrefetchHooks Function({bool playerId, bool gameId}) + $PlayerMatchTableTable, + PlayerMatchTableData, + $$PlayerMatchTableTableFilterComposer, + $$PlayerMatchTableTableOrderingComposer, + $$PlayerMatchTableTableAnnotationComposer, + $$PlayerMatchTableTableCreateCompanionBuilder, + $$PlayerMatchTableTableUpdateCompanionBuilder, + (PlayerMatchTableData, $$PlayerMatchTableTableReferences), + PlayerMatchTableData, + PrefetchHooks Function({bool playerId, bool matchId}) > { - $$PlayerGameTableTableTableManager( + $$PlayerMatchTableTableTableManager( _$AppDatabase db, - $PlayerGameTableTable table, + $PlayerMatchTableTable table, ) : super( TableManagerState( db: db, table: table, createFilteringComposer: () => - $$PlayerGameTableTableFilterComposer($db: db, $table: table), + $$PlayerMatchTableTableFilterComposer($db: db, $table: table), createOrderingComposer: () => - $$PlayerGameTableTableOrderingComposer($db: db, $table: table), + $$PlayerMatchTableTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => - $$PlayerGameTableTableAnnotationComposer($db: db, $table: table), + $$PlayerMatchTableTableAnnotationComposer($db: db, $table: table), updateCompanionCallback: ({ Value playerId = const Value.absent(), - Value gameId = const Value.absent(), + Value matchId = const Value.absent(), Value rowid = const Value.absent(), - }) => PlayerGameTableCompanion( + }) => PlayerMatchTableCompanion( playerId: playerId, - gameId: gameId, + matchId: matchId, rowid: rowid, ), createCompanionCallback: ({ required String playerId, - required String gameId, + required String matchId, Value rowid = const Value.absent(), - }) => PlayerGameTableCompanion.insert( + }) => PlayerMatchTableCompanion.insert( playerId: playerId, - gameId: gameId, + matchId: matchId, rowid: rowid, ), withReferenceMapper: (p0) => p0 .map( (e) => ( e.readTable(table), - $$PlayerGameTableTableReferences(db, table, e), + $$PlayerMatchTableTableReferences(db, table, e), ), ) .toList(), - prefetchHooksCallback: ({playerId = false, gameId = false}) { + prefetchHooksCallback: ({playerId = false, matchId = false}) { return PrefetchHooks( db: db, explicitlyWatchedTables: [], @@ -3392,26 +3410,26 @@ class $$PlayerGameTableTableTableManager currentTable: table, currentColumn: table.playerId, referencedTable: - $$PlayerGameTableTableReferences + $$PlayerMatchTableTableReferences ._playerIdTable(db), referencedColumn: - $$PlayerGameTableTableReferences + $$PlayerMatchTableTableReferences ._playerIdTable(db) .id, ) as T; } - if (gameId) { + if (matchId) { state = state.withJoin( currentTable: table, - currentColumn: table.gameId, + currentColumn: table.matchId, referencedTable: - $$PlayerGameTableTableReferences - ._gameIdTable(db), + $$PlayerMatchTableTableReferences + ._matchIdTable(db), referencedColumn: - $$PlayerGameTableTableReferences - ._gameIdTable(db) + $$PlayerMatchTableTableReferences + ._matchIdTable(db) .id, ) as T; @@ -3428,41 +3446,41 @@ class $$PlayerGameTableTableTableManager ); } -typedef $$PlayerGameTableTableProcessedTableManager = +typedef $$PlayerMatchTableTableProcessedTableManager = ProcessedTableManager< _$AppDatabase, - $PlayerGameTableTable, - PlayerGameTableData, - $$PlayerGameTableTableFilterComposer, - $$PlayerGameTableTableOrderingComposer, - $$PlayerGameTableTableAnnotationComposer, - $$PlayerGameTableTableCreateCompanionBuilder, - $$PlayerGameTableTableUpdateCompanionBuilder, - (PlayerGameTableData, $$PlayerGameTableTableReferences), - PlayerGameTableData, - PrefetchHooks Function({bool playerId, bool gameId}) + $PlayerMatchTableTable, + PlayerMatchTableData, + $$PlayerMatchTableTableFilterComposer, + $$PlayerMatchTableTableOrderingComposer, + $$PlayerMatchTableTableAnnotationComposer, + $$PlayerMatchTableTableCreateCompanionBuilder, + $$PlayerMatchTableTableUpdateCompanionBuilder, + (PlayerMatchTableData, $$PlayerMatchTableTableReferences), + PlayerMatchTableData, + PrefetchHooks Function({bool playerId, bool matchId}) >; -typedef $$GroupGameTableTableCreateCompanionBuilder = - GroupGameTableCompanion Function({ +typedef $$GroupMatchTableTableCreateCompanionBuilder = + GroupMatchTableCompanion Function({ required String groupId, - required String gameId, + required String matchId, Value rowid, }); -typedef $$GroupGameTableTableUpdateCompanionBuilder = - GroupGameTableCompanion Function({ +typedef $$GroupMatchTableTableUpdateCompanionBuilder = + GroupMatchTableCompanion Function({ Value groupId, - Value gameId, + Value matchId, Value rowid, }); -final class $$GroupGameTableTableReferences +final class $$GroupMatchTableTableReferences extends BaseReferences< _$AppDatabase, - $GroupGameTableTable, - GroupGameTableData + $GroupMatchTableTable, + GroupMatchTableData > { - $$GroupGameTableTableReferences( + $$GroupMatchTableTableReferences( super.$_db, super.$_table, super.$_typedResult, @@ -3470,7 +3488,7 @@ final class $$GroupGameTableTableReferences static $GroupTableTable _groupIdTable(_$AppDatabase db) => db.groupTable.createAlias( - $_aliasNameGenerator(db.groupGameTable.groupId, db.groupTable.id), + $_aliasNameGenerator(db.groupMatchTable.groupId, db.groupTable.id), ); $$GroupTableTableProcessedTableManager get groupId { @@ -3487,19 +3505,19 @@ final class $$GroupGameTableTableReferences ); } - static $GameTableTable _gameIdTable(_$AppDatabase db) => - db.gameTable.createAlias( - $_aliasNameGenerator(db.groupGameTable.gameId, db.gameTable.id), + static $MatchTableTable _matchIdTable(_$AppDatabase db) => + db.matchTable.createAlias( + $_aliasNameGenerator(db.groupMatchTable.matchId, db.matchTable.id), ); - $$GameTableTableProcessedTableManager get gameId { - final $_column = $_itemColumn('game_id')!; + $$MatchTableTableProcessedTableManager get matchId { + final $_column = $_itemColumn('match_id')!; - final manager = $$GameTableTableTableManager( + final manager = $$MatchTableTableTableManager( $_db, - $_db.gameTable, + $_db.matchTable, ).filter((f) => f.id.sqlEquals($_column)); - final item = $_typedResult.readTableOrNull(_gameIdTable($_db)); + final item = $_typedResult.readTableOrNull(_matchIdTable($_db)); if (item == null) return manager; return ProcessedTableManager( manager.$state.copyWith(prefetchedData: [item]), @@ -3507,9 +3525,9 @@ final class $$GroupGameTableTableReferences } } -class $$GroupGameTableTableFilterComposer - extends Composer<_$AppDatabase, $GroupGameTableTable> { - $$GroupGameTableTableFilterComposer({ +class $$GroupMatchTableTableFilterComposer + extends Composer<_$AppDatabase, $GroupMatchTableTable> { + $$GroupMatchTableTableFilterComposer({ required super.$db, required super.$table, super.joinBuilder, @@ -3539,20 +3557,20 @@ class $$GroupGameTableTableFilterComposer return composer; } - $$GameTableTableFilterComposer get gameId { - final $$GameTableTableFilterComposer composer = $composerBuilder( + $$MatchTableTableFilterComposer get matchId { + final $$MatchTableTableFilterComposer composer = $composerBuilder( composer: this, - getCurrentColumn: (t) => t.gameId, - referencedTable: $db.gameTable, + getCurrentColumn: (t) => t.matchId, + referencedTable: $db.matchTable, getReferencedColumn: (t) => t.id, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$GameTableTableFilterComposer( + }) => $$MatchTableTableFilterComposer( $db: $db, - $table: $db.gameTable, + $table: $db.matchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -3563,9 +3581,9 @@ class $$GroupGameTableTableFilterComposer } } -class $$GroupGameTableTableOrderingComposer - extends Composer<_$AppDatabase, $GroupGameTableTable> { - $$GroupGameTableTableOrderingComposer({ +class $$GroupMatchTableTableOrderingComposer + extends Composer<_$AppDatabase, $GroupMatchTableTable> { + $$GroupMatchTableTableOrderingComposer({ required super.$db, required super.$table, super.joinBuilder, @@ -3595,20 +3613,20 @@ class $$GroupGameTableTableOrderingComposer return composer; } - $$GameTableTableOrderingComposer get gameId { - final $$GameTableTableOrderingComposer composer = $composerBuilder( + $$MatchTableTableOrderingComposer get matchId { + final $$MatchTableTableOrderingComposer composer = $composerBuilder( composer: this, - getCurrentColumn: (t) => t.gameId, - referencedTable: $db.gameTable, + getCurrentColumn: (t) => t.matchId, + referencedTable: $db.matchTable, getReferencedColumn: (t) => t.id, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$GameTableTableOrderingComposer( + }) => $$MatchTableTableOrderingComposer( $db: $db, - $table: $db.gameTable, + $table: $db.matchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -3619,9 +3637,9 @@ class $$GroupGameTableTableOrderingComposer } } -class $$GroupGameTableTableAnnotationComposer - extends Composer<_$AppDatabase, $GroupGameTableTable> { - $$GroupGameTableTableAnnotationComposer({ +class $$GroupMatchTableTableAnnotationComposer + extends Composer<_$AppDatabase, $GroupMatchTableTable> { + $$GroupMatchTableTableAnnotationComposer({ required super.$db, required super.$table, super.joinBuilder, @@ -3651,20 +3669,20 @@ class $$GroupGameTableTableAnnotationComposer return composer; } - $$GameTableTableAnnotationComposer get gameId { - final $$GameTableTableAnnotationComposer composer = $composerBuilder( + $$MatchTableTableAnnotationComposer get matchId { + final $$MatchTableTableAnnotationComposer composer = $composerBuilder( composer: this, - getCurrentColumn: (t) => t.gameId, - referencedTable: $db.gameTable, + getCurrentColumn: (t) => t.matchId, + referencedTable: $db.matchTable, getReferencedColumn: (t) => t.id, builder: ( joinBuilder, { $addJoinBuilderToRootComposer, $removeJoinBuilderFromRootComposer, - }) => $$GameTableTableAnnotationComposer( + }) => $$MatchTableTableAnnotationComposer( $db: $db, - $table: $db.gameTable, + $table: $db.matchTable, $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, joinBuilder: joinBuilder, $removeJoinBuilderFromRootComposer: @@ -3675,63 +3693,63 @@ class $$GroupGameTableTableAnnotationComposer } } -class $$GroupGameTableTableTableManager +class $$GroupMatchTableTableTableManager extends RootTableManager< _$AppDatabase, - $GroupGameTableTable, - GroupGameTableData, - $$GroupGameTableTableFilterComposer, - $$GroupGameTableTableOrderingComposer, - $$GroupGameTableTableAnnotationComposer, - $$GroupGameTableTableCreateCompanionBuilder, - $$GroupGameTableTableUpdateCompanionBuilder, - (GroupGameTableData, $$GroupGameTableTableReferences), - GroupGameTableData, - PrefetchHooks Function({bool groupId, bool gameId}) + $GroupMatchTableTable, + GroupMatchTableData, + $$GroupMatchTableTableFilterComposer, + $$GroupMatchTableTableOrderingComposer, + $$GroupMatchTableTableAnnotationComposer, + $$GroupMatchTableTableCreateCompanionBuilder, + $$GroupMatchTableTableUpdateCompanionBuilder, + (GroupMatchTableData, $$GroupMatchTableTableReferences), + GroupMatchTableData, + PrefetchHooks Function({bool groupId, bool matchId}) > { - $$GroupGameTableTableTableManager( + $$GroupMatchTableTableTableManager( _$AppDatabase db, - $GroupGameTableTable table, + $GroupMatchTableTable table, ) : super( TableManagerState( db: db, table: table, createFilteringComposer: () => - $$GroupGameTableTableFilterComposer($db: db, $table: table), + $$GroupMatchTableTableFilterComposer($db: db, $table: table), createOrderingComposer: () => - $$GroupGameTableTableOrderingComposer($db: db, $table: table), + $$GroupMatchTableTableOrderingComposer($db: db, $table: table), createComputedFieldComposer: () => - $$GroupGameTableTableAnnotationComposer($db: db, $table: table), + $$GroupMatchTableTableAnnotationComposer($db: db, $table: table), updateCompanionCallback: ({ Value groupId = const Value.absent(), - Value gameId = const Value.absent(), + Value matchId = const Value.absent(), Value rowid = const Value.absent(), - }) => GroupGameTableCompanion( + }) => GroupMatchTableCompanion( groupId: groupId, - gameId: gameId, + matchId: matchId, rowid: rowid, ), createCompanionCallback: ({ required String groupId, - required String gameId, + required String matchId, Value rowid = const Value.absent(), - }) => GroupGameTableCompanion.insert( + }) => GroupMatchTableCompanion.insert( groupId: groupId, - gameId: gameId, + matchId: matchId, rowid: rowid, ), withReferenceMapper: (p0) => p0 .map( (e) => ( e.readTable(table), - $$GroupGameTableTableReferences(db, table, e), + $$GroupMatchTableTableReferences(db, table, e), ), ) .toList(), - prefetchHooksCallback: ({groupId = false, gameId = false}) { + prefetchHooksCallback: ({groupId = false, matchId = false}) { return PrefetchHooks( db: db, explicitlyWatchedTables: [], @@ -3756,25 +3774,27 @@ class $$GroupGameTableTableTableManager state.withJoin( currentTable: table, currentColumn: table.groupId, - referencedTable: $$GroupGameTableTableReferences - ._groupIdTable(db), + referencedTable: + $$GroupMatchTableTableReferences + ._groupIdTable(db), referencedColumn: - $$GroupGameTableTableReferences + $$GroupMatchTableTableReferences ._groupIdTable(db) .id, ) as T; } - if (gameId) { + if (matchId) { state = state.withJoin( currentTable: table, - currentColumn: table.gameId, - referencedTable: $$GroupGameTableTableReferences - ._gameIdTable(db), + currentColumn: table.matchId, + referencedTable: + $$GroupMatchTableTableReferences + ._matchIdTable(db), referencedColumn: - $$GroupGameTableTableReferences - ._gameIdTable(db) + $$GroupMatchTableTableReferences + ._matchIdTable(db) .id, ) as T; @@ -3791,19 +3811,19 @@ class $$GroupGameTableTableTableManager ); } -typedef $$GroupGameTableTableProcessedTableManager = +typedef $$GroupMatchTableTableProcessedTableManager = ProcessedTableManager< _$AppDatabase, - $GroupGameTableTable, - GroupGameTableData, - $$GroupGameTableTableFilterComposer, - $$GroupGameTableTableOrderingComposer, - $$GroupGameTableTableAnnotationComposer, - $$GroupGameTableTableCreateCompanionBuilder, - $$GroupGameTableTableUpdateCompanionBuilder, - (GroupGameTableData, $$GroupGameTableTableReferences), - GroupGameTableData, - PrefetchHooks Function({bool groupId, bool gameId}) + $GroupMatchTableTable, + GroupMatchTableData, + $$GroupMatchTableTableFilterComposer, + $$GroupMatchTableTableOrderingComposer, + $$GroupMatchTableTableAnnotationComposer, + $$GroupMatchTableTableCreateCompanionBuilder, + $$GroupMatchTableTableUpdateCompanionBuilder, + (GroupMatchTableData, $$GroupMatchTableTableReferences), + GroupMatchTableData, + PrefetchHooks Function({bool groupId, bool matchId}) >; class $AppDatabaseManager { @@ -3813,12 +3833,12 @@ class $AppDatabaseManager { $$PlayerTableTableTableManager(_db, _db.playerTable); $$GroupTableTableTableManager get groupTable => $$GroupTableTableTableManager(_db, _db.groupTable); - $$GameTableTableTableManager get gameTable => - $$GameTableTableTableManager(_db, _db.gameTable); + $$MatchTableTableTableManager get matchTable => + $$MatchTableTableTableManager(_db, _db.matchTable); $$PlayerGroupTableTableTableManager get playerGroupTable => $$PlayerGroupTableTableTableManager(_db, _db.playerGroupTable); - $$PlayerGameTableTableTableManager get playerGameTable => - $$PlayerGameTableTableTableManager(_db, _db.playerGameTable); - $$GroupGameTableTableTableManager get groupGameTable => - $$GroupGameTableTableTableManager(_db, _db.groupGameTable); + $$PlayerMatchTableTableTableManager get playerMatchTable => + $$PlayerMatchTableTableTableManager(_db, _db.playerMatchTable); + $$GroupMatchTableTableTableManager get groupMatchTable => + $$GroupMatchTableTableTableManager(_db, _db.groupMatchTable); } diff --git a/lib/data/db/tables/group_game_table.dart b/lib/data/db/tables/group_game_table.dart deleted file mode 100644 index a16672e..0000000 --- a/lib/data/db/tables/group_game_table.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/tables/game_table.dart'; -import 'package:game_tracker/data/db/tables/group_table.dart'; - -class GroupGameTable extends Table { - TextColumn get groupId => - text().references(GroupTable, #id, onDelete: KeyAction.cascade)(); - TextColumn get gameId => - text().references(GameTable, #id, onDelete: KeyAction.cascade)(); - - @override - Set> get primaryKey => {groupId, gameId}; -} diff --git a/lib/data/db/tables/group_match_table.dart b/lib/data/db/tables/group_match_table.dart new file mode 100644 index 0000000..3f77dcb --- /dev/null +++ b/lib/data/db/tables/group_match_table.dart @@ -0,0 +1,13 @@ +import 'package:drift/drift.dart'; +import 'package:game_tracker/data/db/tables/group_table.dart'; +import 'package:game_tracker/data/db/tables/match_table.dart'; + +class GroupMatchTable extends Table { + TextColumn get groupId => + text().references(GroupTable, #id, onDelete: KeyAction.cascade)(); + TextColumn get matchId => + text().references(MatchTable, #id, onDelete: KeyAction.cascade)(); + + @override + Set> get primaryKey => {groupId, matchId}; +} diff --git a/lib/data/db/tables/game_table.dart b/lib/data/db/tables/match_table.dart similarity index 88% rename from lib/data/db/tables/game_table.dart rename to lib/data/db/tables/match_table.dart index 1a37a73..96aff2a 100644 --- a/lib/data/db/tables/game_table.dart +++ b/lib/data/db/tables/match_table.dart @@ -1,6 +1,6 @@ import 'package:drift/drift.dart'; -class GameTable extends Table { +class MatchTable extends Table { TextColumn get id => text()(); TextColumn get name => text()(); late final winnerId = text().nullable()(); diff --git a/lib/data/db/tables/player_game_table.dart b/lib/data/db/tables/player_game_table.dart deleted file mode 100644 index 74c36fe..0000000 --- a/lib/data/db/tables/player_game_table.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:game_tracker/data/db/tables/game_table.dart'; -import 'package:game_tracker/data/db/tables/player_table.dart'; - -class PlayerGameTable extends Table { - TextColumn get playerId => - text().references(PlayerTable, #id, onDelete: KeyAction.cascade)(); - TextColumn get gameId => - text().references(GameTable, #id, onDelete: KeyAction.cascade)(); - - @override - Set> get primaryKey => {playerId, gameId}; -} diff --git a/lib/data/db/tables/player_match_table.dart b/lib/data/db/tables/player_match_table.dart new file mode 100644 index 0000000..e155cd5 --- /dev/null +++ b/lib/data/db/tables/player_match_table.dart @@ -0,0 +1,13 @@ +import 'package:drift/drift.dart'; +import 'package:game_tracker/data/db/tables/match_table.dart'; +import 'package:game_tracker/data/db/tables/player_table.dart'; + +class PlayerMatchTable extends Table { + TextColumn get playerId => + text().references(PlayerTable, #id, onDelete: KeyAction.cascade)(); + TextColumn get matchId => + text().references(MatchTable, #id, onDelete: KeyAction.cascade)(); + + @override + Set> get primaryKey => {playerId, matchId}; +} diff --git a/lib/data/dto/game.dart b/lib/data/dto/match.dart similarity index 80% rename from lib/data/dto/game.dart rename to lib/data/dto/match.dart index 48ef902..9570f66 100644 --- a/lib/data/dto/game.dart +++ b/lib/data/dto/match.dart @@ -3,15 +3,15 @@ import 'package:game_tracker/data/dto/group.dart'; import 'package:game_tracker/data/dto/player.dart'; import 'package:uuid/uuid.dart'; -class Game { +class Match { final String id; final DateTime createdAt; final String name; final List? players; final Group? group; - final Player? winner; + Player? winner; - Game({ + Match({ String? id, DateTime? createdAt, required this.name, @@ -23,11 +23,11 @@ class Game { @override String toString() { - return 'Game{\n\tid: $id,\n\tname: $name,\n\tplayers: $players,\n\tgroup: $group,\n\twinner: $winner\n}'; + return 'Match{\n\tid: $id,\n\tname: $name,\n\tplayers: $players,\n\tgroup: $group,\n\twinner: $winner\n}'; } - /// Creates a Game instance from a JSON object. - Game.fromJson(Map json) + /// Creates a Match instance from a JSON object. + Match.fromJson(Map json) : id = json['id'], name = json['name'], createdAt = DateTime.parse(json['createdAt']), @@ -39,7 +39,7 @@ class Game { group = json['group'] != null ? Group.fromJson(json['group']) : null, winner = json['winner'] != null ? Player.fromJson(json['winner']) : null; - /// Converts the Game instance to a JSON object. + /// Converts the Match instance to a JSON object. Map toJson() => { 'id': id, 'createdAt': createdAt.toIso8601String(), diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb new file mode 100644 index 0000000..6aee6ee --- /dev/null +++ b/lib/l10n/arb/app_de.arb @@ -0,0 +1,90 @@ +{ + "@@locale": "de", + "all_players": "Alle Spieler:innen", + "all_players_selected": "Alle Spieler:innen ausgewählt", + "amount_of_matches": "Anzahl der Spiele", + "app_name": "Game Tracker", + "cancel": "Abbrechen", + "choose_game": "Spielvorlage wählen", + "choose_group": "Gruppe wählen", + "choose_ruleset": "Regelwerk wählen", + "could_not_add_player": "Spieler:in {playerName} konnte nicht hinzugefügt werden", + "create_group": "Gruppe erstellen", + "create_match": "Spiel erstellen", + "create_new_group": "Neue Gruppe erstellen", + "create_new_match": "Neues Spiel erstellen", + "data": "Daten", + "data_successfully_deleted": "Daten erfolgreich gelöscht", + "data_successfully_exported": "Daten erfolgreich exportiert", + "data_successfully_imported": "Daten erfolgreich importiert", + "days_ago": "vor {count} Tagen", + "delete": "Löschen", + "delete_all_data": "Alle Daten löschen", + "error_creating_group": "Fehler beim Erstellen der Gruppe, bitte erneut versuchen", + "error_reading_file": "Fehler beim Lesen der Datei", + "export_canceled": "Export abgebrochen", + "export_data": "Daten exportieren", + "format_exception": "Formatfehler (siehe Konsole)", + "game": "Spielvorlage", + "game_name": "Spielvorlagenname", + "group": "Gruppe", + "group_name": "Gruppenname", + "groups": "Gruppen", + "home": "Startseite", + "import_canceled": "Import abgebrochen", + "import_data": "Daten importieren", + "info": "Info", + "invalid_schema": "Ungültiges Schema", + "least_points": "Niedrigste Punkte", + "legal": "Rechtliches", + "legal_notice": "Impressum", + "licenses": "Lizenzen", + "match_in_progress": "Spiel läuft...", + "match_name": "Spieltitel", + "matches": "Spiele", + "most_points": "Höchste Punkte", + "no_data_available": "Keine Daten verfügbar", + "no_groups_created_yet": "Noch keine Gruppen erstellt", + "no_licenses_found": "Keine Lizenzen gefunden", + "no_license_text_available": "Kein Lizenztext verfügbar", + "no_matches_created_yet": "Noch keine Spiele erstellt", + "no_players_created_yet": "Noch keine Spieler:in erstellt", + "no_players_found_with_that_name": "Keine Spieler:in mit diesem Namen gefunden", + "no_players_selected": "Keine Spieler:innen ausgewählt", + "no_recent_matches_available": "Keine letzten Spiele verfügbar", + "no_second_match_available": "Kein zweites Spiel verfügbar", + "no_statistics_available": "Keine Statistiken verfügbar", + "none": "Kein", + "none_group": "Keine", + "not_available": "Nicht verfügbar", + "player_name": "Spieler:innenname", + "players": "Spieler:innen", + "players_count": "{count} Spieler", + "privacy_policy": "Datenschutzerklärung", + "quick_create": "Schnellzugriff", + "recent_matches": "Letzte Spiele", + "ruleset": "Regelwerk", + "ruleset_least_points": "Umgekehrte Wertung: Der/die Spieler:in mit den wenigsten Punkten gewinnt.", + "ruleset_most_points": "Traditionelles Regelwerk: Der/die Spieler:in mit den meisten Punkten gewinnt.", + "ruleset_single_loser": "Genau ein:e Verlierer:in wird bestimmt; der letzte Platz erhält die Strafe oder Konsequenz.", + "ruleset_single_winner": "Genau ein:e Gewinner:in wird gewählt; Unentschieden werden durch einen vordefinierten Tie-Breaker aufgelöst.", + "search_for_groups": "Nach Gruppen suchen", + "search_for_players": "Nach Spieler:innen suchen", + "select_winner": "Gewinner:in wählen:", + "selected_players": "Ausgewählte Spieler:innen", + "settings": "Einstellungen", + "single_loser": "Ein:e Verlierer:in", + "single_winner": "Ein:e Gewinner:in", + "statistics": "Statistiken", + "stats": "Statistiken", + "successfully_added_player": "Spieler:in {playerName} erfolgreich hinzugefügt", + "there_is_no_group_matching_your_search": "Es gibt keine Gruppe, die deiner Suche entspricht", + "this_cannot_be_undone": "Dies kann nicht rückgängig gemacht werden", + "today_at": "Heute um", + "undo": "Rückgängig", + "unknown_exception": "Unbekannter Fehler (siehe Konsole)", + "winner": "Gewinner:in", + "winrate": "Siegquote", + "wins": "Siege", + "yesterday_at": "Gestern um" +} \ No newline at end of file diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb new file mode 100644 index 0000000..c311050 --- /dev/null +++ b/lib/l10n/arb/app_en.arb @@ -0,0 +1,367 @@ +{ + "@@locale": "en", + "@all_players": { + "description": "Label for all players list" + }, + "@all_players_selected": { + "description": "Message when all players are added to selection" + }, + "@amount_of_matches": { + "description": "Label for amount of matches statistic" + }, + "@app_name": { + "description": "The name of the App" + }, + "@cancel": { + "description": "Cancel button text" + }, + "@choose_game": { + "description": "Label for choosing a game" + }, + "@choose_group": { + "description": "Label for choosing a group" + }, + "@choose_ruleset": { + "description": "Label for choosing a ruleset" + }, + "@could_not_add_player": { + "description": "Error message when adding a player fails" + }, + "@create_group": { + "description": "Button text to create a group" + }, + "@create_match": { + "description": "Button text to create a match" + }, + "@create_new_group": { + "description": "Button text to create a new group" + }, + "@create_new_match": { + "description": "Button text to create a new match" + }, + "@data": { + "description": "Data label" + }, + "@data_successfully_deleted": { + "description": "Success message after deleting data" + }, + "@data_successfully_exported": { + "description": "Success message after exporting data" + }, + "@data_successfully_imported": { + "description": "Success message after importing data" + }, + "@days_ago": { + "description": "Date format for days ago", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "@delete": { + "description": "Delete button text" + }, + "@delete_all_data": { + "description": "Confirmation dialog for deleting all data" + }, + "@error_creating_group": { + "description": "Error message when group creation fails" + }, + "@error_reading_file": { + "description": "Error message when file cannot be read" + }, + "@export_canceled": { + "description": "Message when export is canceled" + }, + "@export_data": { + "description": "Export data menu item" + }, + "@format_exception": { + "description": "Error message for format exceptions" + }, + "@game": { + "description": "Game label" + }, + "@game_name": { + "description": "Placeholder for game name search" + }, + "@group": { + "description": "Group label" + }, + "@group_name": { + "description": "Placeholder for group name input" + }, + "@groups": { + "description": "Label for groups" + }, + "@home": { + "description": "Home tab label" + }, + "@import_canceled": { + "description": "Message when import is canceled" + }, + "@import_data": { + "description": "Import data menu item" + }, + "@info": { + "description": "Info label" + }, + "@invalid_schema": { + "description": "Error message for invalid schema" + }, + "@least_points": { + "description": "Title for least points ruleset" + }, + "@legal": { + "description": "Legal section header" + }, + "@legal_notice": { + "description": "Legal notice menu item" + }, + "@licenses": { + "description": "Licenses menu item" + }, + "@match_in_progress": { + "description": "Message when match is in progress" + }, + "@match_name": { + "description": "Placeholder for match name input" + }, + "@matches": { + "description": "Label for matches" + }, + "@most_points": { + "description": "Title for most points ruleset" + }, + "@no_data_available": { + "description": "Message when no data in the statistic tiles is given" + }, + "@no_groups_created_yet": { + "description": "Message when no groups exist" + }, + "@no_licenses_found": { + "description": "Message when no licenses are found" + }, + "@no_license_text_available": { + "description": "Message when no license text is available" + }, + "@no_matches_created_yet": { + "description": "Message when no matches exist" + }, + "@no_players_created_yet": { + "description": "Message when no players exist" + }, + "@no_players_found_with_that_name": { + "description": "Message when search returns no results" + }, + "@no_players_selected": { + "description": "Message when no players are selected" + }, + "@no_recent_matches_available": { + "description": "Message when no recent matches exist" + }, + "@no_second_match_available": { + "description": "Message when no second match exists" + }, + "@no_statistics_available": { + "description": "Message when no statistics are available, because no matches were played yet" + }, + "@none": { + "description": "None option label" + }, + "@none_group": { + "description": "None group option label" + }, + "@not_available": { + "description": "Abbreviation for not available" + }, + "@player_name": { + "description": "Placeholder for player name input" + }, + "@players": { + "description": "Players label" + }, + "@players_count": { + "description": "Shows the number of players", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "@privacy_policy": { + "description": "Privacy policy menu item" + }, + "@quick_create": { + "description": "Title for quick create section" + }, + "@recent_matches": { + "description": "Title for recent matches section" + }, + "@ruleset": { + "description": "Ruleset label" + }, + "@ruleset_least_points": { + "description": "Description for least points ruleset" + }, + "@ruleset_most_points": { + "description": "Description for most points ruleset" + }, + "@ruleset_single_loser": { + "description": "Description for single loser ruleset" + }, + "@ruleset_single_winner": { + "description": "Description for single winner ruleset" + }, + "@search_for_groups": { + "description": "Hint text for group search input field" + }, + "@search_for_players": { + "description": "Hint text for player search input field" + }, + "@select_winner": { + "description": "Label to select the winner" + }, + "@selected_players": { + "description": "Shows the number of selected players" + }, + "@settings": { + "description": "Label for the App Settings" + }, + "@single_loser": { + "description": "Title for single loser ruleset" + }, + "@single_winner": { + "description": "Title for single winner ruleset" + }, + "@statistics": { + "description": "Statistics tab label" + }, + "@stats": { + "description": "Stats tab label (short)" + }, + "@successfully_added_player": { + "description": "Success message when adding a player", + "placeholders": { + "playerName": { + "type": "String", + "example": "John" + } + } + }, + "@there_is_no_group_matching_your_search": { + "description": "Message when search returns no groups" + }, + "@this_cannot_be_undone": { + "description": "Warning message for irreversible actions" + }, + "@today_at": { + "description": "Date format for today" + }, + "@undo": { + "description": "Undo button text" + }, + "@unknown_exception": { + "description": "Error message for unknown exceptions" + }, + "@winner": { + "description": "Winner label" + }, + "@winrate": { + "description": "Label for winrate statistic" + }, + "@wins": { + "description": "Label for wins statistic" + }, + "@yesterday_at": { + "description": "Date format for yesterday" + }, + "all_players": "All players", + "all_players_selected": "All players selected", + "amount_of_matches": "Amount of Matches", + "app_name": "Game Tracker", + "cancel": "Cancel", + "choose_game": "Choose Game", + "choose_group": "Choose Group", + "choose_ruleset": "Choose Ruleset", + "could_not_add_player": "Could not add player", + "create_group": "Create Group", + "create_match": "Create match", + "create_new_group": "Create new group", + "create_new_match": "Create new match", + "data": "Data", + "data_successfully_deleted": "Data successfully deleted", + "data_successfully_exported": "Data successfully exported", + "data_successfully_imported": "Data successfully imported", + "days_ago": "{count} days ago", + "delete": "Delete", + "delete_all_data": "Delete all data", + "error_creating_group": "Error while creating group, please try again", + "error_reading_file": "Error reading file", + "export_canceled": "Export canceled", + "export_data": "Export data", + "format_exception": "Format Exception (see console)", + "game": "Game", + "game_name": "Game Name", + "group": "Group", + "group_name": "Group name", + "groups": "Groups", + "home": "Home", + "import_canceled": "Import canceled", + "import_data": "Import data", + "info": "Info", + "invalid_schema": "Invalid Schema", + "least_points": "Least Points", + "legal": "Legal", + "legal_notice": "Legal Notice", + "licenses": "Licenses", + "match_in_progress": "Match in progress...", + "match_name": "Match name", + "matches": "Matches", + "most_points": "Most Points", + "no_data_available": "No data available", + "no_groups_created_yet": "No groups created yet", + "no_licenses_found": "No licenses found", + "no_license_text_available": "No license text available", + "no_matches_created_yet": "No matches created yet", + "no_players_created_yet": "No players created yet", + "no_players_found_with_that_name": "No players found with that name", + "no_players_selected": "No players selected", + "no_recent_matches_available": "No recent matches available", + "no_second_match_available": "No second match available", + "no_statistics_available": "No statistics available", + "none": "None", + "none_group": "None", + "not_available": "Not available", + "player_name": "Player name", + "players": "Players", + "players_count": "{count} Players", + "privacy_policy": "Privacy Policy", + "quick_create": "Quick Create", + "recent_matches": "Recent Matches", + "ruleset": "Ruleset", + "ruleset_least_points": "Inverse scoring: the player with the fewest points wins.", + "ruleset_most_points": "Traditional ruleset: the player with the most points wins.", + "ruleset_single_loser": "Exactly one loser is determined; last place receives the penalty or consequence.", + "ruleset_single_winner": "Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.", + "search_for_groups": "Search for groups", + "search_for_players": "Search for players", + "select_winner": "Select Winner:", + "selected_players": "Selected players", + "settings": "Settings", + "single_loser": "Single Loser", + "single_winner": "Single Winner", + "statistics": "Statistics", + "stats": "Stats", + "successfully_added_player": "Successfully added player {playerName}", + "there_is_no_group_matching_your_search": "There is no group matching your search", + "this_cannot_be_undone": "This can't be undone", + "today_at": "Today at", + "undo": "Undo", + "unknown_exception": "Unknown Exception (see console)", + "winner": "Winner", + "winrate": "Winrate", + "wins": "Wins", + "yesterday_at": "Yesterday at" +} \ No newline at end of file diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart new file mode 100644 index 0000000..399dc85 --- /dev/null +++ b/lib/l10n/generated/app_localizations.dart @@ -0,0 +1,656 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:intl/intl.dart' as intl; + +import 'app_localizations_de.dart'; +import 'app_localizations_en.dart'; + +// ignore_for_file: type=lint + +/// Callers can lookup localized strings with an instance of AppLocalizations +/// returned by `AppLocalizations.of(context)`. +/// +/// Applications need to include `AppLocalizations.delegate()` in their app's +/// `localizationDelegates` list, and the locales they support in the app's +/// `supportedLocales` list. For example: +/// +/// ```dart +/// import 'generated/app_localizations.dart'; +/// +/// return MaterialApp( +/// localizationsDelegates: AppLocalizations.localizationsDelegates, +/// supportedLocales: AppLocalizations.supportedLocales, +/// home: MyApplicationHome(), +/// ); +/// ``` +/// +/// ## Update pubspec.yaml +/// +/// Please make sure to update your pubspec.yaml to include the following +/// packages: +/// +/// ```yaml +/// dependencies: +/// # Internationalization support. +/// flutter_localizations: +/// sdk: flutter +/// intl: any # Use the pinned version from flutter_localizations +/// +/// # Rest of dependencies +/// ``` +/// +/// ## iOS Applications +/// +/// iOS applications define key application metadata, including supported +/// locales, in an Info.plist file that is built into the application bundle. +/// To configure the locales supported by your app, you’ll need to edit this +/// file. +/// +/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file. +/// Then, in the Project Navigator, open the Info.plist file under the Runner +/// project’s Runner folder. +/// +/// Next, select the Information Property List item, select Add Item from the +/// Editor menu, then select Localizations from the pop-up menu. +/// +/// Select and expand the newly-created Localizations item then, for each +/// locale your application supports, add a new item and select the locale +/// you wish to add from the pop-up menu in the Value field. This list should +/// be consistent with the languages listed in the AppLocalizations.supportedLocales +/// property. +abstract class AppLocalizations { + AppLocalizations(String locale) + : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + + final String localeName; + + static AppLocalizations of(BuildContext context) { + return Localizations.of(context, AppLocalizations)!; + } + + static const LocalizationsDelegate delegate = + _AppLocalizationsDelegate(); + + /// A list of this localizations delegate along with the default localizations + /// delegates. + /// + /// Returns a list of localizations delegates containing this delegate along with + /// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, + /// and GlobalWidgetsLocalizations.delegate. + /// + /// Additional delegates can be added by appending to this list in + /// MaterialApp. This list does not have to be used at all if a custom list + /// of delegates is preferred or required. + static const List> localizationsDelegates = + >[ + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; + + /// A list of this localizations delegate's supported locales. + static const List supportedLocales = [ + Locale('de'), + Locale('en'), + ]; + + /// Label for all players list + /// + /// In en, this message translates to: + /// **'All players'** + String get all_players; + + /// Message when all players are added to selection + /// + /// In en, this message translates to: + /// **'All players selected'** + String get all_players_selected; + + /// Label for amount of matches statistic + /// + /// In en, this message translates to: + /// **'Amount of Matches'** + String get amount_of_matches; + + /// The name of the App + /// + /// In en, this message translates to: + /// **'Game Tracker'** + String get app_name; + + /// Cancel button text + /// + /// In en, this message translates to: + /// **'Cancel'** + String get cancel; + + /// Label for choosing a game + /// + /// In en, this message translates to: + /// **'Choose Game'** + String get choose_game; + + /// Label for choosing a group + /// + /// In en, this message translates to: + /// **'Choose Group'** + String get choose_group; + + /// Label for choosing a ruleset + /// + /// In en, this message translates to: + /// **'Choose Ruleset'** + String get choose_ruleset; + + /// Error message when adding a player fails + /// + /// In en, this message translates to: + /// **'Could not add player'** + String could_not_add_player(Object playerName); + + /// Button text to create a group + /// + /// In en, this message translates to: + /// **'Create Group'** + String get create_group; + + /// Button text to create a match + /// + /// In en, this message translates to: + /// **'Create match'** + String get create_match; + + /// Button text to create a new group + /// + /// In en, this message translates to: + /// **'Create new group'** + String get create_new_group; + + /// Button text to create a new match + /// + /// In en, this message translates to: + /// **'Create new match'** + String get create_new_match; + + /// Data label + /// + /// In en, this message translates to: + /// **'Data'** + String get data; + + /// Success message after deleting data + /// + /// In en, this message translates to: + /// **'Data successfully deleted'** + String get data_successfully_deleted; + + /// Success message after exporting data + /// + /// In en, this message translates to: + /// **'Data successfully exported'** + String get data_successfully_exported; + + /// Success message after importing data + /// + /// In en, this message translates to: + /// **'Data successfully imported'** + String get data_successfully_imported; + + /// Date format for days ago + /// + /// In en, this message translates to: + /// **'{count} days ago'** + String days_ago(int count); + + /// Delete button text + /// + /// In en, this message translates to: + /// **'Delete'** + String get delete; + + /// Confirmation dialog for deleting all data + /// + /// In en, this message translates to: + /// **'Delete all data'** + String get delete_all_data; + + /// Error message when group creation fails + /// + /// In en, this message translates to: + /// **'Error while creating group, please try again'** + String get error_creating_group; + + /// Error message when file cannot be read + /// + /// In en, this message translates to: + /// **'Error reading file'** + String get error_reading_file; + + /// Message when export is canceled + /// + /// In en, this message translates to: + /// **'Export canceled'** + String get export_canceled; + + /// Export data menu item + /// + /// In en, this message translates to: + /// **'Export data'** + String get export_data; + + /// Error message for format exceptions + /// + /// In en, this message translates to: + /// **'Format Exception (see console)'** + String get format_exception; + + /// Game label + /// + /// In en, this message translates to: + /// **'Game'** + String get game; + + /// Placeholder for game name search + /// + /// In en, this message translates to: + /// **'Game Name'** + String get game_name; + + /// Group label + /// + /// In en, this message translates to: + /// **'Group'** + String get group; + + /// Placeholder for group name input + /// + /// In en, this message translates to: + /// **'Group name'** + String get group_name; + + /// Label for groups + /// + /// In en, this message translates to: + /// **'Groups'** + String get groups; + + /// Home tab label + /// + /// In en, this message translates to: + /// **'Home'** + String get home; + + /// Message when import is canceled + /// + /// In en, this message translates to: + /// **'Import canceled'** + String get import_canceled; + + /// Import data menu item + /// + /// In en, this message translates to: + /// **'Import data'** + String get import_data; + + /// Info label + /// + /// In en, this message translates to: + /// **'Info'** + String get info; + + /// Error message for invalid schema + /// + /// In en, this message translates to: + /// **'Invalid Schema'** + String get invalid_schema; + + /// Title for least points ruleset + /// + /// In en, this message translates to: + /// **'Least Points'** + String get least_points; + + /// Legal section header + /// + /// In en, this message translates to: + /// **'Legal'** + String get legal; + + /// Legal notice menu item + /// + /// In en, this message translates to: + /// **'Legal Notice'** + String get legal_notice; + + /// Licenses menu item + /// + /// In en, this message translates to: + /// **'Licenses'** + String get licenses; + + /// Message when match is in progress + /// + /// In en, this message translates to: + /// **'Match in progress...'** + String get match_in_progress; + + /// Placeholder for match name input + /// + /// In en, this message translates to: + /// **'Match name'** + String get match_name; + + /// Label for matches + /// + /// In en, this message translates to: + /// **'Matches'** + String get matches; + + /// Title for most points ruleset + /// + /// In en, this message translates to: + /// **'Most Points'** + String get most_points; + + /// Message when no data in the statistic tiles is given + /// + /// In en, this message translates to: + /// **'No data available'** + String get no_data_available; + + /// Message when no groups exist + /// + /// In en, this message translates to: + /// **'No groups created yet'** + String get no_groups_created_yet; + + /// Message when no licenses are found + /// + /// In en, this message translates to: + /// **'No licenses found'** + String get no_licenses_found; + + /// Message when no license text is available + /// + /// In en, this message translates to: + /// **'No license text available'** + String get no_license_text_available; + + /// Message when no matches exist + /// + /// In en, this message translates to: + /// **'No matches created yet'** + String get no_matches_created_yet; + + /// Message when no players exist + /// + /// In en, this message translates to: + /// **'No players created yet'** + String get no_players_created_yet; + + /// Message when search returns no results + /// + /// In en, this message translates to: + /// **'No players found with that name'** + String get no_players_found_with_that_name; + + /// Message when no players are selected + /// + /// In en, this message translates to: + /// **'No players selected'** + String get no_players_selected; + + /// Message when no recent matches exist + /// + /// In en, this message translates to: + /// **'No recent matches available'** + String get no_recent_matches_available; + + /// Message when no second match exists + /// + /// In en, this message translates to: + /// **'No second match available'** + String get no_second_match_available; + + /// Message when no statistics are available, because no matches were played yet + /// + /// In en, this message translates to: + /// **'No statistics available'** + String get no_statistics_available; + + /// None option label + /// + /// In en, this message translates to: + /// **'None'** + String get none; + + /// None group option label + /// + /// In en, this message translates to: + /// **'None'** + String get none_group; + + /// Abbreviation for not available + /// + /// In en, this message translates to: + /// **'Not available'** + String get not_available; + + /// Placeholder for player name input + /// + /// In en, this message translates to: + /// **'Player name'** + String get player_name; + + /// Players label + /// + /// In en, this message translates to: + /// **'Players'** + String get players; + + /// Shows the number of players + /// + /// In en, this message translates to: + /// **'{count} Players'** + String players_count(int count); + + /// Privacy policy menu item + /// + /// In en, this message translates to: + /// **'Privacy Policy'** + String get privacy_policy; + + /// Title for quick create section + /// + /// In en, this message translates to: + /// **'Quick Create'** + String get quick_create; + + /// Title for recent matches section + /// + /// In en, this message translates to: + /// **'Recent Matches'** + String get recent_matches; + + /// Ruleset label + /// + /// In en, this message translates to: + /// **'Ruleset'** + String get ruleset; + + /// Description for least points ruleset + /// + /// In en, this message translates to: + /// **'Inverse scoring: the player with the fewest points wins.'** + String get ruleset_least_points; + + /// Description for most points ruleset + /// + /// In en, this message translates to: + /// **'Traditional ruleset: the player with the most points wins.'** + String get ruleset_most_points; + + /// Description for single loser ruleset + /// + /// In en, this message translates to: + /// **'Exactly one loser is determined; last place receives the penalty or consequence.'** + String get ruleset_single_loser; + + /// Description for single winner ruleset + /// + /// In en, this message translates to: + /// **'Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.'** + String get ruleset_single_winner; + + /// Hint text for group search input field + /// + /// In en, this message translates to: + /// **'Search for groups'** + String get search_for_groups; + + /// Hint text for player search input field + /// + /// In en, this message translates to: + /// **'Search for players'** + String get search_for_players; + + /// Label to select the winner + /// + /// In en, this message translates to: + /// **'Select Winner:'** + String get select_winner; + + /// Shows the number of selected players + /// + /// In en, this message translates to: + /// **'Selected players'** + String get selected_players; + + /// Label for the App Settings + /// + /// In en, this message translates to: + /// **'Settings'** + String get settings; + + /// Title for single loser ruleset + /// + /// In en, this message translates to: + /// **'Single Loser'** + String get single_loser; + + /// Title for single winner ruleset + /// + /// In en, this message translates to: + /// **'Single Winner'** + String get single_winner; + + /// Statistics tab label + /// + /// In en, this message translates to: + /// **'Statistics'** + String get statistics; + + /// Stats tab label (short) + /// + /// In en, this message translates to: + /// **'Stats'** + String get stats; + + /// Success message when adding a player + /// + /// In en, this message translates to: + /// **'Successfully added player {playerName}'** + String successfully_added_player(String playerName); + + /// Message when search returns no groups + /// + /// In en, this message translates to: + /// **'There is no group matching your search'** + String get there_is_no_group_matching_your_search; + + /// Warning message for irreversible actions + /// + /// In en, this message translates to: + /// **'This can\'t be undone'** + String get this_cannot_be_undone; + + /// Date format for today + /// + /// In en, this message translates to: + /// **'Today at'** + String get today_at; + + /// Undo button text + /// + /// In en, this message translates to: + /// **'Undo'** + String get undo; + + /// Error message for unknown exceptions + /// + /// In en, this message translates to: + /// **'Unknown Exception (see console)'** + String get unknown_exception; + + /// Winner label + /// + /// In en, this message translates to: + /// **'Winner'** + String get winner; + + /// Label for winrate statistic + /// + /// In en, this message translates to: + /// **'Winrate'** + String get winrate; + + /// Label for wins statistic + /// + /// In en, this message translates to: + /// **'Wins'** + String get wins; + + /// Date format for yesterday + /// + /// In en, this message translates to: + /// **'Yesterday at'** + String get yesterday_at; +} + +class _AppLocalizationsDelegate + extends LocalizationsDelegate { + const _AppLocalizationsDelegate(); + + @override + Future load(Locale locale) { + return SynchronousFuture(lookupAppLocalizations(locale)); + } + + @override + bool isSupported(Locale locale) => + ['de', 'en'].contains(locale.languageCode); + + @override + bool shouldReload(_AppLocalizationsDelegate old) => false; +} + +AppLocalizations lookupAppLocalizations(Locale locale) { + // Lookup logic when only language code is specified. + switch (locale.languageCode) { + case 'de': + return AppLocalizationsDe(); + case 'en': + return AppLocalizationsEn(); + } + + throw FlutterError( + 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.', + ); +} diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart new file mode 100644 index 0000000..f4d0f8c --- /dev/null +++ b/lib/l10n/generated/app_localizations_de.dart @@ -0,0 +1,287 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for German (`de`). +class AppLocalizationsDe extends AppLocalizations { + AppLocalizationsDe([String locale = 'de']) : super(locale); + + @override + String get all_players => 'Alle Spieler:innen'; + + @override + String get all_players_selected => 'Alle Spieler:innen ausgewählt'; + + @override + String get amount_of_matches => 'Anzahl der Spiele'; + + @override + String get app_name => 'Game Tracker'; + + @override + String get cancel => 'Abbrechen'; + + @override + String get choose_game => 'Spielvorlage wählen'; + + @override + String get choose_group => 'Gruppe wählen'; + + @override + String get choose_ruleset => 'Regelwerk wählen'; + + @override + String could_not_add_player(Object playerName) { + return 'Spieler:in $playerName konnte nicht hinzugefügt werden'; + } + + @override + String get create_group => 'Gruppe erstellen'; + + @override + String get create_match => 'Spiel erstellen'; + + @override + String get create_new_group => 'Neue Gruppe erstellen'; + + @override + String get create_new_match => 'Neues Spiel erstellen'; + + @override + String get data => 'Daten'; + + @override + String get data_successfully_deleted => 'Daten erfolgreich gelöscht'; + + @override + String get data_successfully_exported => 'Daten erfolgreich exportiert'; + + @override + String get data_successfully_imported => 'Daten erfolgreich importiert'; + + @override + String days_ago(int count) { + return 'vor $count Tagen'; + } + + @override + String get delete => 'Löschen'; + + @override + String get delete_all_data => 'Alle Daten löschen'; + + @override + String get error_creating_group => + 'Fehler beim Erstellen der Gruppe, bitte erneut versuchen'; + + @override + String get error_reading_file => 'Fehler beim Lesen der Datei'; + + @override + String get export_canceled => 'Export abgebrochen'; + + @override + String get export_data => 'Daten exportieren'; + + @override + String get format_exception => 'Formatfehler (siehe Konsole)'; + + @override + String get game => 'Spielvorlage'; + + @override + String get game_name => 'Spielvorlagenname'; + + @override + String get group => 'Gruppe'; + + @override + String get group_name => 'Gruppenname'; + + @override + String get groups => 'Gruppen'; + + @override + String get home => 'Startseite'; + + @override + String get import_canceled => 'Import abgebrochen'; + + @override + String get import_data => 'Daten importieren'; + + @override + String get info => 'Info'; + + @override + String get invalid_schema => 'Ungültiges Schema'; + + @override + String get least_points => 'Niedrigste Punkte'; + + @override + String get legal => 'Rechtliches'; + + @override + String get legal_notice => 'Impressum'; + + @override + String get licenses => 'Lizenzen'; + + @override + String get match_in_progress => 'Spiel läuft...'; + + @override + String get match_name => 'Spieltitel'; + + @override + String get matches => 'Spiele'; + + @override + String get most_points => 'Höchste Punkte'; + + @override + String get no_data_available => 'Keine Daten verfügbar'; + + @override + String get no_groups_created_yet => 'Noch keine Gruppen erstellt'; + + @override + String get no_licenses_found => 'Keine Lizenzen gefunden'; + + @override + String get no_license_text_available => 'Kein Lizenztext verfügbar'; + + @override + String get no_matches_created_yet => 'Noch keine Spiele erstellt'; + + @override + String get no_players_created_yet => 'Noch keine Spieler:in erstellt'; + + @override + String get no_players_found_with_that_name => + 'Keine Spieler:in mit diesem Namen gefunden'; + + @override + String get no_players_selected => 'Keine Spieler:innen ausgewählt'; + + @override + String get no_recent_matches_available => 'Keine letzten Spiele verfügbar'; + + @override + String get no_second_match_available => 'Kein zweites Spiel verfügbar'; + + @override + String get no_statistics_available => 'Keine Statistiken verfügbar'; + + @override + String get none => 'Kein'; + + @override + String get none_group => 'Keine'; + + @override + String get not_available => 'Nicht verfügbar'; + + @override + String get player_name => 'Spieler:innenname'; + + @override + String get players => 'Spieler:innen'; + + @override + String players_count(int count) { + return '$count Spieler'; + } + + @override + String get privacy_policy => 'Datenschutzerklärung'; + + @override + String get quick_create => 'Schnellzugriff'; + + @override + String get recent_matches => 'Letzte Spiele'; + + @override + String get ruleset => 'Regelwerk'; + + @override + String get ruleset_least_points => + 'Umgekehrte Wertung: Der/die Spieler:in mit den wenigsten Punkten gewinnt.'; + + @override + String get ruleset_most_points => + 'Traditionelles Regelwerk: Der/die Spieler:in mit den meisten Punkten gewinnt.'; + + @override + String get ruleset_single_loser => + 'Genau ein:e Verlierer:in wird bestimmt; der letzte Platz erhält die Strafe oder Konsequenz.'; + + @override + String get ruleset_single_winner => + 'Genau ein:e Gewinner:in wird gewählt; Unentschieden werden durch einen vordefinierten Tie-Breaker aufgelöst.'; + + @override + String get search_for_groups => 'Nach Gruppen suchen'; + + @override + String get search_for_players => 'Nach Spieler:innen suchen'; + + @override + String get select_winner => 'Gewinner:in wählen:'; + + @override + String get selected_players => 'Ausgewählte Spieler:innen'; + + @override + String get settings => 'Einstellungen'; + + @override + String get single_loser => 'Ein:e Verlierer:in'; + + @override + String get single_winner => 'Ein:e Gewinner:in'; + + @override + String get statistics => 'Statistiken'; + + @override + String get stats => 'Statistiken'; + + @override + String successfully_added_player(String playerName) { + return 'Spieler:in $playerName erfolgreich hinzugefügt'; + } + + @override + String get there_is_no_group_matching_your_search => + 'Es gibt keine Gruppe, die deiner Suche entspricht'; + + @override + String get this_cannot_be_undone => + 'Dies kann nicht rückgängig gemacht werden'; + + @override + String get today_at => 'Heute um'; + + @override + String get undo => 'Rückgängig'; + + @override + String get unknown_exception => 'Unbekannter Fehler (siehe Konsole)'; + + @override + String get winner => 'Gewinner:in'; + + @override + String get winrate => 'Siegquote'; + + @override + String get wins => 'Siege'; + + @override + String get yesterday_at => 'Gestern um'; +} diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart new file mode 100644 index 0000000..6c4ac74 --- /dev/null +++ b/lib/l10n/generated/app_localizations_en.dart @@ -0,0 +1,286 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for English (`en`). +class AppLocalizationsEn extends AppLocalizations { + AppLocalizationsEn([String locale = 'en']) : super(locale); + + @override + String get all_players => 'All players'; + + @override + String get all_players_selected => 'All players selected'; + + @override + String get amount_of_matches => 'Amount of Matches'; + + @override + String get app_name => 'Game Tracker'; + + @override + String get cancel => 'Cancel'; + + @override + String get choose_game => 'Choose Game'; + + @override + String get choose_group => 'Choose Group'; + + @override + String get choose_ruleset => 'Choose Ruleset'; + + @override + String could_not_add_player(Object playerName) { + return 'Could not add player'; + } + + @override + String get create_group => 'Create Group'; + + @override + String get create_match => 'Create match'; + + @override + String get create_new_group => 'Create new group'; + + @override + String get create_new_match => 'Create new match'; + + @override + String get data => 'Data'; + + @override + String get data_successfully_deleted => 'Data successfully deleted'; + + @override + String get data_successfully_exported => 'Data successfully exported'; + + @override + String get data_successfully_imported => 'Data successfully imported'; + + @override + String days_ago(int count) { + return '$count days ago'; + } + + @override + String get delete => 'Delete'; + + @override + String get delete_all_data => 'Delete all data'; + + @override + String get error_creating_group => + 'Error while creating group, please try again'; + + @override + String get error_reading_file => 'Error reading file'; + + @override + String get export_canceled => 'Export canceled'; + + @override + String get export_data => 'Export data'; + + @override + String get format_exception => 'Format Exception (see console)'; + + @override + String get game => 'Game'; + + @override + String get game_name => 'Game Name'; + + @override + String get group => 'Group'; + + @override + String get group_name => 'Group name'; + + @override + String get groups => 'Groups'; + + @override + String get home => 'Home'; + + @override + String get import_canceled => 'Import canceled'; + + @override + String get import_data => 'Import data'; + + @override + String get info => 'Info'; + + @override + String get invalid_schema => 'Invalid Schema'; + + @override + String get least_points => 'Least Points'; + + @override + String get legal => 'Legal'; + + @override + String get legal_notice => 'Legal Notice'; + + @override + String get licenses => 'Licenses'; + + @override + String get match_in_progress => 'Match in progress...'; + + @override + String get match_name => 'Match name'; + + @override + String get matches => 'Matches'; + + @override + String get most_points => 'Most Points'; + + @override + String get no_data_available => 'No data available'; + + @override + String get no_groups_created_yet => 'No groups created yet'; + + @override + String get no_licenses_found => 'No licenses found'; + + @override + String get no_license_text_available => 'No license text available'; + + @override + String get no_matches_created_yet => 'No matches created yet'; + + @override + String get no_players_created_yet => 'No players created yet'; + + @override + String get no_players_found_with_that_name => + 'No players found with that name'; + + @override + String get no_players_selected => 'No players selected'; + + @override + String get no_recent_matches_available => 'No recent matches available'; + + @override + String get no_second_match_available => 'No second match available'; + + @override + String get no_statistics_available => 'No statistics available'; + + @override + String get none => 'None'; + + @override + String get none_group => 'None'; + + @override + String get not_available => 'Not available'; + + @override + String get player_name => 'Player name'; + + @override + String get players => 'Players'; + + @override + String players_count(int count) { + return '$count Players'; + } + + @override + String get privacy_policy => 'Privacy Policy'; + + @override + String get quick_create => 'Quick Create'; + + @override + String get recent_matches => 'Recent Matches'; + + @override + String get ruleset => 'Ruleset'; + + @override + String get ruleset_least_points => + 'Inverse scoring: the player with the fewest points wins.'; + + @override + String get ruleset_most_points => + 'Traditional ruleset: the player with the most points wins.'; + + @override + String get ruleset_single_loser => + 'Exactly one loser is determined; last place receives the penalty or consequence.'; + + @override + String get ruleset_single_winner => + 'Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.'; + + @override + String get search_for_groups => 'Search for groups'; + + @override + String get search_for_players => 'Search for players'; + + @override + String get select_winner => 'Select Winner:'; + + @override + String get selected_players => 'Selected players'; + + @override + String get settings => 'Settings'; + + @override + String get single_loser => 'Single Loser'; + + @override + String get single_winner => 'Single Winner'; + + @override + String get statistics => 'Statistics'; + + @override + String get stats => 'Stats'; + + @override + String successfully_added_player(String playerName) { + return 'Successfully added player $playerName'; + } + + @override + String get there_is_no_group_matching_your_search => + 'There is no group matching your search'; + + @override + String get this_cannot_be_undone => 'This can\'t be undone'; + + @override + String get today_at => 'Today at'; + + @override + String get undo => 'Undo'; + + @override + String get unknown_exception => 'Unknown Exception (see console)'; + + @override + String get winner => 'Winner'; + + @override + String get winrate => 'Winrate'; + + @override + String get wins => 'Wins'; + + @override + String get yesterday_at => 'Yesterday at'; +} diff --git a/lib/main.dart b/lib/main.dart index 98c40f8..2f64e2e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/views/main_menu/custom_navigation_bar.dart'; import 'package:provider/provider.dart'; @@ -20,22 +21,36 @@ class GameTracker extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + localeResolutionCallback: (locale, supportedLocales) { + for (final supportedLocale in supportedLocales) { + if (supportedLocale.languageCode == locale?.languageCode) { + return supportedLocale; + } + } + return supportedLocales.firstWhere( + (locale) => locale.languageCode == 'en', + ); + }, debugShowCheckedModeBanner: false, - title: 'Game Tracker', - darkTheme: ThemeData.dark(), - + onGenerateTitle: (context) => AppLocalizations.of(context).app_name, themeMode: ThemeMode.dark, // forces dark mode theme: ThemeData( primaryColor: CustomTheme.primaryColor, scaffoldBackgroundColor: CustomTheme.backgroundColor, appBarTheme: CustomTheme.appBarTheme, - colorScheme: ColorScheme.fromSeed( seedColor: CustomTheme.primaryColor, brightness: Brightness.dark, ).copyWith(surface: CustomTheme.backgroundColor), + pageTransitionsTheme: const PageTransitionsTheme( + builders: { + TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), + TargetPlatform.android: PredictiveBackPageTransitionsBuilder(), + }, + ), ), - home: const CustomNavigationBar(), ); } diff --git a/lib/presentation/views/main_menu/create_game/choose_group_view.dart b/lib/presentation/views/main_menu/create_game/choose_group_view.dart deleted file mode 100644 index c98ce6d..0000000 --- a/lib/presentation/views/main_menu/create_game/choose_group_view.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart'; - -class ChooseGroupView extends StatefulWidget { - final List groups; - final int initialGroupIndex; - - const ChooseGroupView({ - super.key, - required this.groups, - required this.initialGroupIndex, - }); - - @override - State createState() => _ChooseGroupViewState(); -} - -class _ChooseGroupViewState extends State { - late int selectedGroupIndex; - - @override - void initState() { - selectedGroupIndex = widget.initialGroupIndex; - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: CustomTheme.backgroundColor, - appBar: AppBar( - backgroundColor: CustomTheme.backgroundColor, - scrolledUnderElevation: 0, - title: const Text( - 'Choose Group', - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - centerTitle: true, - ), - body: ListView.builder( - padding: const EdgeInsets.only(bottom: 85), - itemCount: widget.groups.length, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - setState(() { - selectedGroupIndex = index; - }); - - Future.delayed(const Duration(milliseconds: 500), () { - if (!context.mounted) return; - Navigator.of(context).pop(widget.groups[index]); - }); - }, - child: GroupTile( - group: widget.groups[index], - isHighlighted: selectedGroupIndex == index, - ), - ); - }, - ), - ); - } -} diff --git a/lib/presentation/views/main_menu/create_game/choose_ruleset_view.dart b/lib/presentation/views/main_menu/create_game/choose_ruleset_view.dart deleted file mode 100644 index b54f56e..0000000 --- a/lib/presentation/views/main_menu/create_game/choose_ruleset_view.dart +++ /dev/null @@ -1,120 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/core/enums.dart'; -import 'package:game_tracker/presentation/widgets/tiles/ruleset_list_tile.dart'; - -class ChooseRulesetView extends StatefulWidget { - final List<(Ruleset, String, String)> rulesets; - final int initialRulesetIndex; - const ChooseRulesetView({ - super.key, - required this.rulesets, - required this.initialRulesetIndex, - }); - - @override - State createState() => _ChooseRulesetViewState(); -} - -class _ChooseRulesetViewState extends State { - late int selectedRulesetIndex; - - @override - void initState() { - selectedRulesetIndex = widget.initialRulesetIndex; - super.initState(); - } - - @override - Widget build(BuildContext context) { - return DefaultTabController( - length: 2, - initialIndex: 0, - child: Scaffold( - backgroundColor: CustomTheme.backgroundColor, - appBar: AppBar( - backgroundColor: CustomTheme.backgroundColor, - scrolledUnderElevation: 0, - title: const Text( - 'Choose Ruleset', - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - centerTitle: true, - ), - body: Column( - children: [ - Container( - color: CustomTheme.backgroundColor, - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - child: TabBar( - padding: const EdgeInsets.symmetric(horizontal: 5), - // Label Settings - labelStyle: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - labelColor: Colors.white, - unselectedLabelStyle: const TextStyle(fontSize: 14), - unselectedLabelColor: Colors.white70, - // Indicator Settings - indicator: CustomTheme.standardBoxDecoration, - indicatorSize: TabBarIndicatorSize.tab, - indicatorWeight: 1, - indicatorPadding: const EdgeInsets.symmetric( - horizontal: 20, - vertical: 0, - ), - // Divider Settings - dividerHeight: 0, - tabs: const [ - Tab(text: 'Rulesets'), - Tab(text: 'Gametypes'), - ], - ), - ), - const Divider( - indent: 30, - endIndent: 30, - thickness: 3, - radius: BorderRadius.all(Radius.circular(12)), - ), - Expanded( - child: TabBarView( - children: [ - ListView.builder( - padding: const EdgeInsets.only(bottom: 85), - itemCount: widget.rulesets.length, - itemBuilder: (BuildContext context, int index) { - return RulesetListTile( - onPressed: () async { - setState(() { - selectedRulesetIndex = index; - }); - Future.delayed(const Duration(milliseconds: 500), () { - if (!context.mounted) return; - Navigator.of( - context, - ).pop(widget.rulesets[index].$1); - }); - }, - title: widget.rulesets[index].$2, - description: widget.rulesets[index].$3, - isHighlighted: selectedRulesetIndex == index, - ); - }, - ), - const Center( - child: Text( - 'No gametypes available', - style: TextStyle(color: Colors.white70), - ), - ), - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/presentation/views/main_menu/create_game/create_game_view.dart b/lib/presentation/views/main_menu/create_game/create_game_view.dart deleted file mode 100644 index 485118b..0000000 --- a/lib/presentation/views/main_menu/create_game/create_game_view.dart +++ /dev/null @@ -1,232 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/core/enums.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/game.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/presentation/views/main_menu/create_game/choose_group_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/create_game/choose_ruleset_view.dart'; -import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; -import 'package:game_tracker/presentation/widgets/player_selection.dart'; -import 'package:game_tracker/presentation/widgets/text_input/text_input_field.dart'; -import 'package:game_tracker/presentation/widgets/tiles/choose_tile.dart'; -import 'package:provider/provider.dart'; - -class CreateGameView extends StatefulWidget { - const CreateGameView({super.key}); - - @override - State createState() => _CreateGameViewState(); -} - -class _CreateGameViewState extends State { - /// Reference to the app database - late final AppDatabase db; - - /// Futures to load all groups and players from the database - late Future> _allGroupsFuture; - - /// Future to load all players from the database - late Future> _allPlayersFuture; - - /// Controller for the game name input field - final TextEditingController _gameNameController = TextEditingController(); - - /// List of all groups from the database - List groupsList = []; - - /// List of all players from the database - List playerList = []; - - /// The currently selected group - Group? selectedGroup; - - /// The index of the currently selected group in [groupsList] to mark it in - /// the [ChooseGroupView] - int selectedGroupIndex = -1; - - /// The currently selected ruleset - Ruleset? selectedRuleset; - - /// The index of the currently selected ruleset in [rulesets] to mark it in - /// the [ChooseRulesetView] - int selectedRulesetIndex = -1; - - /// The currently selected players - List? selectedPlayers; - - /// List of available rulesets with their display names and descriptions - /// as tuples of (Ruleset, String, String) - List<(Ruleset, String, String)> rulesets = [ - ( - Ruleset.singleWinner, - 'Single Winner', - 'Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.', - ), - ( - Ruleset.singleLoser, - 'Single Loser', - 'Exactly one loser is determined; last place receives the penalty or consequence.', - ), - ( - Ruleset.mostPoints, - 'Most Points', - 'Traditional ruleset: the player with the most points wins.', - ), - ( - Ruleset.lastPoints, - 'Least Points', - 'Inverse scoring: the player with the fewest points wins.', - ), - ]; - - @override - void initState() { - super.initState(); - db = Provider.of(context, listen: false); - - _allGroupsFuture = db.groupDao.getAllGroups(); - _allPlayersFuture = db.playerDao.getAllPlayers(); - - Future.wait([_allGroupsFuture, _allPlayersFuture]).then((result) async { - groupsList = result[0] as List; - playerList = result[1] as List; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: CustomTheme.backgroundColor, - appBar: AppBar( - backgroundColor: CustomTheme.backgroundColor, - scrolledUnderElevation: 0, - title: const Text( - 'Create new game', - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - centerTitle: true, - ), - body: SafeArea( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), - child: TextInputField( - controller: _gameNameController, - hintText: 'Game name', - onChanged: (value) { - setState(() {}); - }, - ), - ), - ChooseTile( - title: 'Ruleset', - trailingText: selectedRuleset == null - ? 'None' - : translateRulesetToString(selectedRuleset!), - onPressed: () async { - selectedRuleset = await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => ChooseRulesetView( - rulesets: rulesets, - initialRulesetIndex: selectedRulesetIndex, - ), - ), - ); - selectedRulesetIndex = rulesets.indexWhere( - (r) => r.$1 == selectedRuleset, - ); - setState(() {}); - }, - ), - ChooseTile( - title: 'Group', - trailingText: selectedGroup == null - ? 'None' - : selectedGroup!.name, - onPressed: () async { - selectedGroup = await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => ChooseGroupView( - groups: groupsList, - initialGroupIndex: selectedGroupIndex, - ), - ), - ); - selectedGroupIndex = groupsList.indexWhere( - (g) => g.id == selectedGroup?.id, - ); - setState(() {}); - }, - ), - Expanded( - child: PlayerSelection( - key: ValueKey(selectedGroup?.id ?? 'no_group'), - initialPlayers: selectedGroup == null - ? playerList - : playerList - .where( - (p) => !selectedGroup!.members.any( - (m) => m.id == p.id, - ), - ) - .toList(), - onChanged: (value) { - setState(() { - selectedPlayers = value; - }); - }, - ), - ), - - CustomWidthButton( - text: 'Create game', - sizeRelativeToWidth: 0.95, - buttonType: ButtonType.primary, - onPressed: _enableCreateGameButton() - ? () async { - Game game = Game( - name: _gameNameController.text.trim(), - createdAt: DateTime.now(), - group: selectedGroup!, - players: selectedPlayers, - ); - // TODO: Replace with navigation to GameResultView() - print('Created game: $game'); - Navigator.pop(context); - } - : null, - ), - const SizedBox(height: 20), - ], - ), - ), - ); - } - - /// Translates a [Ruleset] enum value to its corresponding string representation. - String translateRulesetToString(Ruleset ruleset) { - switch (ruleset) { - case Ruleset.singleWinner: - return 'Single Winner'; - case Ruleset.singleLoser: - return 'Single Loser'; - case Ruleset.mostPoints: - return 'Most Points'; - case Ruleset.lastPoints: - return 'Least Points'; - } - } - - /// Determines whether the "Create Game" button should be enabled based on - /// the current state of the input fields. - bool _enableCreateGameButton() { - return _gameNameController.text.isNotEmpty && - (selectedGroup != null || - (selectedPlayers != null && selectedPlayers!.isNotEmpty)) && - selectedRuleset != null; - } -} diff --git a/lib/presentation/views/main_menu/create_group_view.dart b/lib/presentation/views/main_menu/create_group_view.dart deleted file mode 100644 index cbaee6d..0000000 --- a/lib/presentation/views/main_menu/create_group_view.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/core/enums.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; -import 'package:game_tracker/presentation/widgets/player_selection.dart'; -import 'package:game_tracker/presentation/widgets/text_input/text_input_field.dart'; -import 'package:provider/provider.dart'; - -class CreateGroupView extends StatefulWidget { - const CreateGroupView({super.key}); - - @override - State createState() => _CreateGroupViewState(); -} - -class _CreateGroupViewState extends State { - final _groupNameController = TextEditingController(); - late final AppDatabase db; - List selectedPlayers = []; - - @override - void initState() { - super.initState(); - db = Provider.of(context, listen: false); - _groupNameController.addListener(() { - setState(() {}); - }); - } - - @override - void dispose() { - _groupNameController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: CustomTheme.backgroundColor, - appBar: AppBar( - backgroundColor: CustomTheme.backgroundColor, - scrolledUnderElevation: 0, - title: const Text( - 'Create new group', - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - centerTitle: true, - ), - body: SafeArea( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), - child: TextInputField( - controller: _groupNameController, - hintText: 'Group name', - onChanged: (value) { - setState(() {}); - }, - ), - ), - Expanded( - child: PlayerSelection( - onChanged: (value) { - selectedPlayers = [...value]; - }, - ), - ), - CustomWidthButton( - text: 'Create group', - sizeRelativeToWidth: 0.95, - buttonType: ButtonType.primary, - onPressed: - (_groupNameController.text.isEmpty || selectedPlayers.isEmpty) - ? null - : () async { - bool success = await db.groupDao.addGroup( - group: Group( - name: _groupNameController.text.trim(), - members: selectedPlayers, - ), - ); - if (!context.mounted) return; - if (success) { - Navigator.pop(context); - } else { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - backgroundColor: CustomTheme.boxColor, - content: const Center( - child: Text( - 'Error while creating group, please try again', - style: TextStyle(color: Colors.white), - ), - ), - ), - ); - } - setState(() {}); - }, - ), - const SizedBox(height: 20), - ], - ), - ), - ); - } -} diff --git a/lib/presentation/views/main_menu/custom_navigation_bar.dart b/lib/presentation/views/main_menu/custom_navigation_bar.dart index 71a072e..f6eb381 100644 --- a/lib/presentation/views/main_menu/custom_navigation_bar.dart +++ b/lib/presentation/views/main_menu/custom_navigation_bar.dart @@ -1,9 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:game_tracker/core/adaptive_page_route.dart'; import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/presentation/views/main_menu/game_history_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/groups_view.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/views/main_menu/group_view/groups_view.dart'; import 'package:game_tracker/presentation/views/main_menu/home_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/settings_view.dart'; +import 'package:game_tracker/presentation/views/main_menu/match_view/match_view.dart'; +import 'package:game_tracker/presentation/views/main_menu/settings_view/settings_view.dart'; import 'package:game_tracker/presentation/views/main_menu/statistics_view.dart'; import 'package:game_tracker/presentation/widgets/navbar_item.dart'; @@ -16,22 +18,21 @@ class CustomNavigationBar extends StatefulWidget { class _CustomNavigationBarState extends State with SingleTickerProviderStateMixin { + /// Currently selected tab index int currentIndex = 0; + + /// Key count to force rebuild of tab views int tabKeyCount = 0; - @override - void initState() { - super.initState(); - } - @override Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); // Pretty ugly but works final List tabs = [ KeyedSubtree(key: ValueKey('home_$tabKeyCount'), child: const HomeView()), KeyedSubtree( - key: ValueKey('games_$tabKeyCount'), - child: const GameHistoryView(), + key: ValueKey('matches_$tabKeyCount'), + child: const MatchView(), ), KeyedSubtree( key: ValueKey('groups_$tabKeyCount'), @@ -46,7 +47,7 @@ class _CustomNavigationBarState extends State appBar: AppBar( centerTitle: true, title: Text( - _currentTabTitle(), + _currentTabTitle(context), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), backgroundColor: CustomTheme.backgroundColor, @@ -56,7 +57,7 @@ class _CustomNavigationBarState extends State onPressed: () async { await Navigator.push( context, - MaterialPageRoute(builder: (_) => const SettingsView()), + adaptivePageRoute(builder: (_) => const SettingsView()), ); setState(() { tabKeyCount++; @@ -89,28 +90,28 @@ class _CustomNavigationBarState extends State index: 0, isSelected: currentIndex == 0, icon: Icons.home_rounded, - label: 'Home', + label: loc.home, onTabTapped: onTabTapped, ), NavbarItem( index: 1, isSelected: currentIndex == 1, icon: Icons.gamepad_rounded, - label: 'Games', + label: loc.matches, onTabTapped: onTabTapped, ), NavbarItem( index: 2, isSelected: currentIndex == 2, icon: Icons.group_rounded, - label: 'Groups', + label: loc.groups, onTabTapped: onTabTapped, ), NavbarItem( index: 3, isSelected: currentIndex == 3, icon: Icons.bar_chart_rounded, - label: 'Stats', + label: loc.statistics, onTabTapped: onTabTapped, ), ], @@ -122,22 +123,25 @@ class _CustomNavigationBarState extends State ); } + /// Handles tab tap events. Updates the current [index] state. void onTabTapped(int index) { setState(() { currentIndex = index; }); } - String _currentTabTitle() { + /// Returns the title of the current tab based on [currentIndex]. + String _currentTabTitle(context) { + final loc = AppLocalizations.of(context); switch (currentIndex) { case 0: - return 'Home'; + return loc.home; case 1: - return 'Game History'; + return loc.matches; case 2: - return 'Groups'; + return loc.groups; case 3: - return 'Statistics'; + return loc.statistics; default: return ''; } diff --git a/lib/presentation/views/main_menu/game_history_view.dart b/lib/presentation/views/main_menu/game_history_view.dart deleted file mode 100644 index 31d1b56..0000000 --- a/lib/presentation/views/main_menu/game_history_view.dart +++ /dev/null @@ -1,150 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/game.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/presentation/views/main_menu/create_group_view.dart'; -import 'package:game_tracker/presentation/views/main_menu/game_result_view.dart'; -import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; -import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; -import 'package:game_tracker/presentation/widgets/tiles/game_history_tile.dart'; -import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; -import 'package:provider/provider.dart'; - -class GameHistoryView extends StatefulWidget { - const GameHistoryView({super.key}); - - @override - State createState() => _GameHistoryViewState(); -} - -class _GameHistoryViewState extends State { - late Future> _gameListFuture; - late final AppDatabase db; - - late final List skeletonData = List.filled( - 4, - Game( - name: 'Skeleton Game', - group: Group( - name: 'Skeleton Group', - members: [ - Player(name: 'Player 1'), - Player(name: 'Player 2'), - Player(name: 'Player 3'), - Player(name: 'Long Name Player 4'), - Player(name: 'Player 5'), - ], - ), - winner: Player(name: 'Skeleton Player 1'), - players: [Player(name: 'Skeleton Player 6')], - ), - ); - - @override - void initState() { - super.initState(); - db = Provider.of(context, listen: false); - _gameListFuture = Future.delayed( - const Duration(milliseconds: 250), - () => db.gameDao.getAllGames(), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: CustomTheme.backgroundColor, - body: Stack( - alignment: Alignment.center, - children: [ - FutureBuilder>( - future: _gameListFuture, - builder: - (BuildContext context, AsyncSnapshot> snapshot) { - if (snapshot.hasError) { - return const Center( - child: TopCenteredMessage( - icon: Icons.report, - title: 'Error', - message: 'Game data could not be loaded', - ), - ); - } - if (snapshot.connectionState == ConnectionState.done && - (!snapshot.hasData || snapshot.data!.isEmpty)) { - return const Center( - child: TopCenteredMessage( - icon: Icons.report, - title: 'Info', - message: 'No games created yet', - ), - ); - } - final bool isLoading = - snapshot.connectionState == ConnectionState.waiting; - final List games = - (isLoading ? skeletonData : (snapshot.data ?? []) - ..sort( - (a, b) => b.createdAt.compareTo(a.createdAt), - )) - .toList(); - return AppSkeleton( - enabled: isLoading, - child: ListView.builder( - padding: const EdgeInsets.only(bottom: 85), - itemCount: games.length + 1, - itemBuilder: (BuildContext context, int index) { - if (index == games.length) { - return SizedBox( - height: MediaQuery.paddingOf(context).bottom - 80, - ); - } - return GameHistoryTile( - onTap: () async { - await Navigator.push( - context, - CupertinoPageRoute( - fullscreenDialog: true, - builder: (context) => - GameResultView(game: games[index]), - ), - ); - setState(() { - _gameListFuture = db.gameDao.getAllGames(); - }); - }, - game: games[index], - ); - }, - ), - ); - }, - ), - Positioned( - bottom: MediaQuery.paddingOf(context).bottom, - child: CustomWidthButton( - text: 'Create Game', - sizeRelativeToWidth: 0.90, - onPressed: () async { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return const CreateGroupView(); - }, - ), - ); - setState(() { - _gameListFuture = db.gameDao.getAllGames(); - }); - }, - ), - ), - ], - ), - ); - } -} diff --git a/lib/presentation/views/main_menu/group_view/create_group_view.dart b/lib/presentation/views/main_menu/group_view/create_group_view.dart new file mode 100644 index 0000000..8192c6b --- /dev/null +++ b/lib/presentation/views/main_menu/group_view/create_group_view.dart @@ -0,0 +1,113 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/core/enums.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; +import 'package:game_tracker/presentation/widgets/player_selection.dart'; +import 'package:game_tracker/presentation/widgets/text_input/text_input_field.dart'; +import 'package:provider/provider.dart'; + +class CreateGroupView extends StatefulWidget { + const CreateGroupView({super.key}); + + @override + State createState() => _CreateGroupViewState(); +} + +class _CreateGroupViewState extends State { + late final AppDatabase db; + + /// Controller for the group name input field + final _groupNameController = TextEditingController(); + + /// List of currently selected players + List selectedPlayers = []; + + @override + void initState() { + super.initState(); + db = Provider.of(context, listen: false); + _groupNameController.addListener(() { + setState(() {}); + }); + } + + @override + void dispose() { + _groupNameController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); + return ScaffoldMessenger( + child: Scaffold( + backgroundColor: CustomTheme.backgroundColor, + appBar: AppBar(title: Text(loc.create_new_group)), + body: SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + margin: CustomTheme.standardMargin, + child: TextInputField( + controller: _groupNameController, + hintText: loc.group_name, + ), + ), + Expanded( + child: PlayerSelection( + onChanged: (value) { + setState(() { + selectedPlayers = [...value]; + }); + }, + ), + ), + CustomWidthButton( + text: loc.create_group, + sizeRelativeToWidth: 0.95, + buttonType: ButtonType.primary, + onPressed: + (_groupNameController.text.isEmpty || + (selectedPlayers.length < 2)) + ? null + : () async { + bool success = await db.groupDao.addGroup( + group: Group( + name: _groupNameController.text.trim(), + members: selectedPlayers, + ), + ); + if (!context.mounted) return; + if (success) { + Navigator.pop(context); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: CustomTheme.boxColor, + content: Center( + child: Text( + AppLocalizations.of( + context, + ).error_creating_group, + style: const TextStyle(color: Colors.white), + ), + ), + ), + ); + } + }, + ), + const SizedBox(height: 20), + ], + ), + ), + ), + ); + } +} diff --git a/lib/presentation/views/main_menu/group_view/groups_view.dart b/lib/presentation/views/main_menu/group_view/groups_view.dart new file mode 100644 index 0000000..239aa23 --- /dev/null +++ b/lib/presentation/views/main_menu/group_view/groups_view.dart @@ -0,0 +1,123 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/adaptive_page_route.dart'; +import 'package:game_tracker/core/constants.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/views/main_menu/group_view/create_group_view.dart'; +import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; +import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; +import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart'; +import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; +import 'package:provider/provider.dart'; + +class GroupsView extends StatefulWidget { + const GroupsView({super.key}); + + @override + State createState() => _GroupsViewState(); +} + +class _GroupsViewState extends State { + late final AppDatabase db; + + /// Loaded groups from the database + late List loadedGroups; + + /// Loading state + bool isLoading = true; + + List groups = List.filled( + 7, + Group( + name: 'Skeleton Group', + members: List.filled(6, Player(name: 'Skeleton Player')), + ), + ); + + @override + void initState() { + super.initState(); + + db = Provider.of(context, listen: false); + loadGroups(); + } + + @override + Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); + return Scaffold( + backgroundColor: CustomTheme.backgroundColor, + body: Stack( + alignment: Alignment.center, + children: [ + AppSkeleton( + enabled: isLoading, + child: Visibility( + visible: groups.isNotEmpty, + replacement: Center( + child: TopCenteredMessage( + icon: Icons.info, + title: loc.info, + message: loc.no_groups_created_yet, + ), + ), + child: ListView.builder( + padding: const EdgeInsets.only(bottom: 85), + itemCount: groups.length + 1, + itemBuilder: (BuildContext context, int index) { + if (index == groups.length) { + return SizedBox( + height: MediaQuery.paddingOf(context).bottom - 20, + ); + } + return GroupTile(group: groups[index]); + }, + ), + ), + ), + Positioned( + bottom: MediaQuery.paddingOf(context).bottom, + child: CustomWidthButton( + text: loc.create_group, + sizeRelativeToWidth: 0.90, + onPressed: () async { + await Navigator.push( + context, + adaptivePageRoute( + builder: (context) { + return const CreateGroupView(); + }, + ), + ); + setState(() { + loadGroups(); + }); + }, + ), + ), + ], + ), + ); + } + + void loadGroups() { + Future.wait([ + db.groupDao.getAllGroups(), + Future.delayed(Constants.minimumSkeletonDuration), + ]).then((results) { + loadedGroups = results[0] as List; + setState(() { + groups = loadedGroups + ..sort((a, b) => b.createdAt.compareTo(a.createdAt)); + }); + if (mounted) { + setState(() { + isLoading = false; + }); + } + }); + } +} diff --git a/lib/presentation/views/main_menu/groups_view.dart b/lib/presentation/views/main_menu/groups_view.dart deleted file mode 100644 index ce47f90..0000000 --- a/lib/presentation/views/main_menu/groups_view.dart +++ /dev/null @@ -1,119 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/player.dart'; -import 'package:game_tracker/presentation/views/main_menu/create_group_view.dart'; -import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; -import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; -import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart'; -import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; -import 'package:provider/provider.dart'; - -class GroupsView extends StatefulWidget { - const GroupsView({super.key}); - - @override - State createState() => _GroupsViewState(); -} - -class _GroupsViewState extends State { - late Future> _allGroupsFuture; - late final AppDatabase db; - - final player = Player(name: 'Skeleton Player'); - late final List skeletonData = List.filled( - 7, - Group( - name: 'Skeleton Game', - members: [player, player, player, player, player, player], - ), - ); - - @override - void initState() { - super.initState(); - db = Provider.of(context, listen: false); - _allGroupsFuture = Future.delayed( - const Duration(milliseconds: 250), - () => db.groupDao.getAllGroups(), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: CustomTheme.backgroundColor, - body: Stack( - alignment: Alignment.center, - children: [ - FutureBuilder>( - future: _allGroupsFuture, - builder: - (BuildContext context, AsyncSnapshot> snapshot) { - if (snapshot.hasError) { - return const Center( - child: TopCenteredMessage( - icon: Icons.report, - title: 'Error', - message: 'Group data couldn\'t\nbe loaded', - ), - ); - } - if (snapshot.connectionState == ConnectionState.done && - (!snapshot.hasData || snapshot.data!.isEmpty)) { - return const Center( - child: TopCenteredMessage( - icon: Icons.info, - title: 'Info', - message: 'No groups created yet', - ), - ); - } - final bool isLoading = - snapshot.connectionState == ConnectionState.waiting; - final List groups = - isLoading ? skeletonData : (snapshot.data ?? []) - ..sort((a, b) => b.createdAt.compareTo(a.createdAt)); - return AppSkeleton( - enabled: isLoading, - child: ListView.builder( - padding: const EdgeInsets.only(bottom: 85), - itemCount: groups.length + 1, - itemBuilder: (BuildContext context, int index) { - if (index == groups.length) { - return SizedBox( - height: MediaQuery.paddingOf(context).bottom - 20, - ); - } - return GroupTile(group: groups[index]); - }, - ), - ); - }, - ), - Positioned( - bottom: MediaQuery.paddingOf(context).bottom, - child: CustomWidthButton( - text: 'Create Group', - sizeRelativeToWidth: 0.90, - onPressed: () async { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return const CreateGroupView(); - }, - ), - ); - setState(() { - _allGroupsFuture = db.groupDao.getAllGroups(); - }); - }, - ), - ), - ], - ), - ); - } -} diff --git a/lib/presentation/views/main_menu/home_view.dart b/lib/presentation/views/main_menu/home_view.dart index 1667f2b..affbe92 100644 --- a/lib/presentation/views/main_menu/home_view.dart +++ b/lib/presentation/views/main_menu/home_view.dart @@ -1,12 +1,16 @@ import 'package:flutter/material.dart'; +import 'package:game_tracker/core/adaptive_page_route.dart'; +import 'package:game_tracker/core/constants.dart'; import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/game.dart'; import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/match.dart'; import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart'; import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; import 'package:game_tracker/presentation/widgets/buttons/quick_create_button.dart'; -import 'package:game_tracker/presentation/widgets/tiles/game_tile.dart'; import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart'; +import 'package:game_tracker/presentation/widgets/tiles/match_tile.dart'; import 'package:game_tracker/presentation/widgets/tiles/quick_info_tile.dart'; import 'package:provider/provider.dart'; @@ -18,15 +22,22 @@ class HomeView extends StatefulWidget { } class _HomeViewState extends State { - late Future _gameCountFuture; - late Future _groupCountFuture; - late Future> _recentGamesFuture; bool isLoading = true; - late final List skeletonData = List.filled( + /// Amount of matches in the database + int matchCount = 0; + + /// Amount of groups in the database + int groupCount = 0; + + /// Loaded recent matches from the database + List loadedRecentMatches = []; + + /// Recent matches to display, initially filled with skeleton matches + List recentMatches = List.filled( 2, - Game( - name: 'Skeleton Game', + Match( + name: 'Skeleton Match', group: Group( name: 'Skeleton Group', members: [ @@ -34,35 +45,22 @@ class _HomeViewState extends State { Player(name: 'Skeleton Player 2'), ], ), - winner: Player(name: 'Skeleton Player 1'), ), ); @override - initState() { + void initState() { super.initState(); - final db = Provider.of(context, listen: false); - _gameCountFuture = db.gameDao.getGameCount(); - _groupCountFuture = db.groupDao.getGroupCount(); - _recentGamesFuture = db.gameDao.getAllGames(); - - Future.wait([_gameCountFuture, _groupCountFuture, _recentGamesFuture]).then( - (_) async { - await Future.delayed(const Duration(milliseconds: 250)); - if (mounted) { - setState(() { - isLoading = false; - }); - } - }, - ); + loadHomeViewData(); } @override Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { return AppSkeleton( + fixLayoutBuilder: true, enabled: isLoading, child: SingleChildScrollView( child: Column( @@ -71,38 +69,20 @@ class _HomeViewState extends State { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - FutureBuilder( - future: _gameCountFuture, - builder: (context, snapshot) { - final int count = (snapshot.hasData) - ? snapshot.data! - : 0; - return QuickInfoTile( - width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.15, - title: 'Games', - icon: Icons.groups_rounded, - value: count, - ); - }, + QuickInfoTile( + width: constraints.maxWidth * 0.45, + height: constraints.maxHeight * 0.15, + title: loc.matches, + icon: Icons.groups_rounded, + value: matchCount, ), SizedBox(width: constraints.maxWidth * 0.05), - FutureBuilder( - future: _groupCountFuture, - builder: (context, snapshot) { - final int count = - (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) - ? snapshot.data! - : 0; - return QuickInfoTile( - width: constraints.maxWidth * 0.45, - height: constraints.maxHeight * 0.15, - title: 'Groups', - icon: Icons.groups_rounded, - value: count, - ); - }, + QuickInfoTile( + width: constraints.maxWidth * 0.45, + height: constraints.maxHeight * 0.15, + title: loc.groups, + icon: Icons.groups_rounded, + value: groupCount, ), ], ), @@ -110,137 +90,93 @@ class _HomeViewState extends State { padding: const EdgeInsets.symmetric(vertical: 16.0), child: InfoTile( width: constraints.maxWidth * 0.95, - title: 'Recent Games', - icon: Icons.timer, - content: Padding( - padding: const EdgeInsets.symmetric(horizontal: 40.0), - child: FutureBuilder( - future: _recentGamesFuture, - builder: - ( - BuildContext context, - AsyncSnapshot> snapshot, - ) { - if (snapshot.hasError) { - return const Center( - heightFactor: 4, - child: Text( - 'Error while loading recent games.', - ), - ); - } - final List games = - (isLoading - ? skeletonData - : (snapshot.data ?? []) - ..sort( - (a, b) => b.createdAt.compareTo( - a.createdAt, - ), - )) - .take(2) - .toList(); - if (games.isNotEmpty) { - return Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - GameTile( - gameTitle: games[0].name, - gameType: 'Winner', - ruleset: 'Ruleset', - players: _getPlayerText(games[0]), - winner: games[0].winner == null - ? 'Game in progress...' - : games[0].winner!.name, + title: loc.recent_matches, + icon: Icons.history_rounded, + content: Column( + children: [ + if (recentMatches.isNotEmpty) + for (Match match in recentMatches) + Padding( + padding: const EdgeInsets.symmetric( + vertical: 6.0, + ), + child: MatchTile( + compact: true, + width: constraints.maxWidth * 0.9, + match: match, + onTap: () async { + await Navigator.of(context).push( + adaptivePageRoute( + fullscreenDialog: true, + builder: (context) => + MatchResultView(match: match), ), - const Padding( - padding: EdgeInsets.symmetric( - vertical: 8.0, - ), - child: Divider(), - ), - if (games.length > 1) ...[ - GameTile( - gameTitle: games[1].name, - gameType: 'Winner', - ruleset: 'Ruleset', - players: _getPlayerText(games[1]), - winner: games[1].winner == null - ? 'Game in progress...' - : games[1].winner!.name, - ), - const SizedBox(height: 8), - ] else ...[ - const Center( - heightFactor: 4, - child: Text( - 'No second game available.', - ), - ), - ], - ], - ); - } else { - return const Center( - heightFactor: 12, - child: Text('No recent games available.'), - ); - } - }, - ), + ); + await updatedWinnerinRecentMatches(match.id); + }, + ), + ) + else + Center( + heightFactor: 5, + child: Text(loc.no_recent_matches_available), + ), + ], ), ), ), - InfoTile( - width: constraints.maxWidth * 0.95, - title: 'Quick Create', - icon: Icons.add_box_rounded, - content: Column( - spacing: 8, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickCreateButton( - text: 'Category 1', - onPressed: () {}, - ), - QuickCreateButton( - text: 'Category 2', - onPressed: () {}, - ), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickCreateButton( - text: 'Category 3', - onPressed: () {}, - ), - QuickCreateButton( - text: 'Category 4', - onPressed: () {}, - ), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - QuickCreateButton( - text: 'Category 5', - onPressed: () {}, - ), - QuickCreateButton( - text: 'Category 6', - onPressed: () {}, - ), - ], - ), - ], + Padding( + padding: EdgeInsets.zero, + child: InfoTile( + width: constraints.maxWidth * 0.95, + title: loc.quick_create, + icon: Icons.add_box_rounded, + content: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + QuickCreateButton( + text: 'Category 1', + onPressed: () {}, + ), + QuickCreateButton( + text: 'Category 2', + onPressed: () {}, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + QuickCreateButton( + text: 'Category 3', + onPressed: () {}, + ), + QuickCreateButton( + text: 'Category 4', + onPressed: () {}, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + QuickCreateButton( + text: 'Category 5', + onPressed: () {}, + ), + QuickCreateButton( + text: 'Category 6', + onPressed: () {}, + ), + ], + ), + ], + ), ), ), + SizedBox(height: MediaQuery.paddingOf(context).bottom), ], ), ), @@ -249,14 +185,41 @@ class _HomeViewState extends State { ); } - String _getPlayerText(Game game) { - if (game.group == null) { - final playerCount = game.players?.length ?? 0; - return '$playerCount Players'; + /// Loads the data for the HomeView from the database. + /// This includes the match count, group count, and recent matches. + Future loadHomeViewData() async { + final db = Provider.of(context, listen: false); + Future.wait([ + db.matchDao.getMatchCount(), + db.groupDao.getGroupCount(), + db.matchDao.getAllMatches(), + Future.delayed(Constants.minimumSkeletonDuration), + ]).then((results) { + matchCount = results[0] as int; + groupCount = results[1] as int; + loadedRecentMatches = results[2] as List; + recentMatches = + (loadedRecentMatches + ..sort((a, b) => b.createdAt.compareTo(a.createdAt))) + .take(2) + .toList(); + if (mounted) { + setState(() { + isLoading = false; + }); + } + }); + } + + /// Updates the winner information for a specific match in the recent matches list. + Future updatedWinnerinRecentMatches(String matchId) async { + final db = Provider.of(context, listen: false); + final winner = await db.matchDao.getWinner(matchId: matchId); + final matchIndex = recentMatches.indexWhere((match) => match.id == matchId); + if (matchIndex != -1) { + setState(() { + recentMatches[matchIndex].winner = winner; + }); } - if (game.players == null || game.players!.isEmpty) { - return game.group!.name; - } - return '${game.group!.name} + ${game.players!.length}'; } } diff --git a/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart b/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart new file mode 100644 index 0000000..5976f72 --- /dev/null +++ b/lib/presentation/views/main_menu/match_view/create_match/choose_game_view.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/core/enums.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart'; +import 'package:game_tracker/presentation/widgets/tiles/title_description_list_tile.dart'; + +class ChooseGameView extends StatefulWidget { + final List<(String, String, Ruleset)> games; + final int initialGameIndex; + + const ChooseGameView({ + super.key, + required this.games, + required this.initialGameIndex, + }); + + @override + State createState() => _ChooseGameViewState(); +} + +class _ChooseGameViewState extends State { + /// Controller for the search bar + final TextEditingController searchBarController = TextEditingController(); + + /// Currently selected game index + late int selectedGameIndex; + + @override + void initState() { + selectedGameIndex = widget.initialGameIndex; + super.initState(); + } + + @override + Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); + return Scaffold( + backgroundColor: CustomTheme.backgroundColor, + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios), + onPressed: () { + Navigator.of(context).pop(selectedGameIndex); + }, + ), + title: Text(loc.choose_game), + ), + body: PopScope( + // This fixes that the Android Back Gesture didn't return the + // selectedGameIndex and therefore the selected Game wasn't saved + canPop: false, + onPopInvokedWithResult: (bool didPop, Object? result) { + if (didPop) { + return; + } + Navigator.of(context).pop(selectedGameIndex); + }, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: CustomSearchBar( + controller: searchBarController, + hintText: loc.game_name, + ), + ), + const SizedBox(height: 5), + Expanded( + child: ListView.builder( + itemCount: widget.games.length, + itemBuilder: (BuildContext context, int index) { + return TitleDescriptionListTile( + title: widget.games[index].$1, + description: widget.games[index].$2, + badgeText: translateRulesetToString( + widget.games[index].$3, + context, + ), + isHighlighted: selectedGameIndex == index, + onPressed: () async { + setState(() { + if (selectedGameIndex == index) { + selectedGameIndex = -1; + } else { + selectedGameIndex = index; + } + }); + }, + ); + }, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart b/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart new file mode 100644 index 0000000..9e34460 --- /dev/null +++ b/lib/presentation/views/main_menu/match_view/create_match/choose_group_view.dart @@ -0,0 +1,153 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart'; +import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart'; +import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; + +class ChooseGroupView extends StatefulWidget { + final List groups; + final String initialGroupId; + + const ChooseGroupView({ + super.key, + required this.groups, + required this.initialGroupId, + }); + + @override + State createState() => _ChooseGroupViewState(); +} + +class _ChooseGroupViewState extends State { + late String selectedGroupId; + final TextEditingController controller = TextEditingController(); + late final List filteredGroups; + + @override + void initState() { + selectedGroupId = widget.initialGroupId; + filteredGroups = [...widget.groups]; + super.initState(); + } + + @override + Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); + return Scaffold( + backgroundColor: CustomTheme.backgroundColor, + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios), + onPressed: () { + Navigator.of(context).pop( + selectedGroupId == '' + ? null + : widget.groups.firstWhere( + (group) => group.id == selectedGroupId, + ), + ); + }, + ), + title: Text(loc.choose_group), + ), + body: PopScope( + // This fixes that the Android Back Gesture didn't return the + // selectedGroupId and therefore the selected Group wasn't saved + canPop: false, + onPopInvokedWithResult: (bool didPop, Object? result) { + if (didPop) { + return; + } + Navigator.of(context).pop( + selectedGroupId == '' + ? null + : widget.groups.firstWhere( + (group) => group.id == selectedGroupId, + ), + ); + }, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: CustomSearchBar( + controller: controller, + hintText: loc.search_for_groups, + onChanged: (value) { + setState(() { + filterGroups(value); + }); + }, + ), + ), + Expanded( + child: Visibility( + visible: filteredGroups.isNotEmpty, + replacement: Visibility( + visible: widget.groups.isNotEmpty, + replacement: TopCenteredMessage( + icon: Icons.info, + title: loc.info, + message: loc.no_groups_created_yet, + ), + child: TopCenteredMessage( + icon: Icons.info, + title: loc.info, + message: AppLocalizations.of( + context, + ).there_is_no_group_matching_your_search, + ), + ), + child: ListView.builder( + padding: const EdgeInsets.only(bottom: 85), + itemCount: filteredGroups.length, + itemBuilder: (BuildContext context, int index) { + return GestureDetector( + onTap: () { + setState(() { + if (selectedGroupId != filteredGroups[index].id) { + selectedGroupId = filteredGroups[index].id; + } else { + selectedGroupId = ''; + } + }); + }, + child: GroupTile( + group: filteredGroups[index], + isHighlighted: + selectedGroupId == filteredGroups[index].id, + ), + ); + }, + ), + ), + ), + ], + ), + ), + ); + } + + /// Filters the groups based on the search [query]. + void filterGroups(String query) { + setState(() { + if (query.isEmpty) { + filteredGroups.clear(); + filteredGroups.addAll(widget.groups); + } else { + filteredGroups.clear(); + filteredGroups.addAll( + widget.groups.where( + (group) => + group.name.toLowerCase().contains(query.toLowerCase()) || + group.members.any( + (player) => player.name.toLowerCase().contains(query.toLowerCase()), + ), + ), + ); + } + }); + } +} diff --git a/lib/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart b/lib/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart new file mode 100644 index 0000000..ca021af --- /dev/null +++ b/lib/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/core/enums.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/widgets/tiles/title_description_list_tile.dart'; + +class ChooseRulesetView extends StatefulWidget { + final List<(Ruleset, String)> rulesets; + final int initialRulesetIndex; + + const ChooseRulesetView({ + super.key, + required this.rulesets, + required this.initialRulesetIndex, + }); + + @override + State createState() => _ChooseRulesetViewState(); +} + +class _ChooseRulesetViewState extends State { + /// Currently selected ruleset index + late int selectedRulesetIndex; + + @override + void initState() { + selectedRulesetIndex = widget.initialRulesetIndex; + super.initState(); + } + + @override + Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); + return DefaultTabController( + length: 2, + initialIndex: 0, + child: Scaffold( + backgroundColor: CustomTheme.backgroundColor, + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios), + onPressed: () { + Navigator.of(context).pop( + selectedRulesetIndex == -1 + ? null + : widget.rulesets[selectedRulesetIndex].$1, + ); + }, + ), + title: Text(loc.choose_ruleset), + ), + body: PopScope( + // This fixes that the Android Back Gesture didn't return the + // selectedRulesetIndex and therefore the selected Ruleset wasn't saved + canPop: false, + onPopInvokedWithResult: (bool didPop, Object? result) { + if (didPop) { + return; + } + Navigator.of(context).pop( + selectedRulesetIndex == -1 + ? null + : widget.rulesets[selectedRulesetIndex].$1, + ); + }, + child: ListView.builder( + padding: const EdgeInsets.only(bottom: 85), + itemCount: widget.rulesets.length, + itemBuilder: (BuildContext context, int index) { + return TitleDescriptionListTile( + onPressed: () async { + setState(() { + if (selectedRulesetIndex == index) { + selectedRulesetIndex = -1; + } else { + selectedRulesetIndex = index; + } + }); + }, + title: translateRulesetToString( + widget.rulesets[index].$1, + context, + ), + description: widget.rulesets[index].$2, + isHighlighted: selectedRulesetIndex == index, + ); + }, + ), + ), + ), + ); + } +} diff --git a/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart new file mode 100644 index 0000000..b9885a4 --- /dev/null +++ b/lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart @@ -0,0 +1,273 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/adaptive_page_route.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/core/enums.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/match.dart'; +import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_game_view.dart'; +import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_group_view.dart'; +import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart'; +import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart'; +import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; +import 'package:game_tracker/presentation/widgets/player_selection.dart'; +import 'package:game_tracker/presentation/widgets/text_input/text_input_field.dart'; +import 'package:game_tracker/presentation/widgets/tiles/choose_tile.dart'; +import 'package:provider/provider.dart'; + +class CreateMatchView extends StatefulWidget { + final VoidCallback? onWinnerChanged; + const CreateMatchView({super.key, this.onWinnerChanged}); + + @override + State createState() => _CreateMatchViewState(); +} + +class _CreateMatchViewState extends State { + late final AppDatabase db; + + /// Controller for the match name input field + final TextEditingController _matchNameController = TextEditingController(); + + /// Hint text for the match name input field + String? hintText; + + /// List of all groups from the database + List groupsList = []; + + /// List of all players from the database + List playerList = []; + + /// List of players filtered based on the selected group + /// If a group is selected, this list contains all players from [playerList] + /// who are not members of the selected group. If no group is selected, + /// this list is identical to [playerList]. + List filteredPlayerList = []; + + /// The currently selected group + Group? selectedGroup; + + /// The index of the currently selected group in [groupsList] to mark it in + /// the [ChooseGroupView] + String selectedGroupId = ''; + + /// The currently selected ruleset + Ruleset? selectedRuleset; + + /// The index of the currently selected ruleset in [rulesets] to mark it in + /// the [ChooseRulesetView] + int selectedRulesetIndex = -1; + + /// The index of the currently selected game in [games] to mark it in + /// the [ChooseGameView] + int selectedGameIndex = -1; + + /// The currently selected players + List? selectedPlayers; + + /// List of available rulesets with their localized string representations + late final List<(Ruleset, String)> _rulesets; + + @override + void initState() { + super.initState(); + _matchNameController.addListener(() { + setState(() {}); + }); + + db = Provider.of(context, listen: false); + + Future.wait([ + db.groupDao.getAllGroups(), + db.playerDao.getAllPlayers(), + ]).then((result) async { + groupsList = result[0] as List; + playerList = result[1] as List; + setState(() { + filteredPlayerList = List.from(playerList); + }); + }); + } + + @override + void dispose() { + _matchNameController.dispose(); + super.dispose(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final loc = AppLocalizations.of(context); + hintText ??= loc.match_name; + _rulesets = [ + (Ruleset.singleWinner, loc.ruleset_single_winner), + (Ruleset.singleLoser, loc.ruleset_single_loser), + (Ruleset.mostPoints, loc.ruleset_most_points), + (Ruleset.leastPoints, loc.ruleset_least_points), + ]; + } + + // TODO: Replace when games are implemented + List<(String, String, Ruleset)> games = [ + ('Example Game 1', 'This is a description', Ruleset.leastPoints), + ('Example Game 2', '', Ruleset.singleWinner), + ]; + + @override + Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); + return ScaffoldMessenger( + child: Scaffold( + backgroundColor: CustomTheme.backgroundColor, + appBar: AppBar(title: Text(loc.create_new_match)), + body: SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + margin: CustomTheme.tileMargin, + child: TextInputField( + controller: _matchNameController, + hintText: hintText ?? '', + ), + ), + ChooseTile( + title: loc.game, + trailingText: selectedGameIndex == -1 + ? loc.none + : games[selectedGameIndex].$1, + onPressed: () async { + selectedGameIndex = await Navigator.of(context).push( + adaptivePageRoute( + builder: (context) => ChooseGameView( + games: games, + initialGameIndex: selectedGameIndex, + ), + ), + ); + setState(() { + if (selectedGameIndex != -1) { + hintText = games[selectedGameIndex].$1; + selectedRuleset = games[selectedGameIndex].$3; + selectedRulesetIndex = _rulesets.indexWhere( + (r) => r.$1 == selectedRuleset, + ); + } else { + hintText = loc.match_name; + selectedRuleset = null; + } + }); + }, + ), + ChooseTile( + title: loc.ruleset, + trailingText: selectedRuleset == null + ? loc.none + : translateRulesetToString(selectedRuleset!, context), + onPressed: () async { + selectedRuleset = await Navigator.of(context).push( + adaptivePageRoute( + builder: (context) => ChooseRulesetView( + rulesets: _rulesets, + initialRulesetIndex: selectedRulesetIndex, + ), + ), + ); + if (!mounted) return; + selectedRulesetIndex = _rulesets.indexWhere( + (r) => r.$1 == selectedRuleset, + ); + selectedGameIndex = -1; + setState(() {}); + }, + ), + ChooseTile( + title: loc.group, + trailingText: selectedGroup == null + ? loc.none_group + : selectedGroup!.name, + onPressed: () async { + selectedGroup = await Navigator.of(context).push( + adaptivePageRoute( + builder: (context) => ChooseGroupView( + groups: groupsList, + initialGroupId: selectedGroupId, + ), + ), + ); + selectedGroupId = selectedGroup?.id ?? ''; + if (selectedGroup != null) { + filteredPlayerList = playerList + .where( + (p) => !selectedGroup!.members.any((m) => m.id == p.id), + ) + .toList(); + } else { + filteredPlayerList = List.from(playerList); + } + setState(() {}); + }, + ), + Expanded( + child: PlayerSelection( + key: ValueKey(selectedGroup?.id ?? 'no_group'), + initialSelectedPlayers: selectedPlayers ?? [], + availablePlayers: filteredPlayerList, + onChanged: (value) { + setState(() { + selectedPlayers = value; + }); + }, + ), + ), + CustomWidthButton( + text: loc.create_match, + sizeRelativeToWidth: 0.95, + buttonType: ButtonType.primary, + onPressed: _enableCreateGameButton() + ? () async { + Match match = Match( + name: _matchNameController.text.isEmpty + ? (hintText ?? '') + : _matchNameController.text.trim(), + createdAt: DateTime.now(), + group: selectedGroup, + players: selectedPlayers, + ); + await db.matchDao.addMatch(match: match); + if (context.mounted) { + Navigator.pushReplacement( + context, + adaptivePageRoute( + fullscreenDialog: true, + builder: (context) => MatchResultView( + match: match, + onWinnerChanged: widget.onWinnerChanged, + ), + ), + ); + } + } + : null, + ), + ], + ), + ), + ), + ); + } + + /// Determines whether the "Create Match" button should be enabled. + /// + /// Returns `true` if: + /// - A ruleset is selected AND + /// - Either a group is selected OR at least 2 players are selected + bool _enableCreateGameButton() { + return (selectedGroup != null || + (selectedPlayers != null && selectedPlayers!.length > 1)) && + selectedRuleset != null; + } +} diff --git a/lib/presentation/views/main_menu/game_result_view.dart b/lib/presentation/views/main_menu/match_view/match_result_view.dart similarity index 65% rename from lib/presentation/views/main_menu/game_result_view.dart rename to lib/presentation/views/main_menu/match_view/match_result_view.dart index f13553b..0d624f0 100644 --- a/lib/presentation/views/main_menu/game_result_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_result_view.dart @@ -1,32 +1,38 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/game.dart'; +import 'package:game_tracker/data/dto/match.dart'; import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/widgets/tiles/custom_radio_list_tile.dart'; import 'package:provider/provider.dart'; -class GameResultView extends StatefulWidget { - final Game game; +class MatchResultView extends StatefulWidget { + final Match match; - const GameResultView({super.key, required this.game}); + final VoidCallback? onWinnerChanged; + const MatchResultView({super.key, required this.match, this.onWinnerChanged}); @override - State createState() => _GameResultViewState(); + State createState() => _MatchResultViewState(); } -class _GameResultViewState extends State { - late final List allPlayers; +class _MatchResultViewState extends State { late final AppDatabase db; + + /// List of all players who participated in the match + late final List allPlayers; + + /// Currently selected winner player Player? _selectedPlayer; @override void initState() { db = Provider.of(context, listen: false); - allPlayers = getAllPlayers(widget.game); - if (widget.game.winner != null) { + allPlayers = getAllPlayers(widget.match); + if (widget.match.winner != null) { _selectedPlayer = allPlayers.firstWhere( - (p) => p.id == widget.game.winner!.id, + (p) => p.id == widget.match.winner!.id, ); } super.initState(); @@ -34,20 +40,18 @@ class _GameResultViewState extends State { @override Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); return Scaffold( backgroundColor: CustomTheme.backgroundColor, appBar: AppBar( - backgroundColor: CustomTheme.backgroundColor, - scrolledUnderElevation: 0, - title: Text( - widget.game.name, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - overflow: TextOverflow.ellipsis, - ), + leading: IconButton( + icon: const Icon(Icons.close), + onPressed: () { + widget.onWinnerChanged?.call(); + Navigator.of(context).pop(); + }, ), - centerTitle: true, + title: Text(widget.match.name), ), body: SafeArea( child: Column( @@ -71,9 +75,9 @@ class _GameResultViewState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - 'Select Winner:', - style: TextStyle( + Text( + loc.select_winner, + style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), @@ -122,23 +126,36 @@ class _GameResultViewState extends State { ); } + /// Handles saving or removing the winner in the database + /// based on the current selection. Future _handleWinnerSaving() async { if (_selectedPlayer == null) { - await db.gameDao.removeWinner(gameId: widget.game.id); + await db.matchDao.removeWinner(matchId: widget.match.id); } else { - await db.gameDao.setWinner( - gameId: widget.game.id, + await db.matchDao.setWinner( + matchId: widget.match.id, winnerId: _selectedPlayer!.id, ); } + widget.onWinnerChanged?.call(); } - List getAllPlayers(Game game) { - if (game.group == null && game.players != null) { - return [...game.players!]; - } else if (game.group != null && game.players != null) { - return [...game.players!, ...game.group!.members]; + /// Retrieves all players associated with the given [match]. + /// This includes players directly assigned to the match + /// as well as members of the group (if any). + /// The returned list is sorted alphabetically by player name. + List getAllPlayers(Match match) { + List players = []; + + if (match.group == null && match.players != null) { + players = [...match.players!]; + } else if (match.group != null && match.players != null) { + players = [...match.players!, ...match.group!.members]; + } else { + players = [...match.group!.members]; } - return [...game.group!.members]; + + players.sort((a, b) => a.name.compareTo(b.name)); + return players; } } diff --git a/lib/presentation/views/main_menu/match_view/match_view.dart b/lib/presentation/views/main_menu/match_view/match_view.dart new file mode 100644 index 0000000..ecfa9ca --- /dev/null +++ b/lib/presentation/views/main_menu/match_view/match_view.dart @@ -0,0 +1,143 @@ +import 'dart:core' hide Match; + +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/adaptive_page_route.dart'; +import 'package:game_tracker/core/constants.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/match.dart'; +import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/create_match_view.dart'; +import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart'; +import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; +import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; +import 'package:game_tracker/presentation/widgets/tiles/match_tile.dart'; +import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; +import 'package:provider/provider.dart'; + +class MatchView extends StatefulWidget { + const MatchView({super.key}); + + @override + State createState() => _MatchViewState(); +} + +class _MatchViewState extends State { + late final AppDatabase db; + bool isLoading = true; + + /// Loaded matches from the database, + /// initially filled with skeleton matches + List matches = List.filled( + 4, + Match( + name: 'Skeleton match name', + group: Group( + name: 'Group name', + members: List.filled(5, Player(name: 'Player')), + ), + winner: Player(name: 'Player'), + players: [Player(name: 'Player')], + ), + ); + + @override + void initState() { + super.initState(); + db = Provider.of(context, listen: false); + loadGames(); + } + + @override + Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); + return Scaffold( + backgroundColor: CustomTheme.backgroundColor, + body: Stack( + alignment: Alignment.center, + children: [ + AppSkeleton( + enabled: isLoading, + child: Visibility( + visible: matches.isNotEmpty, + replacement: Center( + child: TopCenteredMessage( + icon: Icons.report, + title: loc.info, + message: loc.no_matches_created_yet, + ), + ), + child: ListView.builder( + padding: const EdgeInsets.only(bottom: 85), + itemCount: matches.length + 1, + itemBuilder: (BuildContext context, int index) { + if (index == matches.length) { + return SizedBox( + height: MediaQuery.paddingOf(context).bottom - 20, + ); + } + return Center( + child: Padding( + padding: const EdgeInsets.only(bottom: 12.0), + child: MatchTile( + width: MediaQuery.sizeOf(context).width * 0.95, + onTap: () async { + Navigator.push( + context, + adaptivePageRoute( + fullscreenDialog: true, + builder: (context) => MatchResultView( + match: matches[index], + onWinnerChanged: loadGames, + ), + ), + ); + }, + match: matches[index], + ), + ), + ); + }, + ), + ), + ), + Positioned( + bottom: MediaQuery.paddingOf(context).bottom, + child: CustomWidthButton( + text: loc.create_match, + sizeRelativeToWidth: 0.90, + onPressed: () async { + Navigator.push( + context, + adaptivePageRoute( + builder: (context) => + CreateMatchView(onWinnerChanged: loadGames), + ), + ); + }, + ), + ), + ], + ), + ); + } + + /// Loads the games from the database and sorts them by creation date. + void loadGames() { + Future.wait([ + db.matchDao.getAllMatches(), + Future.delayed(Constants.minimumSkeletonDuration), + ]).then((results) { + if (mounted) { + setState(() { + final loadedMatches = results[0] as List; + matches = loadedMatches + ..sort((a, b) => b.createdAt.compareTo(a.createdAt)); + isLoading = false; + }); + } + }); + } +} diff --git a/lib/presentation/views/main_menu/settings_view.dart b/lib/presentation/views/main_menu/settings_view.dart deleted file mode 100644 index 6ebb7fb..0000000 --- a/lib/presentation/views/main_menu/settings_view.dart +++ /dev/null @@ -1,191 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/core/enums.dart'; -import 'package:game_tracker/presentation/widgets/tiles/settings_list_tile.dart'; -import 'package:game_tracker/services/data_transfer_service.dart'; - -class SettingsView extends StatefulWidget { - const SettingsView({super.key}); - - @override - State createState() => _SettingsViewState(); -} - -class _SettingsViewState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(backgroundColor: CustomTheme.backgroundColor), - backgroundColor: CustomTheme.backgroundColor, - body: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) => - SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Padding( - padding: EdgeInsets.fromLTRB(24, 0, 24, 10), - child: Text( - textAlign: TextAlign.start, - 'Menu', - style: TextStyle( - fontSize: 28, - fontWeight: FontWeight.bold, - ), - ), - ), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 24, vertical: 10), - child: Text( - textAlign: TextAlign.start, - 'Settings', - style: TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - ), - ), - ), - SettingsListTile( - title: 'Export data', - icon: Icons.upload_outlined, - suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), - onPressed: () async { - final String json = - await DataTransferService.getAppDataAsJson(context); - final result = await DataTransferService.exportData( - json, - 'game_tracker-data', - ); - if (!context.mounted) return; - showExportSnackBar(context: context, result: result); - }, - ), - SettingsListTile( - title: 'Import data', - icon: Icons.download_outlined, - suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), - onPressed: () async { - final result = await DataTransferService.importData( - context, - ); - if (!context.mounted) return; - showImportSnackBar(context: context, result: result); - }, - ), - SettingsListTile( - title: 'Delete all data', - icon: Icons.download_outlined, - suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), - onPressed: () { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('Delete all data?'), - content: const Text('This can\'t be undone'), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(false), - child: const Text('Abbrechen'), - ), - TextButton( - onPressed: () => Navigator.of(context).pop(true), - child: const Text('Löschen'), - ), - ], - ), - ).then((confirmed) { - if (confirmed == true && context.mounted) { - DataTransferService.deleteAllData(context); - showSnackbar( - context: context, - message: 'Daten erfolgreich gelöscht', - ); - } - }); - }, - ), - ], - ), - ), - ), - ); - } - - /// Displays a snackbar based on the import result. - /// - /// [context] The BuildContext to show the snackbar in. - /// [result] The result of the import operation. - void showImportSnackBar({ - required BuildContext context, - required ImportResult result, - }) { - switch (result) { - case ImportResult.success: - showSnackbar(context: context, message: 'Data successfully imported'); - case ImportResult.invalidSchema: - showSnackbar(context: context, message: 'Invalid Schema'); - case ImportResult.fileReadError: - showSnackbar(context: context, message: 'Error reading file'); - case ImportResult.canceled: - showSnackbar(context: context, message: 'Import canceled'); - case ImportResult.formatException: - showSnackbar( - context: context, - message: 'Format Exception (see console)', - ); - case ImportResult.unknownException: - showSnackbar( - context: context, - message: 'Unknown Exception (see console)', - ); - } - } - - /// Displays a snackbar based on the export result. - /// - /// [context] The BuildContext to show the snackbar in. - /// [result] The result of the export operation. - void showExportSnackBar({ - required BuildContext context, - required ExportResult result, - }) { - switch (result) { - case ExportResult.success: - showSnackbar(context: context, message: 'Data successfully exported'); - case ExportResult.canceled: - showSnackbar(context: context, message: 'Export canceled'); - case ExportResult.unknownException: - showSnackbar( - context: context, - message: 'Unknown Exception (see console)', - ); - } - } - - /// Displays a snackbar with the given message and optional action. - /// - /// [context] The BuildContext to show the snackbar in. - /// [message] The message to display in the snackbar. - /// [duration] The duration for which the snackbar is displayed. - /// [action] An optional callback function to execute when the action button is pressed. - void showSnackbar({ - required BuildContext context, - required String message, - Duration duration = const Duration(seconds: 3), - VoidCallback? action, - }) { - final messenger = ScaffoldMessenger.of(context); - messenger.hideCurrentSnackBar(); - messenger.showSnackBar( - SnackBar( - content: Text(message, style: const TextStyle(color: Colors.white)), - backgroundColor: CustomTheme.onBoxColor, - duration: duration, - action: action != null - ? SnackBarAction(label: 'Rückgängig', onPressed: action) - : null, - ), - ); - } -} diff --git a/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart b/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart new file mode 100644 index 0000000..02c3adf --- /dev/null +++ b/lib/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart @@ -0,0 +1,137 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class LicenseDetailView extends StatelessWidget { + final Package package; + + const LicenseDetailView({super.key, required this.package}); + + @override + Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); + + return Scaffold( + appBar: AppBar(title: const Text('Lizenzdetails')), + body: SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + margin: const EdgeInsetsGeometry.only(right: 15), + width: 60, + height: 60, + decoration: BoxDecoration( + color: CustomTheme.primaryColor.withAlpha(40), + borderRadius: BorderRadius.circular(10), + ), + child: Icon( + Icons.description, + color: CustomTheme.primaryColor, + size: 30, + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + package.name, + textAlign: TextAlign.left, + style: const TextStyle( + height: 0, + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + if (package.version != null) ...[ + Text( + 'Version ${package.version}', + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade300, + ), + ), + ], + ], + ), + ], + ), + + if (package.authors.isNotEmpty) ...[ + const SizedBox(height: 8), + SelectableText( + package.authors.join(', '), + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade500, + ), + ), + ], + if (package.homepage != null && + package.homepage!.isNotEmpty) ...[ + const SizedBox(height: 8), + GestureDetector( + onTap: () async { + final uri = Uri.parse(package.homepage!); + await launchUrl(uri, mode: LaunchMode.platformDefault); + }, + child: SizedBox( + width: 300, + child: Text( + package.homepage!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + color: CustomTheme.secondaryColor, + decoration: TextDecoration.underline, + decorationColor: CustomTheme.secondaryColor, + ), + ), + ), + ), + ], + ], + ), + ), + const SizedBox(height: 20), + Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16), + decoration: CustomTheme.standardBoxDecoration, + child: (package.license != null && package.license!.isNotEmpty) + ? SelectableText( + package.license!, + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade300, + height: 1.5, + fontFamily: 'monospace', + ), + ) + : Center( + heightFactor: 25, + child: Text( + loc.no_license_text_available, + style: TextStyle(color: Colors.grey.shade500), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart b/lib/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart new file mode 100644 index 0000000..ef1109c --- /dev/null +++ b/lib/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart @@ -0,0 +1,7306 @@ +// dart format off +// cSpell:disable +// ignore_for_file: always_put_required_named_parameters_first +// ignore_for_file: constant_identifier_names +// ignore_for_file: sort_constructors_first + +// This code was generated by dart_pubspec_licenses +// https://pub.dev/packages/dart_pubspec_licenses + +/// This package. +const thisPackage = _game_tracker; + +/// All dependencies including transitive dependencies. +const allDependencies = [ + __fe_analyzer_shared, + _analyzer, + _args, + _async, + _boolean_selector, + _build, + _build_config, + _build_daemon, + _build_resolvers, + _build_runner, + _build_runner_core, + _built_collection, + _built_value, + _characters, + _charcode, + _checked_yaml, + _cli_config, + _cli_util, + _clock, + _code_builder, + _collection, + _convert, + _coverage, + _cross_file, + _crypto, + _csslib, + _cupertino_icons, + _dart_pubspec_licenses, + _dart_style, + _dbus, + _dio, + _dio_web_adapter, + _drift, + _drift_dev, + _drift_flutter, + _fake_async, + _ffi, + _file, + _file_picker, + _file_saver, + _fixnum, + _flutter, + _flutter_lints, + _flutter_plugin_android_lifecycle, + _flutter_web_plugins, + _font_awesome_flutter, + _frontend_server_client, + _glob, + _graphs, + _html, + _http, + _http_multi_server, + _http_parser, + _intl, + _io, + _js, + _json_annotation, + _json_schema, + _leak_tracker, + _leak_tracker_flutter_testing, + _leak_tracker_testing, + _lints, + _logging, + _markdown, + _matcher, + _material_color_utilities, + _meta, + _mime, + _nested, + _node_preamble, + _package_config, + _package_info_plus, + _package_info_plus_platform_interface, + _pana, + _path, + _path_provider, + _path_provider_android, + _path_provider_foundation, + _path_provider_linux, + _path_provider_platform_interface, + _path_provider_windows, + _petitparser, + _platform, + _plugin_platform_interface, + _pool, + _provider, + _pub_semver, + _pubspec_parse, + _quiver, + _recase, + _retry, + _rfc_6901, + _safe_url_check, + _shelf, + _shelf_packages_handler, + _shelf_static, + _shelf_web_socket, + _skeletonizer, + _source_gen, + _source_map_stack_trace, + _source_maps, + _source_span, + _sqlite3, + _sqlite3_flutter_libs, + _sqlparser, + _stack_trace, + _stream_channel, + _stream_transform, + _string_scanner, + _tar, + _term_glyph, + _test, + _test_api, + _test_core, + _timing, + _typed_data, + _uri, + _url_launcher, + _url_launcher_android, + _url_launcher_ios, + _url_launcher_linux, + _url_launcher_macos, + _url_launcher_platform_interface, + _url_launcher_web, + _url_launcher_windows, + _uuid, + _vector_math, + _vm_service, + _watcher, + _web, + _web_socket, + _web_socket_channel, + _webkit_inspection_protocol, + _win32, + _xdg_directories, + _xml, + _yaml +]; + +/// Direct `dependencies`. +const dependencies = [ + _flutter, + _clock, + _cupertino_icons, + _drift, + _drift_flutter, + _file_picker, + _file_saver, + _font_awesome_flutter, + _intl, + _json_schema, + _package_info_plus, + _path_provider, + _provider, + _skeletonizer, + _url_launcher, + _uuid +]; + +/// Direct `dev_dependencies`. +const devDependencies = [ + _build_runner, + _dart_pubspec_licenses, + _drift_dev, + _flutter_lints +]; + +/// Package license definition. +class Package { + /// Package name + final String name; + /// Description + final String description; + /// Authors + final List authors; + /// Whether the license is in markdown format or not (plain text). + final bool isMarkdown; + /// Whether the package is included in the SDK or not. + final bool isSdk; + /// Direct dependencies + final List dependencies; + /// Direct devDependencies + final List devDependencies; + /// Website URL + final String? homepage; + /// Repository URL + final String? repository; + /// Version + final String? version; + /// License + final String? license; + /// The [SPDX](https://spdx.org/licenses/) license identifiers, if detected. + final List spdxIdentifiers; + + const Package({ + required this.name, + required this.description, + required this.authors, + required this.isMarkdown, + required this.isSdk, + required this.dependencies, + required this.devDependencies, + this.homepage, + this.repository, + this.version, + this.license, + this.spdxIdentifiers = const [], + }); +} + +class PackageRef { + final String name; + + const PackageRef(this.name); + + Package resolve() => allDependencies.firstWhere((d) => d.name == name); +} + +/// _fe_analyzer_shared 85.0.0 +const __fe_analyzer_shared = Package( + name: '_fe_analyzer_shared', + description: 'Logic that is shared between the front_end and analyzer packages.', + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/_fe_analyzer_shared', + authors: [], + version: '85.0.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('meta')], + devDependencies: [PackageRef('collection'), PackageRef('test')], + license: '''Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// analyzer 7.7.1 +const _analyzer = Package( + name: 'analyzer', + description: 'This package provides a library that performs static analysis of Dart code.', + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/analyzer', + authors: [], + version: '7.7.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('_fe_analyzer_shared'), PackageRef('collection'), PackageRef('convert'), PackageRef('crypto'), PackageRef('glob'), PackageRef('meta'), PackageRef('package_config'), PackageRef('path'), PackageRef('pub_semver'), PackageRef('source_span'), PackageRef('watcher'), PackageRef('yaml')], + devDependencies: [PackageRef('args'), PackageRef('async'), PackageRef('lints'), PackageRef('matcher'), PackageRef('test'), PackageRef('vm_service')], + license: '''Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// args 2.7.0 +const _args = Package( + name: 'args', + description: 'Library for defining parsers for parsing raw command-line arguments into a set of options and values using GNU and POSIX style options.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/args', + authors: [], + version: '2.7.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test')], + license: '''Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// async 2.13.0 +const _async = Package( + name: 'async', + description: "Utility functions and classes related to the 'dart:async' library.", + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/async', + authors: [], + version: '2.13.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('collection'), PackageRef('meta')], + devDependencies: [PackageRef('fake_async'), PackageRef('stack_trace'), PackageRef('test')], + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// boolean_selector 2.1.2 +const _boolean_selector = Package( + name: 'boolean_selector', + description: "A flexible syntax for boolean expressions, based on a simplified version of Dart's expression syntax.", + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/boolean_selector', + authors: [], + version: '2.1.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('source_span'), PackageRef('string_scanner')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// build 3.1.0 +const _build = Package( + name: 'build', + description: 'A package for authoring build_runner compatible code generators.', + repository: 'https://github.com/dart-lang/build/tree/master/build', + authors: [], + version: '3.1.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('analyzer'), PackageRef('async'), PackageRef('build_runner_core'), PackageRef('convert'), PackageRef('crypto'), PackageRef('glob'), PackageRef('logging'), PackageRef('package_config'), PackageRef('path')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// build_config 1.2.0 +const _build_config = Package( + name: 'build_config', + description: 'Format definition and support for parsing `build.yaml` configuration.', + repository: 'https://github.com/dart-lang/build/tree/master/build_config', + authors: [], + version: '1.2.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('checked_yaml'), PackageRef('json_annotation'), PackageRef('path'), PackageRef('pubspec_parse')], + devDependencies: [PackageRef('build_runner'), PackageRef('term_glyph'), PackageRef('test')], + license: '''Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// build_daemon 4.1.0 +const _build_daemon = Package( + name: 'build_daemon', + description: 'A daemon for running Dart builds.', + repository: 'https://github.com/dart-lang/build/tree/master/build_daemon', + authors: [], + version: '4.1.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('built_collection'), PackageRef('built_value'), PackageRef('crypto'), PackageRef('http_multi_server'), PackageRef('logging'), PackageRef('path'), PackageRef('pool'), PackageRef('shelf'), PackageRef('shelf_web_socket'), PackageRef('stream_transform'), PackageRef('watcher'), PackageRef('web_socket_channel')], + devDependencies: [PackageRef('build_runner'), PackageRef('test')], + license: '''Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// build_resolvers 3.0.3 +const _build_resolvers = Package( + name: 'build_resolvers', + description: 'Resolve Dart code in a Builder', + repository: 'https://github.com/dart-lang/build/tree/master/build_resolvers', + authors: [], + version: '3.0.3', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('analyzer'), PackageRef('async'), PackageRef('build'), PackageRef('build_runner_core'), PackageRef('collection'), PackageRef('package_config'), PackageRef('path'), PackageRef('pool'), PackageRef('pub_semver')], + devDependencies: [PackageRef('logging'), PackageRef('test')], + license: '''Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// build_runner 2.7.1 +const _build_runner = Package( + name: 'build_runner', + description: 'A build system for Dart code generation and modular compilation.', + repository: 'https://github.com/dart-lang/build/tree/master/build_runner', + authors: [], + version: '2.7.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('args'), PackageRef('async'), PackageRef('build'), PackageRef('build_config'), PackageRef('build_daemon'), PackageRef('build_runner_core'), PackageRef('built_collection'), PackageRef('code_builder'), PackageRef('crypto'), PackageRef('dart_style'), PackageRef('frontend_server_client'), PackageRef('glob'), PackageRef('graphs'), PackageRef('http_multi_server'), PackageRef('io'), PackageRef('logging'), PackageRef('meta'), PackageRef('mime'), PackageRef('path'), PackageRef('pub_semver'), PackageRef('shelf'), PackageRef('shelf_web_socket'), PackageRef('stack_trace'), PackageRef('stream_transform'), PackageRef('watcher'), PackageRef('web_socket_channel'), PackageRef('yaml')], + devDependencies: [PackageRef('http'), PackageRef('package_config'), PackageRef('stream_channel'), PackageRef('test'), PackageRef('web')], + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// build_runner_core 9.3.1 +const _build_runner_core = Package( + name: 'build_runner_core', + description: 'Core tools to organize the structure of a build and run Builders.', + repository: 'https://github.com/dart-lang/build/tree/master/build_runner_core', + authors: [], + version: '9.3.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('analyzer'), PackageRef('async'), PackageRef('build'), PackageRef('build_config'), PackageRef('build_resolvers'), PackageRef('build_runner'), PackageRef('built_collection'), PackageRef('built_value'), PackageRef('collection'), PackageRef('convert'), PackageRef('crypto'), PackageRef('glob'), PackageRef('graphs'), PackageRef('json_annotation'), PackageRef('logging'), PackageRef('meta'), PackageRef('package_config'), PackageRef('path'), PackageRef('pool'), PackageRef('timing'), PackageRef('watcher'), PackageRef('yaml')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// built_collection 5.1.1 +const _built_collection = Package( + name: 'built_collection', + description: '''Immutable collections based on the SDK collections. Each SDK collection class is split into a new immutable collection class and a corresponding mutable builder class. +''', + homepage: 'https://github.com/google/built_collection.dart', + authors: [], + version: '5.1.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test')], + license: '''Copyright 2015, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// built_value 8.12.0 +const _built_value = Package( + name: 'built_value', + description: '''Value types with builders, Dart classes as enums, and serialization. This library is the runtime dependency. +''', + repository: 'https://github.com/google/built_value.dart/tree/master/built_value', + authors: [], + version: '8.12.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('built_collection'), PackageRef('collection'), PackageRef('fixnum'), PackageRef('meta')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2015, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// characters 1.4.0 +const _characters = Package( + name: 'characters', + description: 'String replacement with operations that are Unicode/grapheme cluster aware.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/characters', + authors: [], + version: '1.4.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test')], + license: '''Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// charcode 1.4.0 +const _charcode = Package( + name: 'charcode', + description: 'Constants for ASCII and common non-ASCII character codes. Integer constants corresponding to the code points of individual characters.', + repository: 'https://github.com/lrhn/charcode', + authors: [], + version: '1.4.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test'), PackageRef('lints')], + license: '''Copyright 2014, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// checked_yaml 2.0.4 +const _checked_yaml = Package( + name: 'checked_yaml', + description: 'Generate more helpful exceptions when decoding YAML documents using package:json_serializable and package:yaml.', + repository: 'https://github.com/google/json_serializable.dart/tree/master/checked_yaml', + authors: [], + version: '2.0.4', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('json_annotation'), PackageRef('source_span'), PackageRef('yaml')], + devDependencies: [PackageRef('build_runner'), PackageRef('path'), PackageRef('test')], + license: '''Copyright 2019, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// cli_config 0.2.0 +const _cli_config = Package( + name: 'cli_config', + description: 'A library to take config values from configuration files, CLI arguments, and environment variables.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/cli_config', + authors: [], + version: '0.2.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('args'), PackageRef('yaml')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2023, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// cli_util 0.4.2 +const _cli_util = Package( + name: 'cli_util', + description: 'A library to help in building Dart command-line apps.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/cli_util', + authors: [], + version: '0.4.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('meta'), PackageRef('path')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// clock 1.1.2 +const _clock = Package( + name: 'clock', + description: 'A fakeable wrapper for dart:core clock APIs.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/clock', + authors: [], + version: '1.1.2', + spdxIdentifiers: ['Apache-2.0'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test')], + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + ); + +/// code_builder 4.11.0 +const _code_builder = Package( + name: 'code_builder', + description: 'A fluent, builder-based library for generating valid Dart code.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/code_builder', + authors: [], + version: '4.11.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('built_collection'), PackageRef('built_value'), PackageRef('collection'), PackageRef('matcher'), PackageRef('meta')], + devDependencies: [PackageRef('build'), PackageRef('build_runner'), PackageRef('dart_style'), PackageRef('source_gen'), PackageRef('test')], + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// collection 1.19.1 +const _collection = Package( + name: 'collection', + description: 'Collections and utilities functions and classes related to collections.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/collection', + authors: [], + version: '1.19.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test')], + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// convert 3.1.2 +const _convert = Package( + name: 'convert', + description: 'Utilities for converting between data representations. Provides a number of Sink, Codec, Decoder, and Encoder types.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/convert', + authors: [], + version: '3.1.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('typed_data')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// coverage 1.15.0 +const _coverage = Package( + name: 'coverage', + description: 'Coverage data manipulation and formatting', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/coverage', + authors: [], + version: '1.15.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('args'), PackageRef('cli_config'), PackageRef('glob'), PackageRef('logging'), PackageRef('meta'), PackageRef('package_config'), PackageRef('path'), PackageRef('source_maps'), PackageRef('stack_trace'), PackageRef('vm_service'), PackageRef('yaml')], + devDependencies: [PackageRef('build_runner'), PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// cross_file 0.3.5+1 +const _cross_file = Package( + name: 'cross_file', + description: 'An abstraction to allow working with files across multiple platforms.', + repository: 'https://github.com/flutter/packages/tree/main/packages/cross_file', + authors: [], + version: '0.3.5+1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('meta'), PackageRef('web')], + devDependencies: [PackageRef('path'), PackageRef('test')], + license: '''Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// crypto 3.0.7 +const _crypto = Package( + name: 'crypto', + description: 'Implementations of SHA, MD5, and HMAC cryptographic functions.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/crypto', + authors: [], + version: '3.0.7', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('typed_data')], + devDependencies: [PackageRef('convert'), PackageRef('test')], + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// csslib 1.0.2 +const _csslib = Package( + name: 'csslib', + description: 'A library for parsing and analyzing CSS (Cascading Style Sheets).', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/csslib', + authors: [], + version: '1.0.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('source_span')], + devDependencies: [PackageRef('path'), PackageRef('term_glyph'), PackageRef('test')], + license: '''Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// cupertino_icons 1.0.8 +const _cupertino_icons = Package( + name: 'cupertino_icons', + description: 'Default icons asset for Cupertino widgets based on Apple styled icons', + repository: 'https://github.com/flutter/packages/tree/main/third_party/packages/cupertino_icons', + authors: [], + version: '1.0.8', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('flutter')], + license: '''The MIT License (MIT) + +Copyright (c) 2016 Vladimir Kharlampidi + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''', + ); + +/// dart_pubspec_licenses 3.0.15 +const _dart_pubspec_licenses = Package( + name: 'dart_pubspec_licenses', + description: 'A library to make it easy to extract OSS license information from Dart packages using pubspec.yaml', + homepage: 'https://github.com/espresso3389/flutter_oss_licenses/tree/master/packages/dart_pubspec_licenses', + repository: 'https://github.com/espresso3389/flutter_oss_licenses', + authors: [], + version: '3.0.15', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('yaml'), PackageRef('path'), PackageRef('json_annotation'), PackageRef('args'), PackageRef('pana')], + devDependencies: [PackageRef('lints'), PackageRef('build_runner')], + license: '''MIT License + +Copyright (c) 2019 Takashi Kawasaki + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// dart_style 3.1.1 +const _dart_style = Package( + name: 'dart_style', + description: 'Opinionated, automatic Dart source code formatter. Provides an API and a CLI tool.', + repository: 'https://github.com/dart-lang/dart_style', + authors: [], + version: '3.1.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('analyzer'), PackageRef('args'), PackageRef('collection'), PackageRef('package_config'), PackageRef('path'), PackageRef('pub_semver'), PackageRef('source_span'), PackageRef('yaml')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// dbus 0.7.11 +const _dbus = Package( + name: 'dbus', + description: 'A native Dart implementation of the D-Bus message bus client. This package allows Dart applications to directly access services on the Linux desktop.', + homepage: 'https://github.com/canonical/dbus.dart', + authors: [], + version: '0.7.11', + spdxIdentifiers: ['MPL-2.0'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('args'), PackageRef('ffi'), PackageRef('meta'), PackageRef('xml')], + devDependencies: [PackageRef('lints'), PackageRef('test')], + license: '''Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0.''', + ); + +/// dio 5.9.0 +const _dio = Package( + name: 'dio', + description: '''A powerful HTTP networking package, +supports Interceptors, +Aborting and canceling a request, +Custom adapters, Transformers, etc. +''', + homepage: 'https://github.com/cfug/dio', + repository: 'https://github.com/cfug/dio/blob/main/dio', + authors: [], + version: '5.9.0', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async'), PackageRef('collection'), PackageRef('http_parser'), PackageRef('meta'), PackageRef('mime'), PackageRef('path'), PackageRef('dio_web_adapter')], + devDependencies: [PackageRef('lints'), PackageRef('test'), PackageRef('build_runner'), PackageRef('coverage'), PackageRef('crypto')], + license: '''MIT License + +Copyright (c) 2018 Wen Du (wendux) +Copyright (c) 2022 The CFUG Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// dio_web_adapter 2.1.1 +const _dio_web_adapter = Package( + name: 'dio_web_adapter', + description: 'An adapter that supports Dio on Web.', + homepage: 'https://github.com/cfug/dio', + repository: 'https://github.com/cfug/dio/blob/main/plugins/web_adapter', + authors: [], + version: '2.1.1', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('dio'), PackageRef('http_parser'), PackageRef('meta'), PackageRef('web')], + devDependencies: [PackageRef('lints'), PackageRef('test')], + license: '''MIT License + +Copyright (c) 2018 Wen Du (wendux) +Copyright (c) 2022 The CFUG Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// drift 2.29.0 +const _drift = Package( + name: 'drift', + description: 'Drift is a reactive library to store relational data in Dart and Flutter applications.', + homepage: 'https://drift.simonbinder.eu/', + repository: 'https://github.com/simolus3/drift', + authors: [], + version: '2.29.0', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async'), PackageRef('convert'), PackageRef('collection'), PackageRef('meta'), PackageRef('stream_channel'), PackageRef('sqlite3'), PackageRef('path'), PackageRef('stack_trace'), PackageRef('web')], + devDependencies: [PackageRef('analyzer'), PackageRef('drift_dev'), PackageRef('http'), PackageRef('lints'), PackageRef('uuid'), PackageRef('build_runner'), PackageRef('test'), PackageRef('shelf'), PackageRef('vm_service'), PackageRef('build_daemon'), PackageRef('fake_async')], + license: '''MIT License + +Copyright (c) 2021 Simon Binder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// drift_dev 2.29.0 +const _drift_dev = Package( + name: 'drift_dev', + description: 'Dev-dependency for users of drift. Contains the generator and development tools.', + homepage: 'https://drift.simonbinder.eu/', + repository: 'https://github.com/simolus3/drift', + authors: [], + version: '2.29.0', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('charcode'), PackageRef('collection'), PackageRef('recase'), PackageRef('meta'), PackageRef('path'), PackageRef('json_annotation'), PackageRef('stream_transform'), PackageRef('args'), PackageRef('logging'), PackageRef('cli_util'), PackageRef('yaml'), PackageRef('io'), PackageRef('drift'), PackageRef('sqlite3'), PackageRef('sqlparser'), PackageRef('analyzer'), PackageRef('source_span'), PackageRef('package_config'), PackageRef('pub_semver'), PackageRef('build'), PackageRef('build_config'), PackageRef('dart_style'), PackageRef('source_gen'), PackageRef('string_scanner')], + devDependencies: [PackageRef('lints'), PackageRef('checked_yaml'), PackageRef('test'), PackageRef('build_runner'), PackageRef('crypto'), PackageRef('glob')], + license: '''MIT License + +Copyright (c) 2021 Simon Binder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// drift_flutter 0.2.7 +const _drift_flutter = Package( + name: 'drift_flutter', + description: 'Easily set up drift databases across platforms in Flutter apps.', + homepage: 'https://drift.simonbinder.eu/', + repository: 'https://github.com/simolus3/drift', + authors: [], + version: '0.2.7', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('drift'), PackageRef('flutter'), PackageRef('meta'), PackageRef('path'), PackageRef('path_provider'), PackageRef('sqlite3'), PackageRef('sqlite3_flutter_libs')], + devDependencies: [PackageRef('build_runner'), PackageRef('drift_dev'), PackageRef('lints'), PackageRef('test'), PackageRef('async')], + license: '''MIT License + +Copyright (c) 2024 Simon Binder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// fake_async 1.3.3 +const _fake_async = Package( + name: 'fake_async', + description: 'Fake asynchronous events such as timers and microtasks for deterministic testing.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/fake_async', + authors: [], + version: '1.3.3', + spdxIdentifiers: ['Apache-2.0'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('clock'), PackageRef('collection')], + devDependencies: [PackageRef('async'), PackageRef('test')], + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + ); + +/// ffi 2.1.4 +const _ffi = Package( + name: 'ffi', + description: 'Utilities for working with Foreign Function Interface (FFI) code.', + repository: 'https://github.com/dart-lang/native/tree/main/pkgs/ffi', + authors: [], + version: '2.1.4', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test')], + license: '''Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// file 7.0.1 +const _file = Package( + name: 'file', + description: 'A pluggable, mockable file system abstraction for Dart. Supports local file system access, as well as in-memory file systems, record-replay file systems, and chroot file systems.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/file', + authors: [], + version: '7.0.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('meta'), PackageRef('path')], + devDependencies: [PackageRef('lints'), PackageRef('test')], + license: '''Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// file_picker 10.3.7 +const _file_picker = Package( + name: 'file_picker', + description: 'A package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support.', + homepage: 'https://github.com/miguelpruivo/plugins_flutter_file_picker', + repository: 'https://github.com/miguelpruivo/flutter_file_picker', + authors: [], + version: '10.3.7', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('flutter_web_plugins'), PackageRef('flutter_plugin_android_lifecycle'), PackageRef('plugin_platform_interface'), PackageRef('ffi'), PackageRef('path'), PackageRef('win32'), PackageRef('cross_file'), PackageRef('web'), PackageRef('dbus')], + devDependencies: [PackageRef('flutter_lints')], + license: '''MIT License + +Copyright (c) 2018 Miguel Ruivo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// file_saver 0.3.1 +const _file_saver = Package( + name: 'file_saver', + description: 'A Flutter plugin for saving files across all platforms (Android, iOS, Web, Windows, macOS, Linux). Save files from bytes, File objects, file paths, or download from URLs with a single method call. Features include MIME type support, Dio integration, and platform-specific save locations. Supports saveAs() dialog for user-selected locations on supported platforms.', + homepage: 'https://hassanansari.dev', + repository: 'https://github.com/incrediblezayed/file_saver', + authors: [], + version: '0.3.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('collection'), PackageRef('dio'), PackageRef('flutter'), PackageRef('flutter_web_plugins'), PackageRef('path_provider'), PackageRef('path_provider_linux'), PackageRef('path_provider_windows'), PackageRef('web')], + devDependencies: [PackageRef('flutter_lints')], + license: '''BSD 3-Clause License + +Copyright (c) 2021, Hassan Ansari +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// fixnum 1.1.1 +const _fixnum = Package( + name: 'fixnum', + description: 'Library for 32- and 64-bit signed fixed-width integers with consistent behavior between native and JS runtimes.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/fixnum', + authors: [], + version: '1.1.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// flutter 3.38.4 +const _flutter = Package( + name: 'flutter', + description: 'A framework for writing Flutter applications', + homepage: 'https://flutter.dev', + authors: [], + version: '3.38.4', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: true, + dependencies: [PackageRef('characters'), PackageRef('collection'), PackageRef('material_color_utilities'), PackageRef('meta'), PackageRef('vector_math')], + devDependencies: [PackageRef('fake_async'), PackageRef('leak_tracker_flutter_testing'), PackageRef('leak_tracker_testing'), PackageRef('leak_tracker'), PackageRef('web'), PackageRef('clock'), PackageRef('file'), PackageRef('path'), PackageRef('platform')], + license: '''Copyright 2014 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// flutter_lints 5.0.0 +const _flutter_lints = Package( + name: 'flutter_lints', + description: 'Recommended lints for Flutter apps, packages, and plugins to encourage good coding practices.', + repository: 'https://github.com/flutter/packages/tree/main/packages/flutter_lints', + authors: [], + version: '5.0.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('lints')], + devDependencies: [], + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// flutter_plugin_android_lifecycle 2.0.33 +const _flutter_plugin_android_lifecycle = Package( + name: 'flutter_plugin_android_lifecycle', + description: 'Flutter plugin for accessing an Android Lifecycle within other plugins.', + repository: 'https://github.com/flutter/packages/tree/main/packages/flutter_plugin_android_lifecycle', + authors: [], + version: '2.0.33', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter')], + devDependencies: [], + license: '''Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// flutter_web_plugins null +const _flutter_web_plugins = Package( + name: 'flutter_web_plugins', + description: 'Library to register Flutter Web plugins', + homepage: 'https://flutter.dev', + authors: [], + spdxIdentifiers: [], + isMarkdown: false, + isSdk: true, + dependencies: [PackageRef('flutter')], + devDependencies: [], + ); + +/// font_awesome_flutter 10.12.0 +const _font_awesome_flutter = Package( + name: 'font_awesome_flutter', + description: 'The Font Awesome Icon pack available as Flutter Icons. Provides 2000 additional icons to use in your apps.', + repository: 'https://github.com/fluttercommunity/font_awesome_flutter', + authors: [], + version: '10.12.0', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter')], + devDependencies: [PackageRef('recase'), PackageRef('args'), PackageRef('flutter_lints'), PackageRef('pub_semver')], + license: '''MIT License + +Copyright (c) 2017 Brian Egan +Copyright (c) 2020 Michael Spiss +Font Awesome Icons by @fontawesome - https://fontawesome.com +License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// frontend_server_client 4.0.0 +const _frontend_server_client = Package( + name: 'frontend_server_client', + description: 'Client code to start and interact with the frontend_server compiler from the Dart SDK.', + repository: 'https://github.com/dart-lang/webdev/tree/master/frontend_server_client', + authors: [], + version: '4.0.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async'), PackageRef('path')], + devDependencies: [PackageRef('package_config'), PackageRef('shelf'), PackageRef('shelf_packages_handler'), PackageRef('shelf_static'), PackageRef('test'), PackageRef('vm_service')], + license: '''Copyright 2020, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// glob 2.1.3 +const _glob = Package( + name: 'glob', + description: 'A library to perform Bash-style file and directory globbing.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/glob', + authors: [], + version: '2.1.3', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async'), PackageRef('collection'), PackageRef('file'), PackageRef('path'), PackageRef('string_scanner')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// graphs 2.3.2 +const _graphs = Package( + name: 'graphs', + description: 'Graph algorithms that operate on graphs in any representation.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/graphs', + authors: [], + version: '2.3.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('collection')], + devDependencies: [PackageRef('test'), PackageRef('analyzer'), PackageRef('path'), PackageRef('pool')], + license: '''Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// html 0.15.6 +const _html = Package( + name: 'html', + description: 'APIs for parsing and manipulating HTML content outside the browser.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/html', + authors: [], + version: '0.15.6', + spdxIdentifiers: [], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('csslib'), PackageRef('source_span')], + devDependencies: [PackageRef('dart_style'), PackageRef('path'), PackageRef('test')], + license: '''Copyright (c) 2006-2012 The Authors + +Contributors: +James Graham - jg307@cam.ac.uk +Anne van Kesteren - annevankesteren@gmail.com +Lachlan Hunt - lachlan.hunt@lachy.id.au +Matt McDonald - kanashii@kanashii.ca +Sam Ruby - rubys@intertwingly.net +Ian Hickson (Google) - ian@hixie.ch +Thomas Broyer - t.broyer@ltgt.net +Jacques Distler - distler@golem.ph.utexas.edu +Henri Sivonen - hsivonen@iki.fi +Adam Barth - abarth@webkit.org +Eric Seidel - eric@webkit.org +The Mozilla Foundation (contributions from Henri Sivonen since 2008) +David Flanagan (Mozilla) - dflanagan@mozilla.com +Google LLC (contributed the Dart port) - misc@dartlang.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''', + ); + +/// http 1.6.0 +const _http = Package( + name: 'http', + description: 'A composable, multi-platform, Future-based API for HTTP requests.', + repository: 'https://github.com/dart-lang/http/tree/master/pkgs/http', + authors: [], + version: '1.6.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async'), PackageRef('http_parser'), PackageRef('meta'), PackageRef('web')], + devDependencies: [PackageRef('fake_async'), PackageRef('shelf'), PackageRef('stream_channel'), PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// http_multi_server 3.2.2 +const _http_multi_server = Package( + name: 'http_multi_server', + description: 'A dart:io HttpServer wrapper that handles requests from multiple servers.', + repository: 'https://github.com/dart-lang/http/tree/master/pkgs/http_multi_server', + authors: [], + version: '3.2.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async')], + devDependencies: [PackageRef('http'), PackageRef('shelf'), PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// http_parser 4.1.2 +const _http_parser = Package( + name: 'http_parser', + description: 'A platform-independent package for parsing and serializing HTTP formats.', + repository: 'https://github.com/dart-lang/http/tree/master/pkgs/http_parser', + authors: [], + version: '4.1.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('collection'), PackageRef('source_span'), PackageRef('string_scanner'), PackageRef('typed_data')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// intl 0.20.2 +const _intl = Package( + name: 'intl', + description: 'Contains code to deal with internationalized/localized messages, date and number formatting and parsing, bi-directional text, and other internationalization issues.', + repository: 'https://github.com/dart-lang/i18n/tree/main/pkgs/intl', + authors: [], + version: '0.20.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('clock'), PackageRef('meta'), PackageRef('path')], + devDependencies: [PackageRef('ffi'), PackageRef('fixnum'), PackageRef('lints'), PackageRef('test')], + license: '''Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// io 1.0.5 +const _io = Package( + name: 'io', + description: 'Utilities for the Dart VM Runtime including support for ANSI colors, file copying, and standard exit code values.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/io', + authors: [], + version: '1.0.5', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('meta'), PackageRef('path'), PackageRef('string_scanner')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// js 0.7.2 +const _js = Package( + name: 'js', + description: 'Annotations to create static Dart interfaces for JavaScript APIs.', + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/js', + authors: [], + version: '0.7.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('lints')], + license: '''Copyright 2012, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// json_annotation 4.9.0 +const _json_annotation = Package( + name: 'json_annotation', + description: 'Classes and helper functions that support JSON code generation via the `json_serializable` package.', + repository: 'https://github.com/google/json_serializable.dart/tree/master/json_annotation', + authors: [], + version: '4.9.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('meta')], + devDependencies: [], + license: '''Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// json_schema 5.2.2 +const _json_schema = Package( + name: 'json_schema', + description: 'JSON Schema implementation in Dart', + homepage: 'https://github.com/workiva/json_schema', + authors: [], + version: '5.2.2', + spdxIdentifiers: [], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('collection'), PackageRef('http'), PackageRef('logging'), PackageRef('rfc_6901'), PackageRef('uri')], + devDependencies: [PackageRef('path'), PackageRef('shelf'), PackageRef('shelf_static'), PackageRef('test')], + license: '''Copyright 2013-2022 Workiva Inc. + +Licensed under the Boost Software License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.boost.org/LICENSE_1_0.txt + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +This software or document includes material copied from or derived +from JSON-Schema-Test-Suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite), +Copyright (c) 2012 Julian Berman, which is licensed under the following terms: + + Copyright (c) 2012 Julian Berman + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE.''', + ); + +/// leak_tracker 11.0.2 +const _leak_tracker = Package( + name: 'leak_tracker', + description: 'A framework for memory leak tracking for Dart and Flutter applications.', + repository: 'https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker', + authors: [], + version: '11.0.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('clock'), PackageRef('collection'), PackageRef('meta'), PackageRef('path'), PackageRef('vm_service')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2022, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// leak_tracker_flutter_testing 3.0.10 +const _leak_tracker_flutter_testing = Package( + name: 'leak_tracker_flutter_testing', + description: 'An internal package to test leak tracking with Flutter.', + repository: 'https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker_flutter_testing', + authors: [], + version: '3.0.10', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('leak_tracker'), PackageRef('leak_tracker_testing'), PackageRef('matcher'), PackageRef('meta')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2022, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// leak_tracker_testing 3.0.2 +const _leak_tracker_testing = Package( + name: 'leak_tracker_testing', + description: 'Leak tracking code intended for usage in tests.', + repository: 'https://github.com/dart-lang/leak_tracker/tree/main/pkgs/leak_tracker_testing', + authors: [], + version: '3.0.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('leak_tracker'), PackageRef('matcher'), PackageRef('meta')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2022, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// lints 5.1.1 +const _lints = Package( + name: 'lints', + description: """Official Dart lint rules. Defines the 'core' and 'recommended' set of lints suggested by the Dart team. +""", + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/lints', + authors: [], + version: '5.1.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('http'), PackageRef('path'), PackageRef('yaml')], + license: '''Copyright 2021, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// logging 1.3.0 +const _logging = Package( + name: 'logging', + description: 'Provides APIs for debugging and error logging, similar to loggers in other languages, such as the Closure JS Logger and java.util.logging.Logger.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/logging', + authors: [], + version: '1.3.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test')], + license: '''Copyright 2013, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// markdown 7.3.0 +const _markdown = Package( + name: 'markdown', + description: 'A portable Markdown library written in Dart that can parse Markdown into HTML.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/markdown', + authors: [], + version: '7.3.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('args'), PackageRef('meta')], + devDependencies: [PackageRef('build_runner'), PackageRef('collection'), PackageRef('html'), PackageRef('http'), PackageRef('io'), PackageRef('path'), PackageRef('pool'), PackageRef('tar'), PackageRef('test'), PackageRef('web'), PackageRef('yaml')], + license: '''Copyright 2012, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// matcher 0.12.17 +const _matcher = Package( + name: 'matcher', + description: 'Support for specifying test expectations via an extensible Matcher class. Also includes a number of built-in Matcher implementations for common cases.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/matcher', + authors: [], + version: '0.12.17', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async'), PackageRef('meta'), PackageRef('stack_trace'), PackageRef('term_glyph'), PackageRef('test_api')], + devDependencies: [PackageRef('fake_async'), PackageRef('lints'), PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// material_color_utilities 0.11.1 +const _material_color_utilities = Package( + name: 'material_color_utilities', + description: 'Algorithms and utilities that power the Material Design 3 color system, including choosing theme colors from images and creating tones of colors; all in a new color space.', + repository: 'https://github.com/material-foundation/material-color-utilities/tree/main/dart', + authors: [], + version: '0.11.1', + spdxIdentifiers: ['Apache-2.0'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('collection')], + devDependencies: [PackageRef('matcher'), PackageRef('lints'), PackageRef('test')], + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Google LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + ); + +/// meta 1.17.0 +const _meta = Package( + name: 'meta', + description: "Annotations used to express developer intentions that can't otherwise be deduced by statically analyzing source code.", + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/meta', + authors: [], + version: '1.17.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('lints')], + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// mime 2.0.0 +const _mime = Package( + name: 'mime', + description: 'Utilities for handling media (MIME) types, including determining a type from a file extension and file contents.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/mime', + authors: [], + version: '2.0.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test')], + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// nested 1.0.0 +const _nested = Package( + name: 'nested', + description: 'A Flutter Widget which helps nest multiple widgets without needing to manually nest them.', + repository: 'https://github.com/rrousselGit/nested', + authors: [], + version: '1.0.0', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter')], + devDependencies: [], + license: '''MIT License + +Copyright (c) 2019 Remi Rousselet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// node_preamble 2.0.2 +const _node_preamble = Package( + name: 'node_preamble', + description: 'Better node.js preamble for dart2js, use it in your build system.', + homepage: 'https://github.com/mbullington/node_preamble.dart', + authors: ['Michael Bullington '], + version: '2.0.2', + spdxIdentifiers: ['BSD-3-Clause', 'MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [], + license: '''The MIT License (MIT) + +Copyright (c) 2015 Michael Bullington + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=== + +Copyright 2012, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// package_config 2.2.0 +const _package_config = Package( + name: 'package_config', + description: 'Support for reading and writing Dart Package Configuration files.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/package_config', + authors: [], + version: '2.2.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('path')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2019, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// package_info_plus 9.0.0 +const _package_info_plus = Package( + name: 'package_info_plus', + description: 'Flutter plugin for querying information about the application package, such as CFBundleVersion on iOS or versionCode on Android.', + homepage: 'https://github.com/fluttercommunity/plus_plugins', + repository: 'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/package_info_plus/package_info_plus', + authors: [], + version: '9.0.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('ffi'), PackageRef('flutter'), PackageRef('flutter_web_plugins'), PackageRef('http'), PackageRef('meta'), PackageRef('path'), PackageRef('package_info_plus_platform_interface'), PackageRef('web'), PackageRef('win32'), PackageRef('clock')], + devDependencies: [PackageRef('flutter_lints'), PackageRef('test')], + license: '''Copyright 2017 The Chromium Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// package_info_plus_platform_interface 3.2.1 +const _package_info_plus_platform_interface = Package( + name: 'package_info_plus_platform_interface', + description: 'A common platform interface for the package_info_plus plugin.', + homepage: 'https://github.com/fluttercommunity/plus_plugins', + repository: 'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/', + authors: [], + version: '3.2.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('meta'), PackageRef('plugin_platform_interface')], + devDependencies: [PackageRef('flutter_lints')], + license: '''Copyright 2017 The Chromium Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// pana 0.22.22 +const _pana = Package( + name: 'pana', + description: 'PAckage aNAlyzer - produce a report summarizing the health and quality of a Dart package.', + repository: 'https://github.com/dart-lang/pana', + authors: [], + version: '0.22.22', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('analyzer'), PackageRef('args'), PackageRef('async'), PackageRef('cli_util'), PackageRef('collection'), PackageRef('crypto'), PackageRef('html'), PackageRef('http'), PackageRef('io'), PackageRef('json_annotation'), PackageRef('lints'), PackageRef('logging'), PackageRef('markdown'), PackageRef('meta'), PackageRef('path'), PackageRef('pub_semver'), PackageRef('pubspec_parse'), PackageRef('retry'), PackageRef('safe_url_check'), PackageRef('source_span'), PackageRef('string_scanner'), PackageRef('tar'), PackageRef('test'), PackageRef('yaml')], + devDependencies: [PackageRef('build'), PackageRef('build_config'), PackageRef('build_runner'), PackageRef('shelf'), PackageRef('source_gen')], + license: '''Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// path 1.9.1 +const _path = Package( + name: 'path', + description: 'A string-based path manipulation library. All of the path operations you know and love, with solid support for Windows, POSIX (Linux and Mac OS X), and the web.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/path', + authors: [], + version: '1.9.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// path_provider 2.1.5 +const _path_provider = Package( + name: 'path_provider', + description: 'Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories.', + repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider', + authors: [], + version: '2.1.5', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('path_provider_android'), PackageRef('path_provider_foundation'), PackageRef('path_provider_linux'), PackageRef('path_provider_platform_interface'), PackageRef('path_provider_windows')], + devDependencies: [PackageRef('plugin_platform_interface'), PackageRef('test')], + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// path_provider_android 2.2.20 +const _path_provider_android = Package( + name: 'path_provider_android', + description: 'Android implementation of the path_provider plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_android', + authors: [], + version: '2.2.20', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('path_provider_platform_interface')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// path_provider_foundation 2.4.3 +const _path_provider_foundation = Package( + name: 'path_provider_foundation', + description: 'iOS and macOS implementation of the path_provider plugin', + repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_foundation', + authors: [], + version: '2.4.3', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('path_provider_platform_interface')], + devDependencies: [PackageRef('build_runner'), PackageRef('path')], + license: '''Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// path_provider_linux 2.2.1 +const _path_provider_linux = Package( + name: 'path_provider_linux', + description: 'Linux implementation of the path_provider plugin', + repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_linux', + authors: [], + version: '2.2.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('ffi'), PackageRef('flutter'), PackageRef('path'), PackageRef('path_provider_platform_interface'), PackageRef('xdg_directories')], + devDependencies: [], + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// path_provider_platform_interface 2.1.2 +const _path_provider_platform_interface = Package( + name: 'path_provider_platform_interface', + description: 'A common platform interface for the path_provider plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_platform_interface', + authors: [], + version: '2.1.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('platform'), PackageRef('plugin_platform_interface')], + devDependencies: [], + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// path_provider_windows 2.3.0 +const _path_provider_windows = Package( + name: 'path_provider_windows', + description: 'Windows implementation of the path_provider plugin', + repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_windows', + authors: [], + version: '2.3.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('ffi'), PackageRef('flutter'), PackageRef('path'), PackageRef('path_provider_platform_interface')], + devDependencies: [], + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// petitparser 7.0.1 +const _petitparser = Package( + name: 'petitparser', + description: 'A dynamic parser framework to build efficient grammars and parsers quickly.', + homepage: 'https://petitparser.github.io', + repository: 'https://github.com/petitparser/dart-petitparser', + authors: [], + version: '7.0.1', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('meta'), PackageRef('collection')], + devDependencies: [PackageRef('lints'), PackageRef('test')], + license: '''The MIT License + +Copyright (c) 2006-2024 Lukas Renggli. +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + ); + +/// platform 3.1.6 +const _platform = Package( + name: 'platform', + description: 'A pluggable, mockable platform information abstraction for Dart.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/platform', + authors: [], + version: '3.1.6', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test')], + license: '''Copyright 2017, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// plugin_platform_interface 2.1.8 +const _plugin_platform_interface = Package( + name: 'plugin_platform_interface', + description: 'Reusable base class for platform interfaces of Flutter federated plugins, to help enforce best practices.', + repository: 'https://github.com/flutter/packages/tree/main/packages/plugin_platform_interface', + authors: [], + version: '2.1.8', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('meta')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// pool 1.5.2 +const _pool = Package( + name: 'pool', + description: 'Manage a finite pool of resources. Useful for controlling concurrent file system or network requests.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/pool', + authors: [], + version: '1.5.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async'), PackageRef('stack_trace')], + devDependencies: [PackageRef('fake_async'), PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// provider 6.1.5+1 +const _provider = Package( + name: 'provider', + description: 'A wrapper around InheritedWidget to make them easier to use and more reusable.', + repository: 'https://github.com/rrousselGit/provider', + authors: [], + version: '6.1.5+1', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('collection'), PackageRef('flutter'), PackageRef('nested')], + devDependencies: [PackageRef('leak_tracker'), PackageRef('test')], + license: '''MIT License + +Copyright (c) 2019 Remi Rousselet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// pub_semver 2.2.0 +const _pub_semver = Package( + name: 'pub_semver', + description: "Versions and version constraints implementing pub's versioning policy. This is very similar to vanilla semver, with a few corner cases.", + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/pub_semver', + authors: [], + version: '2.2.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('collection')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// pubspec_parse 1.5.0 +const _pubspec_parse = Package( + name: 'pubspec_parse', + description: 'Simple package for parsing pubspec.yaml files with a type-safe API and rich error reporting.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/pubspec_parse', + authors: [], + version: '1.5.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('checked_yaml'), PackageRef('collection'), PackageRef('json_annotation'), PackageRef('pub_semver'), PackageRef('yaml')], + devDependencies: [PackageRef('build_runner'), PackageRef('path'), PackageRef('source_gen'), PackageRef('stack_trace'), PackageRef('test')], + license: '''Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// quiver 3.2.2 +const _quiver = Package( + name: 'quiver', + description: 'Quiver is a set of utility libraries for Dart that makes using many Dart libraries easier and more convenient, or adds additional functionality.', + repository: 'https://github.com/google/quiver-dart', + authors: [], + version: '3.2.2', + spdxIdentifiers: ['Apache-2.0'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('matcher')], + devDependencies: [PackageRef('lints'), PackageRef('path'), PackageRef('test')], + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + ); + +/// recase 4.1.0 +const _recase = Package( + name: 'recase', + description: 'Changes the case of the input text to the desire case convention.', + homepage: 'https://github.com/techniboogie-dart/recase', + authors: [], + version: '4.1.0', + spdxIdentifiers: ['BSD-2-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test')], + license: '''Copyright 2017 Keith Elliott + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// retry 3.1.2 +const _retry = Package( + name: 'retry', + description: 'Utility for wrapping an asynchronous function in automatic retry logic with exponential back-off, useful when making requests over network.', + homepage: 'https://github.com/google/dart-neats/tree/master/retry', + repository: 'https://github.com/google/dart-neats.git', + authors: [], + version: '3.1.2', + spdxIdentifiers: ['Apache-2.0'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('test'), PackageRef('lints')], + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + ); + +/// rfc_6901 0.2.1 +const _rfc_6901 = Package( + name: 'rfc_6901', + description: 'JSON Pointer (RFC 6901). Reads/writes referred values in JSON documents.', + homepage: 'https://github.com/f3ath/rfc-6901-dart', + authors: [], + version: '0.2.1', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('lints'), PackageRef('test')], + license: '''MIT License + +Copyright (c) 2021 The Конь + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// safe_url_check 1.1.2 +const _safe_url_check = Package( + name: 'safe_url_check', + description: 'Check if an untrusted URL is broken, without allowing connections to a private IP address.', + homepage: 'https://github.com/google/dart-neats/tree/master/safe_url_check', + repository: 'https://github.com/google/dart-neats.git', + authors: [], + version: '1.1.2', + spdxIdentifiers: ['Apache-2.0'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('meta'), PackageRef('retry')], + devDependencies: [PackageRef('test'), PackageRef('lints'), PackageRef('build_runner')], + license: '''Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + ); + +/// shelf 1.4.2 +const _shelf = Package( + name: 'shelf', + description: '''A model for web server middleware that encourages composition and easy reuse. +''', + repository: 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf', + authors: [], + version: '1.4.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async'), PackageRef('collection'), PackageRef('http_parser'), PackageRef('path'), PackageRef('stack_trace'), PackageRef('stream_channel')], + devDependencies: [PackageRef('http'), PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// shelf_packages_handler 3.0.2 +const _shelf_packages_handler = Package( + name: 'shelf_packages_handler', + description: 'A shelf handler for serving a `packages/` directory.', + repository: 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf_packages_handler', + authors: [], + version: '3.0.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('path'), PackageRef('shelf'), PackageRef('shelf_static')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// shelf_static 1.1.3 +const _shelf_static = Package( + name: 'shelf_static', + description: 'Static file server support for the shelf package and ecosystem.', + repository: 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf_static', + authors: [], + version: '1.1.3', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('convert'), PackageRef('http_parser'), PackageRef('mime'), PackageRef('path'), PackageRef('shelf')], + devDependencies: [PackageRef('args'), PackageRef('test')], + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// shelf_web_socket 3.0.0 +const _shelf_web_socket = Package( + name: 'shelf_web_socket', + description: 'A shelf handler that wires up a listener for every connection.', + repository: 'https://github.com/dart-lang/shelf/tree/master/pkgs/shelf_web_socket', + authors: [], + version: '3.0.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('shelf'), PackageRef('stream_channel'), PackageRef('web_socket_channel')], + devDependencies: [PackageRef('http'), PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// skeletonizer 2.1.1 +const _skeletonizer = Package( + name: 'skeletonizer', + description: 'Converts already built widgets into skeleton loaders with no extra effort.', + homepage: 'https://github.com/Milad-Akarie/skeletonizer', + authors: [], + version: '2.1.1', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter')], + devDependencies: [PackageRef('flutter_lints')], + license: '''MIT License + +Copyright (c) 2023 Milad Akarie + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// source_gen 4.0.0 +const _source_gen = Package( + name: 'source_gen', + description: 'Source code generation builders and utilities for the Dart build system', + repository: 'https://github.com/dart-lang/source_gen/tree/master/source_gen', + authors: [], + version: '4.0.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('analyzer'), PackageRef('async'), PackageRef('build'), PackageRef('dart_style'), PackageRef('glob'), PackageRef('path'), PackageRef('pub_semver'), PackageRef('source_span'), PackageRef('yaml')], + devDependencies: [PackageRef('logging'), PackageRef('term_glyph'), PackageRef('test')], + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// source_map_stack_trace 2.1.2 +const _source_map_stack_trace = Package( + name: 'source_map_stack_trace', + description: 'A package for applying source maps to stack traces.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/source_map_stack_trace', + authors: [], + version: '2.1.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('path'), PackageRef('source_maps'), PackageRef('stack_trace')], + devDependencies: [PackageRef('source_span'), PackageRef('test')], + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// source_maps 0.10.13 +const _source_maps = Package( + name: 'source_maps', + description: 'A library to programmatically manipulate source map files.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/source_maps', + authors: [], + version: '0.10.13', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('source_span')], + devDependencies: [PackageRef('term_glyph'), PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// source_span 1.10.1 +const _source_span = Package( + name: 'source_span', + description: 'Provides a standard representation for source code locations and spans.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/source_span', + authors: [], + version: '1.10.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('collection'), PackageRef('path'), PackageRef('term_glyph')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// sqlite3 2.9.4 +const _sqlite3 = Package( + name: 'sqlite3', + description: 'Provides lightweight yet convenient bindings to SQLite by using dart:ffi', + homepage: 'https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3', + authors: [], + version: '2.9.4', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('collection'), PackageRef('ffi'), PackageRef('meta'), PackageRef('path'), PackageRef('web'), PackageRef('typed_data')], + devDependencies: [PackageRef('analyzer'), PackageRef('build_daemon'), PackageRef('build_runner'), PackageRef('dart_style'), PackageRef('http'), PackageRef('lints'), PackageRef('shelf'), PackageRef('shelf_static'), PackageRef('stream_channel'), PackageRef('test'), PackageRef('pub_semver'), PackageRef('convert')], + license: '''MIT License + +Copyright (c) 2020 Simon Binder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// sqlite3_flutter_libs 0.5.40 +const _sqlite3_flutter_libs = Package( + name: 'sqlite3_flutter_libs', + description: 'Flutter plugin to include native sqlite3 libraries with your app', + homepage: 'https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3_flutter_libs', + authors: [], + version: '0.5.40', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter')], + devDependencies: [], + license: '''MIT License + +Copyright (c) 2020 Simon Binder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// sqlparser 0.42.0 +const _sqlparser = Package( + name: 'sqlparser', + description: 'Parses sqlite statements and performs static analysis on them', + homepage: 'https://github.com/simolus3/drift/tree/develop/sqlparser', + repository: 'https://github.com/simolus3/drift', + authors: [], + version: '0.42.0', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('meta'), PackageRef('collection'), PackageRef('source_span'), PackageRef('charcode')], + devDependencies: [PackageRef('lints'), PackageRef('test'), PackageRef('path'), PackageRef('ffi'), PackageRef('sqlite3')], + license: '''MIT License + +Copyright (c) 2019 Simon Binder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// stack_trace 1.12.1 +const _stack_trace = Package( + name: 'stack_trace', + description: 'A package for manipulating stack traces and printing them readably.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/stack_trace', + authors: [], + version: '1.12.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('path')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// stream_channel 2.1.4 +const _stream_channel = Package( + name: 'stream_channel', + description: 'An abstraction for two-way communication channels based on the Dart Stream class.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/stream_channel', + authors: [], + version: '2.1.4', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// stream_transform 2.1.1 +const _stream_transform = Package( + name: 'stream_transform', + description: 'A collection of utilities to transform and manipulate streams.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/stream_transform', + authors: [], + version: '2.1.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('async'), PackageRef('fake_async'), PackageRef('test')], + license: '''Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// string_scanner 1.4.1 +const _string_scanner = Package( + name: 'string_scanner', + description: 'A class for parsing strings using a sequence of patterns.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/string_scanner', + authors: [], + version: '1.4.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('source_span')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// tar 2.0.2 +const _tar = Package( + name: 'tar', + description: 'Memory-efficient, streaming implementation of the tar file format', + repository: 'https://github.com/simolus3/tar/', + authors: [], + version: '2.0.2', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async'), PackageRef('meta'), PackageRef('typed_data')], + devDependencies: [PackageRef('charcode'), PackageRef('lints'), PackageRef('file'), PackageRef('path'), PackageRef('test')], + license: '''MIT License + +Copyright (c) 2021 Simon Binder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// term_glyph 1.2.2 +const _term_glyph = Package( + name: 'term_glyph', + description: 'Useful Unicode glyphs and ASCII substitutes.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/term_glyph', + authors: [], + version: '1.2.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('dart_style'), PackageRef('test')], + license: '''Copyright 2017, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// test 1.26.3 +const _test = Package( + name: 'test', + description: 'A full featured library for writing and running Dart tests across platforms.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/test', + authors: [], + version: '1.26.3', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('analyzer'), PackageRef('async'), PackageRef('boolean_selector'), PackageRef('collection'), PackageRef('coverage'), PackageRef('http_multi_server'), PackageRef('io'), PackageRef('js'), PackageRef('matcher'), PackageRef('node_preamble'), PackageRef('package_config'), PackageRef('path'), PackageRef('pool'), PackageRef('shelf'), PackageRef('shelf_packages_handler'), PackageRef('shelf_static'), PackageRef('shelf_web_socket'), PackageRef('source_span'), PackageRef('stack_trace'), PackageRef('stream_channel'), PackageRef('test_api'), PackageRef('test_core'), PackageRef('typed_data'), PackageRef('web_socket_channel'), PackageRef('webkit_inspection_protocol'), PackageRef('yaml')], + devDependencies: [PackageRef('fake_async'), PackageRef('glob')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// test_api 0.7.7 +const _test_api = Package( + name: 'test_api', + description: 'The user facing API for structuring Dart tests and checking expectations.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/test_api', + authors: [], + version: '0.7.7', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async'), PackageRef('boolean_selector'), PackageRef('collection'), PackageRef('meta'), PackageRef('source_span'), PackageRef('stack_trace'), PackageRef('stream_channel'), PackageRef('string_scanner'), PackageRef('term_glyph')], + devDependencies: [PackageRef('analyzer'), PackageRef('fake_async'), PackageRef('glob'), PackageRef('graphs'), PackageRef('path'), PackageRef('test'), PackageRef('test_core')], + license: '''Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// test_core 0.6.12 +const _test_core = Package( + name: 'test_core', + description: 'A basic library for writing tests and running them on the VM.', + repository: 'https://github.com/dart-lang/test/tree/master/pkgs/test_core', + authors: [], + version: '0.6.12', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('analyzer'), PackageRef('args'), PackageRef('async'), PackageRef('boolean_selector'), PackageRef('collection'), PackageRef('coverage'), PackageRef('frontend_server_client'), PackageRef('glob'), PackageRef('io'), PackageRef('meta'), PackageRef('package_config'), PackageRef('path'), PackageRef('pool'), PackageRef('source_map_stack_trace'), PackageRef('source_maps'), PackageRef('source_span'), PackageRef('stack_trace'), PackageRef('stream_channel'), PackageRef('test_api'), PackageRef('vm_service'), PackageRef('yaml')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// timing 1.0.2 +const _timing = Package( + name: 'timing', + description: 'A simple package for tracking the performance of synchronous and asynchronous actions.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/timing', + authors: [], + version: '1.0.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('json_annotation')], + devDependencies: [PackageRef('build_runner'), PackageRef('test')], + license: '''Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// typed_data 1.4.0 +const _typed_data = Package( + name: 'typed_data', + description: 'Utility functions and classes related to the dart:typed_data library.', + repository: 'https://github.com/dart-lang/core/tree/main/pkgs/typed_data', + authors: [], + version: '1.4.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('collection')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// uri 1.0.0 +const _uri = Package( + name: 'uri', + description: 'Utilities for building and parsing URIs, including support for parsing URI templates as defined in RFC 6570.', + repository: 'https://github.com/google/uri.dart', + authors: [], + version: '1.0.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('matcher'), PackageRef('quiver')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2013, the Dart project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// url_launcher 6.3.2 +const _url_launcher = Package( + name: 'url_launcher', + description: 'Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher', + authors: [], + version: '6.3.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('url_launcher_android'), PackageRef('url_launcher_ios'), PackageRef('url_launcher_linux'), PackageRef('url_launcher_macos'), PackageRef('url_launcher_platform_interface'), PackageRef('url_launcher_web'), PackageRef('url_launcher_windows')], + devDependencies: [PackageRef('plugin_platform_interface'), PackageRef('test')], + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// url_launcher_android 6.3.28 +const _url_launcher_android = Package( + name: 'url_launcher_android', + description: 'Android implementation of the url_launcher plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_android', + authors: [], + version: '6.3.28', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('url_launcher_platform_interface')], + devDependencies: [PackageRef('plugin_platform_interface'), PackageRef('test')], + license: '''Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// url_launcher_ios 6.3.6 +const _url_launcher_ios = Package( + name: 'url_launcher_ios', + description: 'iOS implementation of the url_launcher plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_ios', + authors: [], + version: '6.3.6', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('url_launcher_platform_interface')], + devDependencies: [PackageRef('build_runner'), PackageRef('plugin_platform_interface'), PackageRef('test')], + license: '''Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// url_launcher_linux 3.2.2 +const _url_launcher_linux = Package( + name: 'url_launcher_linux', + description: 'Linux implementation of the url_launcher plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_linux', + authors: [], + version: '3.2.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('url_launcher_platform_interface')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// url_launcher_macos 3.2.5 +const _url_launcher_macos = Package( + name: 'url_launcher_macos', + description: 'macOS implementation of the url_launcher plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_macos', + authors: [], + version: '3.2.5', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('url_launcher_platform_interface')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// url_launcher_platform_interface 2.3.2 +const _url_launcher_platform_interface = Package( + name: 'url_launcher_platform_interface', + description: 'A common platform interface for the url_launcher plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_platform_interface', + authors: [], + version: '2.3.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('plugin_platform_interface')], + devDependencies: [], + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// url_launcher_web 2.4.1 +const _url_launcher_web = Package( + name: 'url_launcher_web', + description: 'Web platform implementation of url_launcher', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_web', + authors: [], + version: '2.4.1', + spdxIdentifiers: ['Apache-2.0', 'BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('flutter_web_plugins'), PackageRef('url_launcher_platform_interface'), PackageRef('web')], + devDependencies: [], + license: '''url_launcher_web + +Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +platform_detect + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Workiva Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.''', + ); + +/// url_launcher_windows 3.1.5 +const _url_launcher_windows = Package( + name: 'url_launcher_windows', + description: 'Windows implementation of the url_launcher plugin.', + repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_windows', + authors: [], + version: '3.1.5', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('url_launcher_platform_interface')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// uuid 4.5.2 +const _uuid = Package( + name: 'uuid', + description: '''RFC4122 (v1, v4, v5, v6, v7, v8) UUID Generator and Parser for Dart +''', + repository: 'https://github.com/Daegalus/dart-uuid', + authors: [], + version: '4.5.2', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('crypto'), PackageRef('meta'), PackageRef('fixnum')], + devDependencies: [PackageRef('lints'), PackageRef('test')], + license: '''Copyright (c) 2021 Yulian Kuncheff + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''', + ); + +/// vector_math 2.2.0 +const _vector_math = Package( + name: 'vector_math', + description: 'A Vector Math library for 2D and 3D applications.', + repository: 'https://github.com/google/vector_math.dart', + authors: [], + version: '2.2.0', + spdxIdentifiers: ['Zlib', 'BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('build_runner'), PackageRef('path'), PackageRef('test')], + license: '''Copyright 2015, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Copyright (C) 2013 Andrew Magill + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution.''', + ); + +/// vm_service 15.0.2 +const _vm_service = Package( + name: 'vm_service', + description: 'A library to communicate with a service implementing the Dart VM service protocol.', + repository: 'https://github.com/dart-lang/sdk/tree/main/pkg/vm_service', + authors: [], + version: '15.0.2', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('async'), PackageRef('collection'), PackageRef('lints'), PackageRef('logging'), PackageRef('markdown'), PackageRef('path'), PackageRef('pub_semver'), PackageRef('stack_trace'), PackageRef('test')], + license: '''Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// watcher 1.1.4 +const _watcher = Package( + name: 'watcher', + description: 'A file system watcher. It monitors changes to contents of directories and sends notifications when files have been added, removed, or modified.', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/watcher', + authors: [], + version: '1.1.4', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async'), PackageRef('path')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2014, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// web 1.1.1 +const _web = Package( + name: 'web', + description: 'Lightweight browser API bindings built around JS interop.', + repository: 'https://github.com/dart-lang/web', + authors: [], + version: '1.1.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [], + devDependencies: [PackageRef('path'), PackageRef('test')], + license: '''Copyright 2023, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// web_socket 1.0.1 +const _web_socket = Package( + name: 'web_socket', + description: 'Any easy-to-use library for communicating with WebSockets that has multiple implementations.', + repository: 'https://github.com/dart-lang/http/tree/master/pkgs/web_socket', + authors: [], + version: '1.0.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('web')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2024, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// web_socket_channel 3.0.3 +const _web_socket_channel = Package( + name: 'web_socket_channel', + description: 'StreamChannel wrappers for WebSockets. Provides a cross-platform WebSocketChannel API, a cross-platform implementation of that API that communicates over an underlying StreamChannel.', + repository: 'https://github.com/dart-lang/http/tree/master/pkgs/web_socket_channel', + authors: [], + version: '3.0.3', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('async'), PackageRef('crypto'), PackageRef('stream_channel'), PackageRef('web'), PackageRef('web_socket')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2016, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// webkit_inspection_protocol 1.2.1 +const _webkit_inspection_protocol = Package( + name: 'webkit_inspection_protocol', + description: '''A client for the Chrome DevTools Protocol (previously called the Webkit Inspection Protocol). +''', + repository: 'https://github.com/google/webkit_inspection_protocol.dart', + authors: [], + version: '1.2.1', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('logging')], + devDependencies: [PackageRef('args'), PackageRef('lints'), PackageRef('shelf_static'), PackageRef('shelf_web_socket'), PackageRef('shelf'), PackageRef('test'), PackageRef('web_socket_channel')], + license: '''Copyright 2013, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// win32 5.15.0 +const _win32 = Package( + name: 'win32', + description: '''Access common Win32 APIs directly from Dart using FFI — no C required! +''', + homepage: 'https://win32.pub', + repository: 'https://github.com/halildurmus/win32', + authors: [], + version: '5.15.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('ffi')], + devDependencies: [PackageRef('args'), PackageRef('path'), PackageRef('test')], + license: '''BSD 3-Clause License + +Copyright (c) 2024, Halil Durmus + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// xdg_directories 1.1.0 +const _xdg_directories = Package( + name: 'xdg_directories', + description: 'A Dart package for reading XDG directory configuration information on Linux.', + repository: 'https://github.com/flutter/packages/tree/main/packages/xdg_directories', + authors: [], + version: '1.1.0', + spdxIdentifiers: ['BSD-3-Clause'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('meta'), PackageRef('path')], + devDependencies: [PackageRef('test')], + license: '''Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', + ); + +/// xml 6.6.1 +const _xml = Package( + name: 'xml', + description: 'A lightweight library for parsing, traversing, querying, transforming and building XML documents.', + homepage: 'https://github.com/renggli/dart-xml', + authors: [], + version: '6.6.1', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('collection'), PackageRef('meta'), PackageRef('petitparser')], + devDependencies: [PackageRef('args'), PackageRef('lints'), PackageRef('test')], + license: '''The MIT License + +Copyright (c) 2006-2025 Lukas Renggli. +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.''', + ); + +/// yaml 3.1.3 +const _yaml = Package( + name: 'yaml', + description: 'A parser for YAML, a human-friendly data serialization standard', + repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/yaml', + authors: [], + version: '3.1.3', + spdxIdentifiers: ['MIT'], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('collection'), PackageRef('source_span'), PackageRef('string_scanner')], + devDependencies: [PackageRef('path'), PackageRef('test')], + license: '''Copyright (c) 2014, the Dart project authors. +Copyright (c) 2006, Kirill Simonov. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + +/// game_tracker 0.0.5+127 +const _game_tracker = Package( + name: 'game_tracker', + description: 'Game Tracking App for Card Games', + authors: [], + version: '0.0.5+127', + spdxIdentifiers: [], + isMarkdown: false, + isSdk: false, + dependencies: [PackageRef('flutter'), PackageRef('clock'), PackageRef('cupertino_icons'), PackageRef('drift'), PackageRef('drift_flutter'), PackageRef('file_picker'), PackageRef('file_saver'), PackageRef('font_awesome_flutter'), PackageRef('intl'), PackageRef('json_schema'), PackageRef('package_info_plus'), PackageRef('path_provider'), PackageRef('provider'), PackageRef('skeletonizer'), PackageRef('url_launcher'), PackageRef('uuid')], + devDependencies: [PackageRef('build_runner'), PackageRef('dart_pubspec_licenses'), PackageRef('drift_dev'), PackageRef('flutter_lints')], + ); + diff --git a/lib/presentation/views/main_menu/settings_view/licenses_view.dart b/lib/presentation/views/main_menu/settings_view/licenses_view.dart new file mode 100644 index 0000000..603162f --- /dev/null +++ b/lib/presentation/views/main_menu/settings_view/licenses_view.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; +import 'package:game_tracker/presentation/widgets/tiles/license_tile.dart'; + +class LicensesView extends StatelessWidget { + const LicensesView({super.key}); + + @override + Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); + + return Scaffold( + appBar: AppBar( + title: Text(loc.licenses), + backgroundColor: CustomTheme.backgroundColor, + ), + backgroundColor: CustomTheme.backgroundColor, + body: ListView.builder( + itemCount: allDependencies.length, + itemBuilder: (context, index) { + final package = allDependencies[index]; + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8), + child: LicenseTile(package: package), + ); + }, + ), + ); + } +} diff --git a/lib/presentation/views/main_menu/settings_view/settings_view.dart b/lib/presentation/views/main_menu/settings_view/settings_view.dart new file mode 100644 index 0000000..1843c90 --- /dev/null +++ b/lib/presentation/views/main_menu/settings_view/settings_view.dart @@ -0,0 +1,310 @@ +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/core/enums.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses_view.dart'; +import 'package:game_tracker/presentation/widgets/tiles/settings_list_tile.dart'; +import 'package:game_tracker/services/data_transfer_service.dart'; +import 'package:intl/intl.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class SettingsView extends StatefulWidget { + const SettingsView({super.key}); + + @override + State createState() => _SettingsViewState(); +} + +class _SettingsViewState extends State { + PackageInfo _packageInfo = PackageInfo( + appName: 'n.A.', + packageName: 'n.A.', + version: 'n.A.', + buildNumber: 'n.A.', + ); + @override + void initState() { + super.initState(); + _initPackageInfo(); + } + + @override + Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); + return ScaffoldMessenger( + child: Scaffold( + appBar: AppBar(backgroundColor: CustomTheme.backgroundColor), + backgroundColor: CustomTheme.backgroundColor, + body: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 16, bottom: 10), + child: Text( + textAlign: TextAlign.start, + loc.settings, + style: const TextStyle( + fontSize: 28, + fontWeight: FontWeight.bold, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 16, top: 10, bottom: 10), + child: Text( + textAlign: TextAlign.start, + loc.data, + style: const TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + ), + ), + ), + SettingsListTile( + title: loc.export_data, + icon: Icons.upload, + suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), + onPressed: () async { + final String json = + await DataTransferService.getAppDataAsJson(context); + final result = await DataTransferService.exportData( + json, + 'game_tracker-data', + ); + if (!context.mounted) return; + showExportSnackBar(context: context, result: result); + }, + ), + SettingsListTile( + title: loc.import_data, + icon: Icons.download, + suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), + onPressed: () async { + final result = await DataTransferService.importData(context); + if (!context.mounted) return; + showImportSnackBar(context: context, result: result); + }, + ), + SettingsListTile( + title: loc.delete_all_data, + icon: Icons.delete, + suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), + onPressed: () { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('${loc.delete_all_data}?'), + content: Text(loc.this_cannot_be_undone), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text(loc.cancel), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: Text(loc.delete), + ), + ], + ), + ).then((confirmed) { + if (confirmed == true && context.mounted) { + DataTransferService.deleteAllData(context); + showSnackbar( + context: context, + message: AppLocalizations.of( + context, + ).data_successfully_deleted, + ); + } + }); + }, + ), + Padding( + padding: const EdgeInsets.only(left: 16, top: 10, bottom: 10), + child: Text( + textAlign: TextAlign.start, + loc.legal, + style: const TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + ), + ), + ), + SettingsListTile( + title: loc.licenses, + icon: Icons.insert_drive_file, + suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const LicensesView(), + ), + ); + }, + ), + SettingsListTile( + title: loc.legal_notice, + icon: Icons.account_balance_sharp, + suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), + onPressed: null, + ), + SettingsListTile( + title: loc.privacy_policy, + icon: Icons.gpp_good_rounded, + suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16), + onPressed: null, + ), + Padding( + padding: const EdgeInsets.only(top: 30, bottom: 20), + child: Center( + child: Column( + spacing: 4, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 40, + children: [ + GestureDetector( + child: const Icon(Icons.language), + onTap: () => { + launchUrl(Uri.parse('https://liquid-dev.de')), + }, + ), + GestureDetector( + child: const FaIcon(FontAwesomeIcons.github), + onTap: () => { + launchUrl( + Uri.parse( + 'https://github.com/liquiddevelopmentde', + ), + ), + }, + ), + GestureDetector( + child: Icon( + Platform.isIOS + ? CupertinoIcons.mail_solid + : Icons.email, + ), + onTap: () => launchUrl( + Uri.parse('mailto:hi@liquid-dev.de'), + ), + ), + ], + ), + ), + Text( + '© ${DateFormat('yyyy').format(DateTime.now())} Liquid Development', + style: TextStyle( + color: Colors.grey.shade600, + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + Text( + 'Version ${_packageInfo.version} (${_packageInfo.buildNumber})', + style: TextStyle( + color: Colors.grey.shade600, + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ); + } + + /// Displays a snackbar based on the import result. + /// + /// [context] The BuildContext to show the snackbar in. + /// [result] The result of the import operation. + void showImportSnackBar({ + required BuildContext context, + required ImportResult result, + }) { + final loc = AppLocalizations.of(context); + switch (result) { + case ImportResult.success: + showSnackbar(context: context, message: loc.data_successfully_imported); + case ImportResult.invalidSchema: + showSnackbar(context: context, message: loc.invalid_schema); + case ImportResult.fileReadError: + showSnackbar(context: context, message: loc.error_reading_file); + case ImportResult.canceled: + showSnackbar(context: context, message: loc.import_canceled); + case ImportResult.formatException: + showSnackbar(context: context, message: loc.format_exception); + case ImportResult.unknownException: + showSnackbar(context: context, message: loc.unknown_exception); + } + } + + /// Displays a snackbar based on the export result. + /// + /// [context] The BuildContext to show the snackbar in. + /// [result] The result of the export operation. + void showExportSnackBar({ + required BuildContext context, + required ExportResult result, + }) { + final loc = AppLocalizations.of(context); + switch (result) { + case ExportResult.success: + showSnackbar(context: context, message: loc.data_successfully_exported); + case ExportResult.canceled: + showSnackbar(context: context, message: loc.export_canceled); + case ExportResult.unknownException: + showSnackbar(context: context, message: loc.unknown_exception); + } + } + + /// Displays a snackbar with the given message and optional action. + /// + /// [context] The BuildContext to show the snackbar in. + /// [message] The message to display in the snackbar. + /// [duration] The duration for which the snackbar is displayed. + /// [action] An optional callback function to execute when the action button is pressed. + void showSnackbar({ + required BuildContext context, + required String message, + Duration duration = const Duration(seconds: 3), + VoidCallback? action, + }) { + final loc = AppLocalizations.of(context); + final messenger = ScaffoldMessenger.of(context); + messenger.hideCurrentSnackBar(); + messenger.showSnackBar( + SnackBar( + content: Text(message, style: const TextStyle(color: Colors.white)), + backgroundColor: CustomTheme.onBoxColor, + duration: duration, + action: action != null + ? SnackBarAction(label: loc.undo, onPressed: action) + : null, + ), + ); + } + + /// Initializes the package information. + Future _initPackageInfo() async { + final info = await PackageInfo.fromPlatform(); + setState(() { + _packageInfo = info; + }); + } +} diff --git a/lib/presentation/views/main_menu/statistics_view.dart b/lib/presentation/views/main_menu/statistics_view.dart index 564d0d5..53569ad 100644 --- a/lib/presentation/views/main_menu/statistics_view.dart +++ b/lib/presentation/views/main_menu/statistics_view.dart @@ -1,9 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:game_tracker/core/constants.dart'; import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/game.dart'; +import 'package:game_tracker/data/dto/match.dart'; import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; import 'package:game_tracker/presentation/widgets/tiles/statistics_tile.dart'; +import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; class StatisticsView extends StatefulWidget { @@ -14,37 +17,20 @@ class StatisticsView extends StatefulWidget { } class _StatisticsViewState extends State { - late Future> _gamesFuture; - late Future> _playersFuture; List<(String, int)> winCounts = List.filled(6, ('Skeleton Player', 1)); - List<(String, int)> gameCounts = List.filled(6, ('Skeleton Player', 1)); + List<(String, int)> matchCounts = List.filled(6, ('Skeleton Player', 1)); List<(String, double)> winRates = List.filled(6, ('Skeleton Player', 1)); bool isLoading = true; @override void initState() { super.initState(); - final db = Provider.of(context, listen: false); - _gamesFuture = db.gameDao.getAllGames(); - _playersFuture = db.playerDao.getAllPlayers(); - - Future.wait([_gamesFuture, _playersFuture]).then((results) async { - await Future.delayed(const Duration(milliseconds: 250)); - final games = results[0] as List; - final players = results[1] as List; - winCounts = _calculateWinsForAllPlayers(games, players); - gameCounts = _calculateGameAmountsForAllPlayers(games, players); - winRates = computeWinRatePercent(wins: winCounts, games: gameCounts); - if (mounted) { - setState(() { - isLoading = false; - }); - } - }); + loadStatisticData(); } @override Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { return SingleChildScrollView( @@ -58,31 +44,48 @@ class _StatisticsViewState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(height: constraints.maxHeight * 0.01), - StatisticsTile( - icon: Icons.sports_score, - title: 'Wins per Player', - width: constraints.maxWidth * 0.95, - values: winCounts, - itemCount: 3, - barColor: Colors.blue, - ), - SizedBox(height: constraints.maxHeight * 0.02), - StatisticsTile( - icon: Icons.percent, - title: 'Winrate per Player', - width: constraints.maxWidth * 0.95, - values: winRates, - itemCount: 5, - barColor: Colors.orange[700]!, - ), - SizedBox(height: constraints.maxHeight * 0.02), - StatisticsTile( - icon: Icons.casino, - title: 'Games per Player', - width: constraints.maxWidth * 0.95, - values: gameCounts, - itemCount: 10, - barColor: Colors.green, + Visibility( + visible: + winCounts.isEmpty && + matchCounts.isEmpty && + winRates.isEmpty, + replacement: Column( + children: [ + StatisticsTile( + icon: Icons.sports_score, + title: loc.wins, + width: constraints.maxWidth * 0.95, + values: winCounts, + itemCount: 3, + barColor: Colors.green, + ), + SizedBox(height: constraints.maxHeight * 0.02), + StatisticsTile( + icon: Icons.percent, + title: loc.winrate, + width: constraints.maxWidth * 0.95, + values: winRates, + itemCount: 5, + barColor: Colors.orange[700]!, + ), + SizedBox(height: constraints.maxHeight * 0.02), + StatisticsTile( + icon: Icons.casino, + title: loc.amount_of_matches, + width: constraints.maxWidth * 0.95, + values: matchCounts, + itemCount: 10, + barColor: Colors.blue, + ), + ], + ), + child: TopCenteredMessage( + icon: Icons.info, + title: loc.info, + message: AppLocalizations.of( + context, + ).no_statistics_available, + ), ), SizedBox(height: MediaQuery.paddingOf(context).bottom), ], @@ -94,17 +97,49 @@ class _StatisticsViewState extends State { ); } + /// Loads matches and players from the database + /// and calculates statistics for each player + void loadStatisticData() { + final db = Provider.of(context, listen: false); + + Future.wait([ + db.matchDao.getAllMatches(), + db.playerDao.getAllPlayers(), + Future.delayed(Constants.minimumSkeletonDuration), + ]).then((results) async { + if (!mounted) return; + final matches = results[0] as List; + final players = results[1] as List; + winCounts = _calculateWinsForAllPlayers( + matches: matches, + players: players, + context: context, + ); + matchCounts = _calculateMatchAmountsForAllPlayers( + matches: matches, + players: players, + context: context, + ); + winRates = computeWinRatePercent(wins: winCounts, matches: matchCounts); + setState(() { + isLoading = false; + }); + }); + } + /// Calculates the number of wins for each player /// and returns a sorted list of tuples (playerName, winCount) - List<(String, int)> _calculateWinsForAllPlayers( - List games, - List players, - ) { + List<(String, int)> _calculateWinsForAllPlayers({ + required List matches, + required List players, + required BuildContext context, + }) { List<(String, int)> winCounts = []; + final loc = AppLocalizations.of(context); // Getting the winners - for (var game in games) { - final winner = game.winner; + for (var match in matches) { + final winner = match.winner; if (winner != null) { final index = winCounts.indexWhere((entry) => entry.$1 == winner.id); // -1 means winner not found in winCounts @@ -131,7 +166,7 @@ class _StatisticsViewState extends State { final playerId = winCounts[i].$1; final player = players.firstWhere( (p) => p.id == playerId, - orElse: () => Player(id: playerId, name: 'N.a.'), + orElse: () => Player(id: playerId, name: loc.not_available), ); winCounts[i] = (player.name, winCounts[i].$2); } @@ -141,83 +176,85 @@ class _StatisticsViewState extends State { return winCounts; } - /// Calculates the number of games played for each player - /// and returns a sorted list of tuples (playerName, gameCount) - List<(String, int)> _calculateGameAmountsForAllPlayers( - List games, - List players, - ) { - List<(String, int)> gameCounts = []; + /// Calculates the number of matches played for each player + /// and returns a sorted list of tuples (playerName, matchCount) + List<(String, int)> _calculateMatchAmountsForAllPlayers({ + required List matches, + required List players, + required BuildContext context, + }) { + List<(String, int)> matchCounts = []; + final loc = AppLocalizations.of(context); - // Counting games for each player - for (var game in games) { - if (game.group != null) { - final members = game.group!.members.map((p) => p.id).toList(); + // Counting matches for each player + for (var match in matches) { + if (match.group != null) { + final members = match.group!.members.map((p) => p.id).toList(); for (var playerId in members) { - final index = gameCounts.indexWhere((entry) => entry.$1 == playerId); - // -1 means player not found in gameCounts + final index = matchCounts.indexWhere((entry) => entry.$1 == playerId); + // -1 means player not found in matchCounts if (index != -1) { - final current = gameCounts[index].$2; - gameCounts[index] = (playerId, current + 1); + final current = matchCounts[index].$2; + matchCounts[index] = (playerId, current + 1); } else { - gameCounts.add((playerId, 1)); + matchCounts.add((playerId, 1)); } } } - if (game.players != null) { - final members = game.players!.map((p) => p.id).toList(); + if (match.players != null) { + final members = match.players!.map((p) => p.id).toList(); for (var playerId in members) { - final index = gameCounts.indexWhere((entry) => entry.$1 == playerId); - // -1 means player not found in gameCounts + final index = matchCounts.indexWhere((entry) => entry.$1 == playerId); + // -1 means player not found in matchCounts if (index != -1) { - final current = gameCounts[index].$2; - gameCounts[index] = (playerId, current + 1); + final current = matchCounts[index].$2; + matchCounts[index] = (playerId, current + 1); } else { - gameCounts.add((playerId, 1)); + matchCounts.add((playerId, 1)); } } } } - // Adding all players with zero games + // Adding all players with zero matches for (var player in players) { - final index = gameCounts.indexWhere((entry) => entry.$1 == player.id); - // -1 means player not found in gameCounts + final index = matchCounts.indexWhere((entry) => entry.$1 == player.id); + // -1 means player not found in matchCounts if (index == -1) { - gameCounts.add((player.id, 0)); + matchCounts.add((player.id, 0)); } } // Replace player IDs with names - for (int i = 0; i < gameCounts.length; i++) { - final playerId = gameCounts[i].$1; + for (int i = 0; i < matchCounts.length; i++) { + final playerId = matchCounts[i].$1; final player = players.firstWhere( (p) => p.id == playerId, - orElse: () => Player(id: playerId, name: 'N.a.'), + orElse: () => Player(id: playerId, name: loc.not_available), ); - gameCounts[i] = (player.name, gameCounts[i].$2); + matchCounts[i] = (player.name, matchCounts[i].$2); } - gameCounts.sort((a, b) => b.$2.compareTo(a.$2)); + matchCounts.sort((a, b) => b.$2.compareTo(a.$2)); - return gameCounts; + return matchCounts; } // dart List<(String, double)> computeWinRatePercent({ required List<(String, int)> wins, - required List<(String, int)> games, + required List<(String, int)> matches, }) { final Map winsMap = {for (var e in wins) e.$1: e.$2}; - final Map gamesMap = {for (var e in games) e.$1: e.$2}; + final Map matchesMap = {for (var e in matches) e.$1: e.$2}; // Get all unique player names - final names = {...winsMap.keys, ...gamesMap.keys}; + final names = {...winsMap.keys, ...matchesMap.keys}; // Calculate win rates final result = names.map((name) { final int w = winsMap[name] ?? 0; - final int g = gamesMap[name] ?? 0; + final int g = matchesMap[name] ?? 0; // Calculate percentage and round to 2 decimal places // Avoid division by zero final double percent = (g > 0) diff --git a/lib/presentation/widgets/app_skeleton.dart b/lib/presentation/widgets/app_skeleton.dart index 209f1d8..1d74456 100644 --- a/lib/presentation/widgets/app_skeleton.dart +++ b/lib/presentation/widgets/app_skeleton.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:skeletonizer/skeletonizer.dart'; +/// A widget that provides a skeleton loading effect to its child widget tree. +/// - [child]: The widget tree to apply the skeleton effect to. +/// - [enabled]: A boolean to enable or disable the skeleton effect. +/// - [fixLayoutBuilder]: A boolean to fix the layout builder for AnimatedSwitcher. class AppSkeleton extends StatefulWidget { - final Widget child; - final bool enabled; - final bool fixLayoutBuilder; - const AppSkeleton({ super.key, required this.child, @@ -13,6 +13,15 @@ class AppSkeleton extends StatefulWidget { this.fixLayoutBuilder = false, }); + /// The widget tree to apply the skeleton effect to. + final Widget child; + + /// A boolean to enable or disable the skeleton effect. + final bool enabled; + + /// A boolean to fix the layout builder for AnimatedSwitcher. + final bool fixLayoutBuilder; + @override State createState() => _AppSkeletonState(); } diff --git a/lib/presentation/widgets/buttons/custom_width_button.dart b/lib/presentation/widgets/buttons/custom_width_button.dart index 17c9dc5..7e52648 100644 --- a/lib/presentation/widgets/buttons/custom_width_button.dart +++ b/lib/presentation/widgets/buttons/custom_width_button.dart @@ -2,6 +2,12 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/core/enums.dart'; +/// A custom button widget that is designed to have a width relative to the screen size. +/// It supports three types of buttons: primary, secondary, and text buttons. +/// - [text]: The text to display on the button. +/// - [buttonType]: The type of button to display. Defaults to [ButtonType.primary]. +/// - [sizeRelativeToWidth]: The size of the button relative to the width of the screen. +/// - [onPressed]: The callback to be invoked when the button is pressed. class CustomWidthButton extends StatelessWidget { const CustomWidthButton({ super.key, @@ -11,9 +17,16 @@ class CustomWidthButton extends StatelessWidget { this.onPressed, }); + /// The text to display on the button. final String text; + + /// The size of the button relative to the width of the screen. final double sizeRelativeToWidth; + + /// The callback to be invoked when the button is pressed. final VoidCallback? onPressed; + + /// The type of button to display. Depends on the enum [ButtonType]. final ButtonType buttonType; @override @@ -47,7 +60,7 @@ class CustomWidthButton extends StatelessWidget { 60, ), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: CustomTheme.standardBorderRadiusAll, ), ), child: Text( @@ -78,7 +91,7 @@ class CustomWidthButton extends StatelessWidget { ), side: BorderSide(color: borderSideColor, width: 2), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: CustomTheme.standardBorderRadiusAll, ), ), child: Text( diff --git a/lib/presentation/widgets/buttons/quick_create_button.dart b/lib/presentation/widgets/buttons/quick_create_button.dart index 3860f1c..40ebeab 100644 --- a/lib/presentation/widgets/buttons/quick_create_button.dart +++ b/lib/presentation/widgets/buttons/quick_create_button.dart @@ -1,15 +1,22 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +/// A button widget designed for quick creating matches in the [HomeView] +/// - [text]: The text to display on the button. +/// - [onPressed]: The callback to be invoked when the button is pressed. class QuickCreateButton extends StatefulWidget { - final String text; - final VoidCallback? onPressed; const QuickCreateButton({ super.key, required this.text, required this.onPressed, }); + /// The text to display on the button. + final String text; + + /// The callback to be invoked when the button is pressed. + final VoidCallback? onPressed; + @override State createState() => _QuickCreateButtonState(); } @@ -22,7 +29,9 @@ class _QuickCreateButtonState extends State { style: ElevatedButton.styleFrom( minimumSize: const Size(140, 45), backgroundColor: CustomTheme.primaryColor, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + shape: RoundedRectangleBorder( + borderRadius: CustomTheme.standardBorderRadiusAll, + ), ), child: Text( widget.text, diff --git a/lib/presentation/widgets/navbar_item.dart b/lib/presentation/widgets/navbar_item.dart index b249571..13a8d4d 100644 --- a/lib/presentation/widgets/navbar_item.dart +++ b/lib/presentation/widgets/navbar_item.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; +/// A navigation bar item widget that represents a single tab in a navigation bar. +/// - [index]: The index of the tab. +/// - [isSelected]: A boolean indicating whether the tab is currently selected. +/// - [icon]: The icon to display for the tab. +/// - [label]: The label to display for the tab. +/// - [onTabTapped]: The callback to be invoked when the tab is tapped. class NavbarItem extends StatefulWidget { - final int index; - final bool isSelected; - final IconData icon; - final String label; - final Function(int) onTabTapped; - const NavbarItem({ super.key, required this.index, @@ -16,6 +16,21 @@ class NavbarItem extends StatefulWidget { required this.onTabTapped, }); + /// The index of the tab. + final int index; + + /// A boolean indicating whether the tab is currently selected. + final bool isSelected; + + /// The icon to display for the tab. + final IconData icon; + + /// The label to display for the tab. + final String label; + + /// The callback to be invoked when the tab is tapped. + final Function(int) onTabTapped; + @override State createState() => _NavbarItemState(); } diff --git a/lib/presentation/widgets/player_selection.dart b/lib/presentation/widgets/player_selection.dart index 092a613..9280ae0 100644 --- a/lib/presentation/widgets/player_selection.dart +++ b/lib/presentation/widgets/player_selection.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:game_tracker/core/constants.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/data/db/database.dart'; import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart'; import 'package:game_tracker/presentation/widgets/tiles/text_icon_list_tile.dart'; @@ -9,28 +11,55 @@ import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; +/// A widget that allows users to select players from a list, +/// with search functionality and the ability to add new players. +/// - [availablePlayers]: An optional list of players to choose from. If null, all +/// players from the database are used. +/// - [initialSelectedPlayers]: An optional list of players that should be pre-selected. +/// - [onChanged]: A callback function that is invoked whenever the selection changes, +/// providing the updated list of selected players. class PlayerSelection extends StatefulWidget { - final Function(List value) onChanged; - final List initialPlayers; - const PlayerSelection({ super.key, + this.availablePlayers, + this.initialSelectedPlayers, required this.onChanged, - this.initialPlayers = const [], }); + /// An optional list of players to choose from. If null, all players from the database are used. + final List? availablePlayers; + + /// An optional list of players that should be pre-selected. + final List? initialSelectedPlayers; + + /// A callback function that is invoked whenever the selection changes, + final Function(List value) onChanged; + @override State createState() => _PlayerSelectionState(); } class _PlayerSelectionState extends State { - List selectedPlayers = []; - List suggestedPlayers = []; + late final AppDatabase db; + bool isLoading = true; + + /// Future that loads all players from the database. + late Future> _allPlayersFuture; + + /// The complete list of all available players. List allPlayers = []; + + /// The list of players suggested based on the search input. + List suggestedPlayers = []; + + /// The list of currently selected players. + List selectedPlayers = []; + + /// Controller for the search bar input. late final TextEditingController _searchBarController = TextEditingController(); - late final AppDatabase db; - late Future> _allPlayersFuture; + + /// Skeleton data used while loading players. late final List skeletonData = List.filled( 7, Player(name: 'Player 0'), @@ -40,33 +69,15 @@ class _PlayerSelectionState extends State { void initState() { super.initState(); db = Provider.of(context, listen: false); - loadPlayerList(); - } - - void loadPlayerList() { - _allPlayersFuture = Future.delayed( - const Duration(milliseconds: 250), - () => db.playerDao.getAllPlayers(), - ); suggestedPlayers = skeletonData; - _allPlayersFuture.then((loadedPlayers) { - setState(() { - if (widget.initialPlayers.isNotEmpty) { - allPlayers = [...widget.initialPlayers]; - suggestedPlayers = [...widget.initialPlayers]; - } else { - loadedPlayers.sort((a, b) => a.name.compareTo(b.name)); - allPlayers = [...loadedPlayers]; - suggestedPlayers = [...loadedPlayers]; - } - }); - }); + loadPlayerList(); } @override Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); return Container( - margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + margin: CustomTheme.standardMargin, padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10), decoration: CustomTheme.standardBoxDecoration, child: Column( @@ -75,7 +86,7 @@ class _PlayerSelectionState extends State { CustomSearchBar( controller: _searchBarController, constraints: const BoxConstraints(maxHeight: 45, minHeight: 45), - hintText: 'Search for players', + hintText: loc.search_for_players, trailingButtonShown: true, trailingButtonicon: Icons.add_circle, trailingButtonEnabled: _searchBarController.text.trim().isNotEmpty, @@ -108,160 +119,206 @@ class _PlayerSelectionState extends State { ), const SizedBox(height: 10), Text( - 'Selected players: (${selectedPlayers.length})', + loc.selected_players, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), const SizedBox(height: 10), - Wrap( - alignment: WrapAlignment.start, - crossAxisAlignment: WrapCrossAlignment.start, - spacing: 8.0, - runSpacing: 8.0, - children: [ - // Generates a TextIconTile for each selected player. - for (var player in selectedPlayers) - TextIconTile( - text: player.name, - onIconTap: () { - setState(() { - // Removes the player from the selection and notifies the parent. - final currentSearch = _searchBarController.text - .toLowerCase(); - selectedPlayers.remove(player); - widget.onChanged([...selectedPlayers]); - // If the player matches the current search query (or search is empty), - // they are added back to the suggestions and the list is re-sorted. - if (currentSearch.isEmpty || - player.name.toLowerCase().contains(currentSearch)) { - suggestedPlayers.add(player); - } - }); - }, - ), - ], - ), - const SizedBox(height: 10), - const Text( - 'All players:', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 10), - FutureBuilder( - future: _allPlayersFuture, - builder: - (BuildContext context, AsyncSnapshot> snapshot) { - if (snapshot.hasError) { - return const Center( - child: TopCenteredMessage( - icon: Icons.report, - title: 'Error', - message: 'Player data couldn\'t\nbe loaded.', - ), - ); - } - bool doneLoading = - snapshot.connectionState == ConnectionState.done; - bool snapshotDataEmpty = - !snapshot.hasData || snapshot.data!.isEmpty; - if (doneLoading && - (snapshotDataEmpty && allPlayers.isEmpty)) { - return const Center( - child: TopCenteredMessage( - icon: Icons.info, - title: 'Info', - message: 'No players created yet.', - ), - ); - } - final bool isLoading = - snapshot.connectionState == ConnectionState.waiting; - return Expanded( - child: AppSkeleton( - enabled: isLoading, - child: Visibility( - visible: - (suggestedPlayers.isEmpty && allPlayers.isNotEmpty), - replacement: ListView.builder( - itemCount: suggestedPlayers.length, - itemBuilder: (BuildContext context, int index) { - return TextIconListTile( - text: suggestedPlayers[index].name, - onPressed: () { + SizedBox( + height: 50, + child: selectedPlayers.isEmpty + ? Center(child: Text(loc.no_players_selected)) + : SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + for (var player in selectedPlayers) + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: TextIconTile( + text: player.name, + onIconTap: () { setState(() { - if (!selectedPlayers.contains( - suggestedPlayers[index], - )) { - selectedPlayers.add( - suggestedPlayers[index], - ); - widget.onChanged([...selectedPlayers]); - suggestedPlayers.remove( - suggestedPlayers[index], + // Removes the player from the selection and notifies the parent. + selectedPlayers.remove(player); + widget.onChanged([...selectedPlayers]); + + // Get the current search query + final currentSearch = _searchBarController + .text + .toLowerCase(); + + // If the player matches the current search query (or search is empty), + // they are added back to the `suggestedPlayers` and the list is re-sorted. + if (currentSearch.isEmpty || + player.name.toLowerCase().contains( + currentSearch, + )) { + suggestedPlayers.add(player); + suggestedPlayers.sort( + (a, b) => a.name.compareTo(b.name), ); } }); }, - ); - }, - ), - child: TopCenteredMessage( - icon: Icons.info, - title: 'Info', - message: (selectedPlayers.length == allPlayers.length) - ? 'No more players to add.' - : 'No players found with that name.', - ), - ), + ), + ), + ], ), - ); - }, + ), + ), + const SizedBox(height: 10), + Text( + loc.all_players, + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 10), + Expanded( + child: AppSkeleton( + enabled: isLoading, + child: Visibility( + visible: suggestedPlayers.isNotEmpty, + replacement: TopCenteredMessage( + icon: Icons.info, + title: loc.info, + message: _getInfoText(context), + ), + child: ListView.builder( + itemCount: suggestedPlayers.length, + itemBuilder: (BuildContext context, int index) { + return TextIconListTile( + text: suggestedPlayers[index].name, + onPressed: () { + setState(() { + // If the player is not already selected + if (!selectedPlayers.contains( + suggestedPlayers[index], + )) { + // Add to player to the front of the selectedPlayers + selectedPlayers.insert(0, suggestedPlayers[index]); + // Notify the parent widget of the change + widget.onChanged([...selectedPlayers]); + // Remove the player from the suggestedPlayers + suggestedPlayers.remove(suggestedPlayers[index]); + } + }); + }, + ); + }, + ), + ), + ), ), ], ), ); } + /// Loads the list of players from the database or uses the provided available players. + /// Sets the loading state and updates the player lists accordingly. + void loadPlayerList() { + _allPlayersFuture = Future.wait([ + db.playerDao.getAllPlayers(), + Future.delayed(Constants.minimumSkeletonDuration), + ]).then((results) => results[0] as List); + if (mounted) { + _allPlayersFuture.then((loadedPlayers) { + setState(() { + // If a list of available players is provided (even if empty), use that list. + if (widget.availablePlayers != null) { + widget.availablePlayers!.sort((a, b) => a.name.compareTo(b.name)); + allPlayers = [...widget.availablePlayers!]; + suggestedPlayers = [...allPlayers]; + + if (widget.initialSelectedPlayers != null) { + // Ensures that only players available for selection are pre-selected. + selectedPlayers = widget.initialSelectedPlayers! + .where( + (p) => widget.availablePlayers!.any( + (available) => available.id == p.id, + ), + ) + .toList(); + } + } else { + // Otherwise, use the loaded players from the database. + loadedPlayers.sort((a, b) => a.name.compareTo(b.name)); + allPlayers = [...loadedPlayers]; + suggestedPlayers = [...loadedPlayers]; + } + isLoading = false; + }); + }); + } + } + /// Adds a new player to the database from the search bar input. /// Shows a snackbar indicating success or failure. /// [context] - BuildContext to show the snackbar. - void addNewPlayerFromSearch({required BuildContext context}) async { - String playerName = _searchBarController.text.trim(); - Player createdPlayer = Player(name: playerName); - bool success = await db.playerDao.addPlayer(player: createdPlayer); + Future addNewPlayerFromSearch({required BuildContext context}) async { + final loc = AppLocalizations.of(context); + final playerName = _searchBarController.text.trim(); + + final createdPlayer = Player(name: playerName); + final success = await db.playerDao.addPlayer(player: createdPlayer); + if (!context.mounted) return; + if (success) { - selectedPlayers.add(createdPlayer); - widget.onChanged([...selectedPlayers]); - allPlayers.add(createdPlayer); - setState(() { - _searchBarController.clear(); - suggestedPlayers = allPlayers.where((player) { - return !selectedPlayers.contains(player); - }).toList(); - }); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - backgroundColor: CustomTheme.boxColor, - content: Center( - child: Text( - 'Successfully added player $playerName.', - style: const TextStyle(color: Colors.white), - ), - ), - ), - ); + _handleSuccessfulPlayerCreation(createdPlayer); + showSnackBarMessage(loc.successfully_added_player(playerName)); } else { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - backgroundColor: CustomTheme.boxColor, - content: Center( - child: Text( - 'Could not add player $playerName.', - style: const TextStyle(color: Colors.white), - ), - ), + showSnackBarMessage(loc.could_not_add_player(playerName)); + } + } + + /// Updates the state after successfully adding a new player. + void _handleSuccessfulPlayerCreation(Player player) { + selectedPlayers.insert(0, player); + widget.onChanged([...selectedPlayers]); + allPlayers.add(player); + + setState(() { + _searchBarController.clear(); + _updateSuggestedPlayers(); + }); + } + + /// Updates the suggested players list based on current selection. + void _updateSuggestedPlayers() { + suggestedPlayers = allPlayers + .where((player) => !selectedPlayers.contains(player)) + .toList(); + } + + /// Displays a snackbar message at the bottom of the screen. + /// [message] - The message to display in the snackbar. + void showSnackBarMessage(String message) { + if (!context.mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: CustomTheme.boxColor, + content: Center( + child: Text(message, style: const TextStyle(color: Colors.white)), ), - ); + ), + ); + } + + /// Determines the appropriate info text to display when no players + /// are available in the suggested players list. + String _getInfoText(BuildContext context) { + final loc = AppLocalizations.of(context); + if (allPlayers.isEmpty) { + // No players exist in the database + return loc.no_players_created_yet; + } else if (selectedPlayers.length == allPlayers.length || + widget.availablePlayers?.isEmpty == true) { + // All players have been selected or + // available players list is provided but empty + return loc.all_players_selected; + } else { + // No players match the search query + return loc.no_players_found_with_that_name; } } } diff --git a/lib/presentation/widgets/text_input/custom_search_bar.dart b/lib/presentation/widgets/text_input/custom_search_bar.dart index e3fe976..bf7971a 100644 --- a/lib/presentation/widgets/text_input/custom_search_bar.dart +++ b/lib/presentation/widgets/text_input/custom_search_bar.dart @@ -1,16 +1,16 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +/// A custom search bar widget that encapsulates a [SearchBar] with additional customization options. +/// - [controller]: The controller for the search bar's text input. +/// - [hintText]: The hint text displayed in the search bar when it is empty. +/// - [trailingButtonShown]: Whether to show the trailing button. +/// - [trailingButtonicon]: The icon for the trailing button. +/// - [trailingButtonEnabled]: Whether the trailing button is in enabled state. +/// - [onTrailingButtonPressed]: The callback invoked when the trailing button is pressed. +/// - [onChanged]: The callback invoked when the text in the search bar changes. +/// - [constraints]: The constraints for the search bar. class CustomSearchBar extends StatelessWidget { - final TextEditingController controller; - final String hintText; - final ValueChanged? onChanged; - final BoxConstraints? constraints; - final bool trailingButtonShown; - final bool trailingButtonEnabled; - final VoidCallback? onTrailingButtonPressed; - final IconData trailingButtonicon; - const CustomSearchBar({ super.key, required this.controller, @@ -23,6 +23,30 @@ class CustomSearchBar extends StatelessWidget { this.constraints, }); + /// The controller for the search bar's text input. + final TextEditingController controller; + + /// The hint text displayed in the search bar when it is empty. + final String hintText; + + /// Whether to show the trailing button. + final bool trailingButtonShown; + + /// The icon for the trailing button. + final IconData trailingButtonicon; + + /// Whether the trailing button is in enabled state. + final bool trailingButtonEnabled; + + /// The callback invoked when the trailing button is pressed. + final VoidCallback? onTrailingButtonPressed; + + /// The callback invoked when the text in the search bar changes. + final ValueChanged? onChanged; + + /// The constraints for the search bar. + final BoxConstraints? constraints; + @override Widget build(BuildContext context) { return SearchBar( @@ -30,7 +54,7 @@ class CustomSearchBar extends StatelessWidget { constraints: constraints ?? const BoxConstraints(maxHeight: 45, minHeight: 45), hintText: hintText, - onChanged: trailingButtonEnabled ? onChanged : null, + onChanged: onChanged, hintStyle: WidgetStateProperty.all(const TextStyle(fontSize: 16)), leading: const Icon(Icons.search), trailing: [ diff --git a/lib/presentation/widgets/text_input/text_input_field.dart b/lib/presentation/widgets/text_input/text_input_field.dart index 6cd9d75..a409c68 100644 --- a/lib/presentation/widgets/text_input/text_input_field.dart +++ b/lib/presentation/widgets/text_input/text_input_field.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +/// A custom text input field widget that encapsulates a [TextField] with specific styling. +/// - [controller]: The controller for the text input field. +/// - [onChanged]: The callback invoked when the text in the field changes. +/// - [hintText]: The hint text displayed in the text input field when it is empty class TextInputField extends StatelessWidget { - final TextEditingController controller; - final ValueChanged? onChanged; - final String hintText; - const TextInputField({ super.key, required this.controller, @@ -13,6 +13,15 @@ class TextInputField extends StatelessWidget { this.onChanged, }); + /// The controller for the text input field. + final TextEditingController controller; + + /// The callback invoked when the text in the field changes. + final ValueChanged? onChanged; + + /// The hint text displayed in the text input field when it is empty. + final String hintText; + @override Widget build(BuildContext context) { return TextField( diff --git a/lib/presentation/widgets/tiles/choose_tile.dart b/lib/presentation/widgets/tiles/choose_tile.dart index 10a695d..f6ec940 100644 --- a/lib/presentation/widgets/tiles/choose_tile.dart +++ b/lib/presentation/widgets/tiles/choose_tile.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +/// A tile widget that allows users to choose an option by tapping on it. +/// - [title]: The title text displayed on the tile. +/// - [trailingText]: Optional trailing text displayed on the tile. +/// - [onPressed]: The callback invoked when the tile is tapped. class ChooseTile extends StatefulWidget { - final String title; - final VoidCallback? onPressed; - final String? trailingText; const ChooseTile({ super.key, required this.title, @@ -12,6 +13,15 @@ class ChooseTile extends StatefulWidget { this.onPressed, }); + /// The title text displayed on the tile. + final String title; + + /// The callback invoked when the tile is tapped. + final VoidCallback? onPressed; + + /// Optional trailing text displayed on the tile. + final String? trailingText; + @override State createState() => _ChooseTileState(); } @@ -22,8 +32,8 @@ class _ChooseTileState extends State { return GestureDetector( onTap: widget.onPressed, child: Container( - margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 5), - padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15), + margin: CustomTheme.tileMargin, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: CustomTheme.standardBoxDecoration, child: Row( children: [ diff --git a/lib/presentation/widgets/tiles/custom_radio_list_tile.dart b/lib/presentation/widgets/tiles/custom_radio_list_tile.dart index 11e8b40..706aabb 100644 --- a/lib/presentation/widgets/tiles/custom_radio_list_tile.dart +++ b/lib/presentation/widgets/tiles/custom_radio_list_tile.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +/// A custom radio list tile widget that encapsulates a [Radio] button with additional styling and functionality. +/// - [text]: The text to display next to the radio button. +/// - [value]: The value associated with the radio button. +/// - [onContainerTap]: The callback invoked when the container is tapped. class CustomRadioListTile extends StatelessWidget { - final String text; - final T value; - final ValueChanged onContainerTap; - const CustomRadioListTile({ super.key, required this.text, @@ -13,6 +13,15 @@ class CustomRadioListTile extends StatelessWidget { required this.onContainerTap, }); + /// The text to display next to the radio button. + final String text; + + /// The value associated with the radio button. + final T value; + + /// The callback invoked when the container is tapped. + final ValueChanged onContainerTap; + @override Widget build(BuildContext context) { return GestureDetector( @@ -23,7 +32,7 @@ class CustomRadioListTile extends StatelessWidget { decoration: BoxDecoration( color: CustomTheme.boxColor, border: Border.all(color: CustomTheme.boxBorder), - borderRadius: BorderRadius.circular(12), + borderRadius: CustomTheme.standardBorderRadiusAll, ), child: Row( children: [ diff --git a/lib/presentation/widgets/tiles/game_history_tile.dart b/lib/presentation/widgets/tiles/game_history_tile.dart deleted file mode 100644 index 83da859..0000000 --- a/lib/presentation/widgets/tiles/game_history_tile.dart +++ /dev/null @@ -1,180 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; -import 'package:game_tracker/data/dto/game.dart'; -import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; -import 'package:intl/intl.dart'; - -class GameHistoryTile extends StatefulWidget { - final Game game; - final VoidCallback onTap; - - const GameHistoryTile({super.key, required this.game, required this.onTap}); - - @override - State createState() => _GameHistoryTileState(); -} - -class _GameHistoryTileState extends State { - @override - Widget build(BuildContext context) { - final group = widget.game.group; - final winner = widget.game.winner; - final allPlayers = _getAllPlayers(); - - return GestureDetector( - onTap: widget.onTap, - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: CustomTheme.boxColor, - border: Border.all(color: CustomTheme.boxBorder), - borderRadius: BorderRadius.circular(12), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - widget.game.name, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - overflow: TextOverflow.ellipsis, - ), - ), - Text( - _formatDate(widget.game.createdAt), - style: const TextStyle(fontSize: 12, color: Colors.grey), - ), - ], - ), - - const SizedBox(height: 8), - - if (group != null) ...[ - Row( - children: [ - const Icon(Icons.group, size: 16, color: Colors.grey), - const SizedBox(width: 6), - Expanded( - child: Text( - group.name, - style: const TextStyle(fontSize: 14, color: Colors.grey), - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - const SizedBox(height: 12), - ], - - if (winner != null) ...[ - Container( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 12, - ), - decoration: BoxDecoration( - color: Colors.green.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: Colors.green.withValues(alpha: 0.3), - width: 1, - ), - ), - child: Row( - children: [ - const Icon( - Icons.emoji_events, - size: 20, - color: Colors.amber, - ), - const SizedBox(width: 8), - Expanded( - child: Text( - 'Winner: ${winner.name}', - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Colors.white, - ), - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ), - const SizedBox(height: 12), - ], - - if (allPlayers.isNotEmpty) ...[ - const Text( - 'Players', - style: TextStyle( - fontSize: 13, - color: Colors.grey, - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 6), - Wrap( - spacing: 6, - runSpacing: 6, - children: allPlayers.map((player) { - return TextIconTile(text: player.name, iconEnabled: false); - }).toList(), - ), - ], - ], - ), - ), - ); - } - - String _formatDate(DateTime dateTime) { - final now = DateTime.now(); - final difference = now.difference(dateTime); - - if (difference.inDays == 0) { - return 'Today at ${DateFormat('HH:mm').format(dateTime)}'; - } else if (difference.inDays == 1) { - return 'Yesterday at ${DateFormat('HH:mm').format(dateTime)}'; - } else if (difference.inDays < 7) { - return '${difference.inDays} days ago'; - } else { - return DateFormat('MMM d, yyyy').format(dateTime); - } - } - - List _getAllPlayers() { - final allPlayers = []; - final playerIds = {}; - - // Add players from game.players - if (widget.game.players != null) { - for (var player in widget.game.players!) { - if (!playerIds.contains(player.id)) { - allPlayers.add(player); - playerIds.add(player.id); - } - } - } - - // Add players from game.group.players - if (widget.game.group?.members != null) { - for (var player in widget.game.group!.members) { - if (!playerIds.contains(player.id)) { - allPlayers.add(player); - playerIds.add(player.id); - } - } - } - - return allPlayers; - } -} diff --git a/lib/presentation/widgets/tiles/group_tile.dart b/lib/presentation/widgets/tiles/group_tile.dart index 248c1c6..64d9caa 100644 --- a/lib/presentation/widgets/tiles/group_tile.dart +++ b/lib/presentation/widgets/tiles/group_tile.dart @@ -3,16 +3,22 @@ import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/data/dto/group.dart'; import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; +/// A tile widget that displays information about a group, including its name and members. +/// - [group]: The group data to be displayed. +/// - [isHighlighted]: Whether the tile should be highlighted. class GroupTile extends StatelessWidget { const GroupTile({super.key, required this.group, this.isHighlighted = false}); + /// The group data to be displayed. final Group group; + + /// Whether the tile should be highlighted. final bool isHighlighted; @override Widget build(BuildContext context) { return AnimatedContainer( - margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + margin: CustomTheme.standardMargin, padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), decoration: isHighlighted ? CustomTheme.highlightedBoxDecoration @@ -56,7 +62,9 @@ class GroupTile extends StatelessWidget { spacing: 12.0, runSpacing: 8.0, children: [ - for (var member in group.members) + for (var member in [ + ...group.members, + ]..sort((a, b) => a.name.compareTo(b.name))) TextIconTile(text: member.name, iconEnabled: false), ], ), diff --git a/lib/presentation/widgets/tiles/info_tile.dart b/lib/presentation/widgets/tiles/info_tile.dart index ff73e59..3e11679 100644 --- a/lib/presentation/widgets/tiles/info_tile.dart +++ b/lib/presentation/widgets/tiles/info_tile.dart @@ -1,13 +1,14 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +/// A tile widget that displays a title with an icon and some content below it. +/// - [title]: The title text displayed on the tile. +/// - [icon]: The icon displayed next to the title. +/// - [content]: The content widget displayed below the title. +/// - [padding]: Optional padding for the tile content. +/// - [height]: Optional height for the tile. +/// - [width]: Optional width for the tile. class InfoTile extends StatefulWidget { - final String title; - final IconData icon; - final Widget content; - final EdgeInsets? padding; - final double? height; - final double? width; const InfoTile({ super.key, required this.title, @@ -18,6 +19,24 @@ class InfoTile extends StatefulWidget { this.width, }); + /// The title text displayed on the tile. + final String title; + + /// The icon displayed next to the title. + final IconData icon; + + /// The content widget displayed below the title. + final Widget content; + + /// Optional padding for the tile content. + final EdgeInsets? padding; + + /// Optional height for the tile. + final double? height; + + /// Optional width for the tile. + final double? width; + @override State createState() => _InfoTileState(); } diff --git a/lib/presentation/widgets/tiles/license_tile.dart b/lib/presentation/widgets/tiles/license_tile.dart new file mode 100644 index 0000000..5850d9e --- /dev/null +++ b/lib/presentation/widgets/tiles/license_tile.dart @@ -0,0 +1,106 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart'; +import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart'; + +class LicenseTile extends StatelessWidget { + final Package package; + + const LicenseTile({super.key, required this.package}); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => LicenseDetailView(package: package), + ), + ); + }, + child: Container( + margin: const EdgeInsets.only(bottom: 8), + padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 12), + decoration: CustomTheme.standardBoxDecoration.copyWith( + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Container( + width: 50, + height: 50, + decoration: BoxDecoration( + color: CustomTheme.primaryColor.withAlpha(40), + borderRadius: BorderRadius.circular(10), + ), + child: Icon( + Icons.description, + color: CustomTheme.primaryColor, + size: 32, + ), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Flexible( + child: Text( + package.name, + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + ), + if (package.version != null && + package.version!.isNotEmpty) ...[ + const SizedBox(width: 12), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 2, + ), + decoration: BoxDecoration( + color: CustomTheme.onBoxColor, + borderRadius: BorderRadius.circular(6), + ), + child: Text( + 'v${package.version}', + style: TextStyle( + fontSize: 11, + color: Colors.grey.shade500, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ], + ), + const SizedBox(height: 4), + Text( + package.description, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 13, + color: Colors.grey.shade400, + height: 1.3, + ), + ), + ], + ), + ), + const SizedBox(width: 12), + // Arrow Icon + Icon(Icons.chevron_right, color: Colors.grey.shade600, size: 24), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/widgets/tiles/game_tile.dart b/lib/presentation/widgets/tiles/match_summary_tile.dart similarity index 86% rename from lib/presentation/widgets/tiles/game_tile.dart rename to lib/presentation/widgets/tiles/match_summary_tile.dart index fcd2f65..719037b 100644 --- a/lib/presentation/widgets/tiles/game_tile.dart +++ b/lib/presentation/widgets/tiles/match_summary_tile.dart @@ -2,27 +2,27 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:skeletonizer/skeletonizer.dart'; -class GameTile extends StatefulWidget { - final String gameTitle; - final String gameType; +class MatchSummaryTile extends StatefulWidget { + final String matchTitle; + final String game; final String ruleset; final String players; final String winner; - const GameTile({ + const MatchSummaryTile({ super.key, - required this.gameTitle, - required this.gameType, + required this.matchTitle, + required this.game, required this.ruleset, required this.players, required this.winner, }); @override - State createState() => _GameTileState(); + State createState() => _MatchSummaryTileState(); } -class _GameTileState extends State { +class _MatchSummaryTileState extends State { @override Widget build(BuildContext context) { return Column( @@ -31,12 +31,12 @@ class _GameTileState extends State { Row( children: [ Text( - widget.gameTitle, + widget.matchTitle, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(width: 5), Text( - widget.gameType, + widget.game, style: const TextStyle(fontSize: 14, color: Colors.grey), ), ], diff --git a/lib/presentation/widgets/tiles/match_tile.dart b/lib/presentation/widgets/tiles/match_tile.dart new file mode 100644 index 0000000..88ae1f1 --- /dev/null +++ b/lib/presentation/widgets/tiles/match_tile.dart @@ -0,0 +1,266 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; +import 'package:game_tracker/data/dto/match.dart'; +import 'package:game_tracker/data/dto/player.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; +import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart'; +import 'package:intl/intl.dart'; + +/// A tile widget that displays information about a match, including its name, +/// creation date, associated group, winner, and players. +/// - [match]: The match data to be displayed. +/// - [onTap]: The callback invoked when the tile is tapped. +/// - [width]: Optional width for the tile. +/// - [compact]: Whether to display the tile in a compact mode +class MatchTile extends StatefulWidget { + const MatchTile({ + super.key, + required this.match, + required this.onTap, + this.width, + this.compact = false, + }); + + /// The match data to be displayed. + final Match match; + + /// The callback invoked when the tile is tapped. + final VoidCallback onTap; + + /// Optional width for the tile. + final double? width; + + /// Whether to display the tile in a compact mode + final bool compact; + + @override + State createState() => _MatchTileState(); +} + +class _MatchTileState extends State { + late final List _allPlayers; + + @override + void initState() { + super.initState(); + _allPlayers = _getCombinedPlayers(); + } + + @override + Widget build(BuildContext context) { + final group = widget.match.group; + final winner = widget.match.winner; + final loc = AppLocalizations.of(context); + + return GestureDetector( + onTap: widget.onTap, + child: Container( + margin: EdgeInsets.zero, + width: widget.width, + padding: const EdgeInsets.all(12), + decoration: CustomTheme.standardBoxDecoration, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + widget.match.name, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + overflow: TextOverflow.ellipsis, + ), + ), + Text( + _formatDate(widget.match.createdAt, context), + style: const TextStyle(fontSize: 12, color: Colors.grey), + ), + ], + ), + + const SizedBox(height: 8), + + if (group != null) ...[ + Row( + children: [ + const Icon(Icons.group, size: 16, color: Colors.grey), + const SizedBox(width: 6), + Expanded( + child: Text( + '${group.name}${widget.match.players != null ? ' + ${widget.match.players?.length}' : ''}', + style: const TextStyle(fontSize: 14, color: Colors.grey), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + const SizedBox(height: 12), + ] else if (widget.compact) ...[ + Row( + children: [ + const Icon(Icons.person, size: 16, color: Colors.grey), + const SizedBox(width: 6), + Expanded( + child: Text( + '${widget.match.players!.length} ${loc.players}', + style: const TextStyle(fontSize: 14, color: Colors.grey), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + const SizedBox(height: 12), + ], + + if (winner != null) ...[ + Container( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 12, + ), + decoration: BoxDecoration( + color: Colors.green.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: Colors.green.withValues(alpha: 0.3), + width: 1, + ), + ), + child: Row( + children: [ + const Icon( + Icons.emoji_events, + size: 20, + color: Colors.amber, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + '${loc.winner}: ${winner.name}', + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: CustomTheme.textColor, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + const SizedBox(height: 12), + ] else ...[ + Container( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 12, + ), + decoration: BoxDecoration( + color: Colors.amber.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: Colors.amber.withValues(alpha: 0.3), + width: 1, + ), + ), + child: Row( + children: [ + const Icon( + Icons.watch_later, + size: 20, + color: Colors.amber, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + loc.match_in_progress, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: CustomTheme.textColor, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + const SizedBox(height: 12), + ], + + if (_allPlayers.isNotEmpty && widget.compact == false) ...[ + Text( + loc.players, + style: const TextStyle( + fontSize: 13, + color: Colors.grey, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 6), + Wrap( + spacing: 6, + runSpacing: 6, + children: _allPlayers.map((player) { + return TextIconTile(text: player.name, iconEnabled: false); + }).toList(), + ), + ], + ], + ), + ), + ); + } + + /// Formats the given [dateTime] into a human-readable string based on its + /// difference from the current date. + String _formatDate(DateTime dateTime, BuildContext context) { + final now = DateTime.now(); + final difference = now.difference(dateTime); + final loc = AppLocalizations.of(context); + + if (difference.inDays == 0) { + return "${loc.today_at} ${DateFormat('HH:mm').format(dateTime)}"; + } else if (difference.inDays == 1) { + return "${loc.yesterday_at} ${DateFormat('HH:mm').format(dateTime)}"; + } else if (difference.inDays < 7) { + return loc.days_ago(difference.inDays); + } else { + return DateFormat('MMM d, yyyy').format(dateTime); + } + } + + /// Retrieves all unique players associated with the match, + /// combining players from both the match and its group. + List _getCombinedPlayers() { + final allPlayers = []; + final playerIds = {}; + + // Add players from game.players + if (widget.match.players != null) { + for (var player in widget.match.players!) { + if (!playerIds.contains(player.id)) { + allPlayers.add(player); + playerIds.add(player.id); + } + } + } + + // Add players from game.group.players + if (widget.match.group?.members != null) { + for (var player in widget.match.group!.members) { + if (!playerIds.contains(player.id)) { + allPlayers.add(player); + playerIds.add(player.id); + } + } + } + + allPlayers.sort((a, b) => a.name.compareTo(b.name)); + return allPlayers; + } +} diff --git a/lib/presentation/widgets/tiles/quick_info_tile.dart b/lib/presentation/widgets/tiles/quick_info_tile.dart index d360aba..839f6c3 100644 --- a/lib/presentation/widgets/tiles/quick_info_tile.dart +++ b/lib/presentation/widgets/tiles/quick_info_tile.dart @@ -1,13 +1,14 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +/// A tile widget that displays a title with an icon and a numeric value below it. +/// - [title]: The title text displayed on the tile. +/// - [icon]: The icon displayed next to the title. +/// - [value]: The numeric value displayed below the title. +/// - [height]: Optional height for the tile. +/// - [width]: Optional width for the tile. +/// - [padding]: Optional padding for the tile content. class QuickInfoTile extends StatefulWidget { - final String title; - final IconData icon; - final int value; - final double? height; - final double? width; - final EdgeInsets? padding; const QuickInfoTile({ super.key, required this.title, @@ -18,6 +19,24 @@ class QuickInfoTile extends StatefulWidget { this.padding, }); + /// The title text displayed on the tile. + final String title; + + /// The icon displayed next to the title. + final IconData icon; + + /// The numeric value displayed below the title. + final int value; + + /// Optional height for the tile. + final double? height; + + /// Optional width for the tile. + final double? width; + + /// Optional padding for the tile content. + final EdgeInsets? padding; + @override State createState() => _QuickInfoTileState(); } diff --git a/lib/presentation/widgets/tiles/ruleset_list_tile.dart b/lib/presentation/widgets/tiles/ruleset_list_tile.dart deleted file mode 100644 index 13eaf82..0000000 --- a/lib/presentation/widgets/tiles/ruleset_list_tile.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:game_tracker/core/custom_theme.dart'; - -class RulesetListTile extends StatelessWidget { - final String title; - final String description; - final VoidCallback? onPressed; - final bool isHighlighted; - - const RulesetListTile({ - super.key, - required this.title, - required this.description, - this.onPressed, - this.isHighlighted = false, - }); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onPressed, - child: AnimatedContainer( - margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), - padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12), - decoration: isHighlighted - ? CustomTheme.highlightedBoxDecoration - : CustomTheme.standardBoxDecoration, - duration: const Duration(milliseconds: 200), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: Text( - title, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), - ), - ], - ), - const SizedBox(height: 5), - Text(description, style: const TextStyle(fontSize: 14)), - const SizedBox(height: 2.5), - ], - ), - ), - ); - } -} diff --git a/lib/presentation/widgets/tiles/settings_list_tile.dart b/lib/presentation/widgets/tiles/settings_list_tile.dart index 6b43557..ba05225 100644 --- a/lib/presentation/widgets/tiles/settings_list_tile.dart +++ b/lib/presentation/widgets/tiles/settings_list_tile.dart @@ -1,19 +1,32 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +/// A customizable settings list tile widget that displays an icon, title, and an optional suffix widget. +/// - [icon]: The icon displayed on the left side of the tile. +/// - [title]: The title text displayed next to the icon. +/// - [suffixWidget]: An optional widget displayed on the right side of the tile. +/// - [onPressed]: The callback invoked when the tile is tapped. class SettingsListTile extends StatelessWidget { - final VoidCallback? onPressed; - final IconData icon; - final String title; - final Widget? suffixWidget; const SettingsListTile({ super.key, - required this.title, required this.icon, + required this.title, this.suffixWidget, this.onPressed, }); + /// The icon displayed on the left side of the tile. + final IconData icon; + + /// The title text displayed next to the icon. + final String title; + + /// An optional widget displayed on the right side of the tile. + final Widget? suffixWidget; + + /// The callback invoked when the tile is tapped. + final VoidCallback? onPressed; + @override Widget build(BuildContext context) { return Padding( @@ -25,7 +38,7 @@ class SettingsListTile extends StatelessWidget { onTap: onPressed ?? () {}, child: Container( margin: EdgeInsets.zero, - padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 14), + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), decoration: CustomTheme.standardBoxDecoration, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -34,12 +47,17 @@ class SettingsListTile extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Container( - padding: const EdgeInsets.all(8), + width: 44, + height: 44, decoration: BoxDecoration( - color: CustomTheme.primaryColor, - shape: BoxShape.circle, + color: CustomTheme.primaryColor.withAlpha(40), + borderRadius: BorderRadius.circular(10), + ), + child: Icon( + icon, + size: 28, + color: CustomTheme.primaryColor.withGreen(40), ), - child: Icon(icon, size: 24), ), const SizedBox(width: 16), Text(title, style: const TextStyle(fontSize: 18)), diff --git a/lib/presentation/widgets/tiles/statistics_tile.dart b/lib/presentation/widgets/tiles/statistics_tile.dart index 6e3b9b2..2c0ced0 100644 --- a/lib/presentation/widgets/tiles/statistics_tile.dart +++ b/lib/presentation/widgets/tiles/statistics_tile.dart @@ -1,8 +1,16 @@ import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart'; +/// A tile widget that displays statistical data using horizontal bars. +/// - [icon]: The icon displayed next to the title. +/// - [title]: The title text displayed on the tile. +/// - [width]: The width of the tile. +/// - [values]: A list of tuples containing labels and their corresponding numeric values. +/// - [itemCount]: The maximum number of items to display. +/// - [barColor]: The color of the bars representing the values. class StatisticsTile extends StatelessWidget { const StatisticsTile({ super.key, @@ -14,16 +22,27 @@ class StatisticsTile extends StatelessWidget { required this.barColor, }); + /// The icon displayed next to the title. final IconData icon; + + /// The title text displayed on the tile. final String title; + + /// The width of the tile. final double width; + + /// A list of tuples containing labels and their corresponding numeric values. final List<(String, num)> values; + + /// The maximum number of items to display. final int itemCount; + + /// The color of the bars representing the values. final Color barColor; @override Widget build(BuildContext context) { - final maxBarWidth = MediaQuery.of(context).size.width * 0.65; + final loc = AppLocalizations.of(context); return InfoTile( width: width, @@ -33,42 +52,60 @@ class StatisticsTile extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 20.0), child: Visibility( visible: values.isNotEmpty, - replacement: const Center( + replacement: Center( heightFactor: 4, - child: Text('No data available.'), + child: Text(loc.no_data_available), ), - child: Column( - children: List.generate(min(values.length, itemCount), (index) { - /// The maximum wins among all players - final maxGames = values.isNotEmpty ? values[0].$2 : 0; + child: LayoutBuilder( + builder: (context, constraints) { + final maxBarWidth = constraints.maxWidth * 0.65; + return Column( + children: List.generate(min(values.length, itemCount), (index) { + /// The maximum wins among all players + final maxMatches = values.isNotEmpty ? values[0].$2 : 0; - /// Fraction of wins - final double fraction = (maxGames > 0) - ? (values[index].$2 / maxGames) - : 0.0; + /// Fraction of wins + final double fraction = (maxMatches > 0) + ? (values[index].$2 / maxMatches) + : 0.0; - /// Calculated width for current the bar - final double barWidth = maxBarWidth * fraction; + /// Calculated width for current the bar + final double barWidth = maxBarWidth * fraction; - return Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Stack( + return Padding( + padding: const EdgeInsets.symmetric(vertical: 2.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, children: [ - Container( - height: 24, - width: barWidth, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: barColor, - ), + Stack( + children: [ + Container( + height: 24, + width: barWidth, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: barColor, + ), + ), + Padding( + padding: const EdgeInsets.only(left: 4.0), + child: Text( + values[index].$1, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ], ), - Padding( - padding: const EdgeInsets.only(left: 4.0), + const Spacer(), + Center( child: Text( - values[index].$1, + values[index].$2 <= 1 && values[index].$2 is double + ? values[index].$2.toStringAsFixed(2) + : values[index].$2.toString(), + textAlign: TextAlign.center, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, @@ -77,23 +114,10 @@ class StatisticsTile extends StatelessWidget { ), ], ), - const Spacer(), - Center( - child: Text( - values[index].$2 <= 1 && values[index].$2 is double - ? values[index].$2.toStringAsFixed(2) - : values[index].$2.toString(), - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), + ); + }), ); - }), + }, ), ), ), diff --git a/lib/presentation/widgets/tiles/text_icon_list_tile.dart b/lib/presentation/widgets/tiles/text_icon_list_tile.dart index b23ef75..7d3fe1c 100644 --- a/lib/presentation/widgets/tiles/text_icon_list_tile.dart +++ b/lib/presentation/widgets/tiles/text_icon_list_tile.dart @@ -1,18 +1,27 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +/// A list tile widget that displays text with an optional icon button. +/// - [text]: The text to display in the tile. +/// - [onPressed]: The callback to be invoked when the icon is pressed. +/// - [iconEnabled]: A boolean to determine if the icon should be displayed. class TextIconListTile extends StatelessWidget { - final String text; - final VoidCallback? onPressed; - final bool iconEnabled; - const TextIconListTile({ super.key, required this.text, - this.onPressed, this.iconEnabled = true, + this.onPressed, }); + /// The text to display in the tile. + final String text; + + /// A boolean to determine if the icon should be displayed. + final bool iconEnabled; + + /// The callback to be invoked when the icon is pressed. + final VoidCallback? onPressed; + @override Widget build(BuildContext context) { return Container( diff --git a/lib/presentation/widgets/tiles/text_icon_tile.dart b/lib/presentation/widgets/tiles/text_icon_tile.dart index 2544837..7142b27 100644 --- a/lib/presentation/widgets/tiles/text_icon_tile.dart +++ b/lib/presentation/widgets/tiles/text_icon_tile.dart @@ -1,18 +1,27 @@ import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; +/// A tile widget that displays text with an optional icon that can be tapped. +/// - [text]: The text to display in the tile. +/// - [iconEnabled]: A boolean to determine if the icon should be displayed. +/// - [onIconTap]: The callback to be invoked when the icon is tapped. class TextIconTile extends StatelessWidget { - final String text; - final bool iconEnabled; - final VoidCallback? onIconTap; - const TextIconTile({ super.key, required this.text, - this.onIconTap, this.iconEnabled = true, + this.onIconTap, }); + /// The text to display in the tile. + final String text; + + /// A boolean to determine if the icon should be displayed. + final bool iconEnabled; + + /// The callback to be invoked when the icon is tapped. + final VoidCallback? onIconTap; + @override Widget build(BuildContext context) { return Container( diff --git a/lib/presentation/widgets/tiles/title_description_list_tile.dart b/lib/presentation/widgets/tiles/title_description_list_tile.dart new file mode 100644 index 0000000..781149e --- /dev/null +++ b/lib/presentation/widgets/tiles/title_description_list_tile.dart @@ -0,0 +1,110 @@ +import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; + +/// A list tile widget that displays a title and description, with optional highlighting and badge. +/// - [title]: The title text displayed on the tile. +/// - [description]: The description text displayed below the title. +/// - [onPressed]: The callback invoked when the tile is tapped. +/// - [isHighlighted]: A boolean to determine if the tile should be highlighted. +/// - [badgeText]: Optional text to display in a badge on the right side of the title. +/// - [badgeColor]: Optional color for the badge background. +class TitleDescriptionListTile extends StatelessWidget { + const TitleDescriptionListTile({ + super.key, + required this.title, + required this.description, + this.onPressed, + this.isHighlighted = false, + this.badgeText, + this.badgeColor, + }); + + /// The title text displayed on the tile. + final String title; + + /// The description text displayed below the title. + final String description; + + /// The callback invoked when the tile is tapped. + final VoidCallback? onPressed; + + /// A boolean to determine if the tile should be highlighted. + final bool isHighlighted; + + /// Optional text to display in a badge on the right side of the title. + final String? badgeText; + + /// Optional color for the badge background. + final Color? badgeColor; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onPressed, + child: AnimatedContainer( + margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 10), + padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12), + decoration: isHighlighted + ? CustomTheme.highlightedBoxDecoration + : CustomTheme.standardBoxDecoration, + duration: const Duration(milliseconds: 200), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + width: 230, + child: Text( + title, + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + ), + if (badgeText != null) ...[ + const Spacer(), + Container( + constraints: const BoxConstraints(maxWidth: 115), + margin: const EdgeInsets.only(top: 4), + padding: const EdgeInsets.symmetric( + vertical: 2, + horizontal: 6, + ), + decoration: BoxDecoration( + color: badgeColor ?? CustomTheme.primaryColor, + borderRadius: BorderRadius.circular(4), + ), + child: Text( + badgeText!, + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + style: const TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ], + ), + if (description.isNotEmpty) ...[ + const SizedBox(height: 5), + Text(description, style: const TextStyle(fontSize: 14)), + const SizedBox(height: 2.5), + ], + ], + ), + ), + ); + } +} diff --git a/lib/presentation/widgets/top_centered_message.dart b/lib/presentation/widgets/top_centered_message.dart index a5deea2..c15c93d 100644 --- a/lib/presentation/widgets/top_centered_message.dart +++ b/lib/presentation/widgets/top_centered_message.dart @@ -1,5 +1,9 @@ import 'package:flutter/material.dart'; +/// A widget that displays a message centered at the top of the screen with an icon, title, and message. +/// - [icon]: The icon to display above the title. +/// - [title]: The title text to display. +/// - [message]: The message text to display below the title. class TopCenteredMessage extends StatelessWidget { const TopCenteredMessage({ super.key, @@ -8,10 +12,15 @@ class TopCenteredMessage extends StatelessWidget { required this.message, }); - final String title; - final String message; + /// The icon to display above the title. final IconData icon; + /// The title text to display. + final String title; + + /// The message text to display below the title. + final String message; + @override Widget build(BuildContext context) { return Container( diff --git a/lib/services/data_transfer_service.dart b/lib/services/data_transfer_service.dart index f040b0a..8767c59 100644 --- a/lib/services/data_transfer_service.dart +++ b/lib/services/data_transfer_service.dart @@ -6,8 +6,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:game_tracker/core/enums.dart'; import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/game.dart'; import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/match.dart'; import 'package:game_tracker/data/dto/player.dart'; import 'package:json_schema/json_schema.dart'; import 'package:provider/provider.dart'; @@ -16,7 +16,7 @@ class DataTransferService { /// Deletes all data from the database. static Future deleteAllData(BuildContext context) async { final db = Provider.of(context, listen: false); - await db.gameDao.deleteAllGames(); + await db.matchDao.deleteAllMatches(); await db.groupDao.deleteAllGroups(); await db.playerDao.deleteAllPlayers(); } @@ -25,15 +25,31 @@ class DataTransferService { /// Returns the JSON string representation of the data. static Future getAppDataAsJson(BuildContext context) async { final db = Provider.of(context, listen: false); - final games = await db.gameDao.getAllGames(); + final matches = await db.matchDao.getAllMatches(); final groups = await db.groupDao.getAllGroups(); final players = await db.playerDao.getAllPlayers(); // Construct a JSON representation of the data final Map jsonMap = { - 'games': games.map((game) => game.toJson()).toList(), - 'groups': groups.map((group) => group.toJson()).toList(), - 'players': players.map((player) => player.toJson()).toList(), + 'players': players.map((p) => p.toJson()).toList(), + + 'groups': groups + .map((g) => { + 'id': g.id, + 'name': g.name, + 'createdAt': g.createdAt.toIso8601String(), + 'memberIds': (g.members).map((m) => m.id).toList(), + }).toList(), + + 'matches': matches + .map((m) => { + 'id': m.id, + 'name': m.name, + 'createdAt': m.createdAt.toIso8601String(), + 'groupId': m.group?.id, + 'playerIds': (m.players ?? []).map((p) => p.id).toList(), + 'winnerId': m.winner?.id, + }).toList(), }; return json.encode(jsonMap); @@ -46,7 +62,7 @@ class DataTransferService { /// [fileName] The desired name for the exported file (without extension). static Future exportData( String jsonString, - String fileName, + String fileName ) async { try { final bytes = Uint8List.fromList(utf8.encode(jsonString)); @@ -54,11 +70,13 @@ class DataTransferService { fileName: '$fileName.json', bytes: bytes, ); + if (path == null) { return ExportResult.canceled; } else { return ExportResult.success; } + } catch (e, stack) { print('[exportData] $e'); print(stack); @@ -81,41 +99,77 @@ class DataTransferService { try { final jsonString = await _readFileContent(path.files.single); - if (jsonString == null) { - return ImportResult.fileReadError; - } + if (jsonString == null) return ImportResult.fileReadError; - if (await _validateJsonSchema(jsonString)) { - final Map jsonData = - json.decode(jsonString) as Map; + final isValid = await _validateJsonSchema(jsonString); + if (!isValid) return ImportResult.invalidSchema; - final List? gamesJson = jsonData['games'] as List?; - final List? groupsJson = jsonData['groups'] as List?; - final List? playersJson = - jsonData['players'] as List?; + final Map decoded = json.decode(jsonString) as Map; - final List importedGames = - gamesJson - ?.map((g) => Game.fromJson(g as Map)) - .toList() ?? - []; - final List importedGroups = - groupsJson - ?.map((g) => Group.fromJson(g as Map)) - .toList() ?? - []; - final List importedPlayers = - playersJson - ?.map((p) => Player.fromJson(p as Map)) - .toList() ?? - []; + final List playersJson = (decoded['players'] as List?) ?? []; + final List groupsJson = (decoded['groups'] as List?) ?? []; + final List matchesJson = (decoded['matches'] as List?) ?? []; + + // Players + final List importedPlayers = playersJson + .map((p) => Player.fromJson(p as Map)) + .toList(); + + final Map playerById = { + for (final p in importedPlayers) p.id: p, + }; + + // Groups + final List importedGroups = groupsJson.map((g) { + final map = g as Map; + final memberIds = (map['memberIds'] as List? ?? []).cast(); + + final members = memberIds + .map((id) => playerById[id]) + .whereType() + .toList(); + + return Group( + id: map['id'] as String, + name: map['name'] as String, + members: members, + createdAt: DateTime.parse(map['createdAt'] as String), + ); + }).toList(); + + final Map groupById = { + for (final g in importedGroups) g.id: g, + }; + + // Matches + final List importedMatches = matchesJson.map((m) { + final map = m as Map; + + final String? groupId = map['groupId'] as String?; + final List playerIds = (map['playerIds'] as List? ?? []).cast(); + final String? winnerId = map['winnerId'] as String?; + + final group = (groupId == null) ? null : groupById[groupId]; + final players = playerIds + .map((id) => playerById[id]) + .whereType() + .toList(); + final winner = (winnerId == null) ? null : playerById[winnerId]; + + return Match( + id: map['id'] as String, + name: map['name'] as String, + group: group, + players: players, + createdAt: DateTime.parse(map['createdAt'] as String), + winner: winner, + ); + }).toList(); + + await db.playerDao.addPlayersAsList(players: importedPlayers); + await db.groupDao.addGroupsAsList(groups: importedGroups); + await db.matchDao.addMatchAsList(matches: importedMatches); - await db.playerDao.addPlayersAsList(players: importedPlayers); - await db.groupDao.addGroupsAsList(groups: importedGroups); - await db.gameDao.addGamesAsList(games: importedGames); - } else { - return ImportResult.invalidSchema; - } return ImportResult.success; } on FormatException catch (e, stack) { print('[importData] FormatException'); @@ -158,4 +212,4 @@ class DataTransferService { return false; } } -} +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 07e4df2..2afff43 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.1+21 +version: 0.0.5+143 environment: sdk: ^3.8.1 @@ -9,31 +9,35 @@ environment: dependencies: flutter: sdk: flutter - material_symbols_icons: ^4.2815.1 - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.8 + flutter_localizations: + sdk: flutter + clock: ^1.1.2 + cupertino_icons: ^1.0.6 drift: ^2.27.0 drift_flutter: ^0.2.4 + file_picker: ^10.3.6 + file_saver: ^0.3.1 + font_awesome_flutter: ^10.12.0 + intl: any + json_schema: ^5.2.2 + package_info_plus: ^9.0.0 path_provider: ^2.1.5 provider: ^6.1.5 skeletonizer: ^2.1.0+1 + url_launcher: ^6.3.2 uuid: ^4.5.2 - file_picker: ^10.3.6 - json_schema: ^5.2.2 - file_saver: ^0.3.1 - clock: ^1.1.2 - intl: ^0.18.0 + dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^5.0.0 - drift_dev: ^2.27.0 build_runner: ^2.5.4 + dart_pubspec_licenses: ^3.0.14 + drift_dev: ^2.27.0 + flutter_lints: ^5.0.0 flutter: uses-material-design: true + generate: true assets: - assets/schema.json diff --git a/test/db_tests/game_test.dart b/test/db_tests/game_test.dart index 4a5cc32..0ec2cfc 100644 --- a/test/db_tests/game_test.dart +++ b/test/db_tests/game_test.dart @@ -3,8 +3,8 @@ import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/game.dart'; import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/match.dart'; import 'package:game_tracker/data/dto/player.dart'; void main() { @@ -16,14 +16,14 @@ void main() { late Player testPlayer5; late Group testGroup1; late Group testGroup2; - late Game testGame1; - late Game testGame2; - late Game testGameOnlyPlayers; - late Game testGameOnlyGroup; + late Match testMatch1; + late Match testMatch2; + late Match testMatchOnlyPlayers; + late Match testMatchOnlyGroup; final fixedDate = DateTime(2025, 19, 11, 00, 11, 23); final fakeClock = Clock(() => fixedDate); - setUp(() { + setUp(() async { database = AppDatabase( DatabaseConnection( NativeDatabase.memory(), @@ -46,46 +46,61 @@ void main() { name: 'Test Group 2', members: [testPlayer4, testPlayer5], ); - testGame1 = Game( - name: 'First Test Game', + testMatch1 = Match( + name: 'First Test Match', group: testGroup1, players: [testPlayer4, testPlayer5], winner: testPlayer4, ); - testGame2 = Game( - name: 'Second Test Game', + testMatch2 = Match( + name: 'Second Test Match', group: testGroup2, players: [testPlayer1, testPlayer2, testPlayer3], winner: testPlayer2, ); - testGameOnlyPlayers = Game( - name: 'Test Game with Players', + testMatchOnlyPlayers = Match( + name: 'Test Match with Players', players: [testPlayer1, testPlayer2, testPlayer3], winner: testPlayer3, ); - testGameOnlyGroup = Game(name: 'Test Game with Group', group: testGroup2); + testMatchOnlyGroup = Match( + name: 'Test Match with Group', + group: testGroup2, + ); }); + await database.playerDao.addPlayersAsList( + players: [ + testPlayer1, + testPlayer2, + testPlayer3, + testPlayer4, + testPlayer5, + ], + ); + await database.groupDao.addGroupsAsList(groups: [testGroup1, testGroup2]); }); tearDown(() async { await database.close(); }); - group('Game Tests', () { - test('Adding and fetching single game works correctly', () async { - await database.gameDao.addGame(game: testGame1); + group('Match Tests', () { + test('Adding and fetching single match works correctly', () async { + await database.matchDao.addMatch(match: testMatch1); - final result = await database.gameDao.getGameById(gameId: testGame1.id); + final result = await database.matchDao.getMatchById( + matchId: testMatch1.id, + ); - expect(result.id, testGame1.id); - expect(result.name, testGame1.name); - expect(result.createdAt, testGame1.createdAt); + expect(result.id, testMatch1.id); + expect(result.name, testMatch1.name); + expect(result.createdAt, testMatch1.createdAt); - if (result.winner != null && testGame1.winner != null) { - expect(result.winner!.id, testGame1.winner!.id); - expect(result.winner!.name, testGame1.winner!.name); - expect(result.winner!.createdAt, testGame1.winner!.createdAt); + if (result.winner != null && testMatch1.winner != null) { + expect(result.winner!.id, testMatch1.winner!.id); + expect(result.winner!.name, testMatch1.winner!.name); + expect(result.winner!.createdAt, testMatch1.winner!.createdAt); } else { - expect(result.winner, testGame1.winner); + expect(result.winner, testMatch1.winner); } if (result.group != null) { @@ -99,188 +114,203 @@ void main() { fail('Group is null'); } if (result.players != null) { - expect(result.players!.length, testGame1.players!.length); + expect(result.players!.length, testMatch1.players!.length); - for (int i = 0; i < testGame1.players!.length; i++) { - expect(result.players![i].id, testGame1.players![i].id); - expect(result.players![i].name, testGame1.players![i].name); - expect(result.players![i].createdAt, testGame1.players![i].createdAt); + for (int i = 0; i < testMatch1.players!.length; i++) { + expect(result.players![i].id, testMatch1.players![i].id); + expect(result.players![i].name, testMatch1.players![i].name); + expect( + result.players![i].createdAt, + testMatch1.players![i].createdAt, + ); } } else { fail('Players is null'); } }); - test('Adding and fetching multiple games works correctly', () async { - await database.gameDao.addGamesAsList( - games: [testGame1, testGame2, testGameOnlyGroup, testGameOnlyPlayers], + test('Adding and fetching multiple matches works correctly', () async { + await database.matchDao.addMatchAsList( + matches: [ + testMatch1, + testMatch2, + testMatchOnlyGroup, + testMatchOnlyPlayers, + ], ); - final allGames = await database.gameDao.getAllGames(); - expect(allGames.length, 4); + final allMatches = await database.matchDao.getAllMatches(); + expect(allMatches.length, 4); - final testGames = { - testGame1.id: testGame1, - testGame2.id: testGame2, - testGameOnlyGroup.id: testGameOnlyGroup, - testGameOnlyPlayers.id: testGameOnlyPlayers, + final testMatches = { + testMatch1.id: testMatch1, + testMatch2.id: testMatch2, + testMatchOnlyGroup.id: testMatchOnlyGroup, + testMatchOnlyPlayers.id: testMatchOnlyPlayers, }; - for (final game in allGames) { - final testGame = testGames[game.id]!; + for (final match in allMatches) { + final testMatch = testMatches[match.id]!; - // Game-Checks - expect(game.id, testGame.id); - expect(game.name, testGame.name); - expect(game.createdAt, testGame.createdAt); - if (game.winner != null && testGame.winner != null) { - expect(game.winner!.id, testGame.winner!.id); - expect(game.winner!.name, testGame.winner!.name); - expect(game.winner!.createdAt, testGame.winner!.createdAt); + // Match-Checks + expect(match.id, testMatch.id); + expect(match.name, testMatch.name); + expect(match.createdAt, testMatch.createdAt); + if (match.winner != null && testMatch.winner != null) { + expect(match.winner!.id, testMatch.winner!.id); + expect(match.winner!.name, testMatch.winner!.name); + expect(match.winner!.createdAt, testMatch.winner!.createdAt); } else { - expect(game.winner, testGame.winner); + expect(match.winner, testMatch.winner); } // Group-Checks - if (testGame.group != null) { - expect(game.group!.id, testGame.group!.id); - expect(game.group!.name, testGame.group!.name); - expect(game.group!.createdAt, testGame.group!.createdAt); + if (testMatch.group != null) { + expect(match.group!.id, testMatch.group!.id); + expect(match.group!.name, testMatch.group!.name); + expect(match.group!.createdAt, testMatch.group!.createdAt); // Group Members-Checks - expect(game.group!.members.length, testGame.group!.members.length); - for (int i = 0; i < testGame.group!.members.length; i++) { - expect(game.group!.members[i].id, testGame.group!.members[i].id); + expect(match.group!.members.length, testMatch.group!.members.length); + for (int i = 0; i < testMatch.group!.members.length; i++) { + expect(match.group!.members[i].id, testMatch.group!.members[i].id); expect( - game.group!.members[i].name, - testGame.group!.members[i].name, + match.group!.members[i].name, + testMatch.group!.members[i].name, ); expect( - game.group!.members[i].createdAt, - testGame.group!.members[i].createdAt, + match.group!.members[i].createdAt, + testMatch.group!.members[i].createdAt, ); } } else { - expect(game.group, null); + expect(match.group, null); } // Players-Checks - if (testGame.players != null) { - expect(game.players!.length, testGame.players!.length); - for (int i = 0; i < testGame.players!.length; i++) { - expect(game.players![i].id, testGame.players![i].id); - expect(game.players![i].name, testGame.players![i].name); - expect(game.players![i].createdAt, testGame.players![i].createdAt); + if (testMatch.players != null) { + expect(match.players!.length, testMatch.players!.length); + for (int i = 0; i < testMatch.players!.length; i++) { + expect(match.players![i].id, testMatch.players![i].id); + expect(match.players![i].name, testMatch.players![i].name); + expect( + match.players![i].createdAt, + testMatch.players![i].createdAt, + ); } } else { - expect(game.players, null); + expect(match.players, null); } } }); - test('Adding the same game twice does not create duplicates', () async { - await database.gameDao.addGame(game: testGame1); - await database.gameDao.addGame(game: testGame1); + test('Adding the same match twice does not create duplicates', () async { + await database.matchDao.addMatch(match: testMatch1); + await database.matchDao.addMatch(match: testMatch1); - final gameCount = await database.gameDao.getGameCount(); - expect(gameCount, 1); + final matchCount = await database.matchDao.getMatchCount(); + expect(matchCount, 1); }); - test('Game existence check works correctly', () async { - var gameExists = await database.gameDao.gameExists(gameId: testGame1.id); - expect(gameExists, false); - - await database.gameDao.addGame(game: testGame1); - - gameExists = await database.gameDao.gameExists(gameId: testGame1.id); - expect(gameExists, true); - }); - - test('Deleting a game works correctly', () async { - await database.gameDao.addGame(game: testGame1); - - final gameDeleted = await database.gameDao.deleteGame( - gameId: testGame1.id, + test('Match existence check works correctly', () async { + var matchExists = await database.matchDao.matchExists( + matchId: testMatch1.id, ); - expect(gameDeleted, true); + expect(matchExists, false); - final gameExists = await database.gameDao.gameExists( - gameId: testGame1.id, + await database.matchDao.addMatch(match: testMatch1); + + matchExists = await database.matchDao.matchExists(matchId: testMatch1.id); + expect(matchExists, true); + }); + + test('Deleting a match works correctly', () async { + await database.matchDao.addMatch(match: testMatch1); + + final matchDeleted = await database.matchDao.deleteMatch( + matchId: testMatch1.id, ); - expect(gameExists, false); + expect(matchDeleted, true); + + final matchExists = await database.matchDao.matchExists( + matchId: testMatch1.id, + ); + expect(matchExists, false); }); - test('Getting the game count works correctly', () async { - var gameCount = await database.gameDao.getGameCount(); - expect(gameCount, 0); + test('Getting the match count works correctly', () async { + var matchCount = await database.matchDao.getMatchCount(); + expect(matchCount, 0); - await database.gameDao.addGame(game: testGame1); + await database.matchDao.addMatch(match: testMatch1); - gameCount = await database.gameDao.getGameCount(); - expect(gameCount, 1); + matchCount = await database.matchDao.getMatchCount(); + expect(matchCount, 1); - await database.gameDao.addGame(game: testGame2); + await database.matchDao.addMatch(match: testMatch2); - gameCount = await database.gameDao.getGameCount(); - expect(gameCount, 2); + matchCount = await database.matchDao.getMatchCount(); + expect(matchCount, 2); - await database.gameDao.deleteGame(gameId: testGame1.id); + await database.matchDao.deleteMatch(matchId: testMatch1.id); - gameCount = await database.gameDao.getGameCount(); - expect(gameCount, 1); + matchCount = await database.matchDao.getMatchCount(); + expect(matchCount, 1); - await database.gameDao.deleteGame(gameId: testGame2.id); + await database.matchDao.deleteMatch(matchId: testMatch2.id); - gameCount = await database.gameDao.getGameCount(); - expect(gameCount, 0); + matchCount = await database.matchDao.getMatchCount(); + expect(matchCount, 0); }); - test('Checking if game has winner works correclty', () async { - await database.gameDao.addGame(game: testGame1); - await database.gameDao.addGame(game: testGameOnlyGroup); + test('Checking if match has winner works correctly', () async { + await database.matchDao.addMatch(match: testMatch1); + await database.matchDao.addMatch(match: testMatchOnlyGroup); - var hasWinner = await database.gameDao.hasWinner(gameId: testGame1.id); + var hasWinner = await database.matchDao.hasWinner(matchId: testMatch1.id); expect(hasWinner, true); - hasWinner = await database.gameDao.hasWinner( - gameId: testGameOnlyGroup.id, + hasWinner = await database.matchDao.hasWinner( + matchId: testMatchOnlyGroup.id, ); expect(hasWinner, false); }); - test('Fetching the winner of a game works correctly', () async { - await database.gameDao.addGame(game: testGame1); + test('Fetching the winner of a match works correctly', () async { + await database.matchDao.addMatch(match: testMatch1); - final winner = await database.gameDao.getWinner(gameId: testGame1.id); + final winner = await database.matchDao.getWinner(matchId: testMatch1.id); if (winner == null) { fail('Winner is null'); } else { - expect(winner.id, testGame1.winner!.id); - expect(winner.name, testGame1.winner!.name); - expect(winner.createdAt, testGame1.winner!.createdAt); + expect(winner.id, testMatch1.winner!.id); + expect(winner.name, testMatch1.winner!.name); + expect(winner.createdAt, testMatch1.winner!.createdAt); } }); - test('Updating the winner of a game works correctly', () async { - await database.gameDao.addGame(game: testGame1); + test('Updating the winner of a match works correctly', () async { + await database.matchDao.addMatch(match: testMatch1); - final winner = await database.gameDao.getWinner(gameId: testGame1.id); + final winner = await database.matchDao.getWinner(matchId: testMatch1.id); if (winner == null) { fail('Winner is null'); } else { - expect(winner.id, testGame1.winner!.id); - expect(winner.name, testGame1.winner!.name); - expect(winner.createdAt, testGame1.winner!.createdAt); + expect(winner.id, testMatch1.winner!.id); + expect(winner.name, testMatch1.winner!.name); + expect(winner.createdAt, testMatch1.winner!.createdAt); expect(winner.id, testPlayer4.id); expect(winner.id != testPlayer5.id, true); } - await database.gameDao.setWinner( - gameId: testGame1.id, + await database.matchDao.setWinner( + matchId: testMatch1.id, winnerId: testPlayer5.id, ); - final newWinner = await database.gameDao.getWinner(gameId: testGame1.id); + final newWinner = await database.matchDao.getWinner( + matchId: testMatch1.id, + ); if (newWinner == null) { fail('New winner is null'); @@ -292,39 +322,41 @@ void main() { }); test('Removing a winner works correctly', () async { - await database.gameDao.addGame(game: testGame2); + await database.matchDao.addMatch(match: testMatch2); - var hasWinner = await database.gameDao.hasWinner(gameId: testGame2.id); + var hasWinner = await database.matchDao.hasWinner(matchId: testMatch2.id); expect(hasWinner, true); - await database.gameDao.removeWinner(gameId: testGame2.id); + await database.matchDao.removeWinner(matchId: testMatch2.id); - hasWinner = await database.gameDao.hasWinner(gameId: testGame2.id); + hasWinner = await database.matchDao.hasWinner(matchId: testMatch2.id); expect(hasWinner, false); - final removedWinner = await database.gameDao.getWinner( - gameId: testGame2.id, + final removedWinner = await database.matchDao.getWinner( + matchId: testMatch2.id, ); expect(removedWinner, null); }); - test('Renaming a game works correctly', () async { - await database.gameDao.addGame(game: testGame1); + test('Renaming a match works correctly', () async { + await database.matchDao.addMatch(match: testMatch1); - var fetchedGame = await database.gameDao.getGameById( - gameId: testGame1.id, + var fetchedMatch = await database.matchDao.getMatchById( + matchId: testMatch1.id, ); - expect(fetchedGame.name, testGame1.name); + expect(fetchedMatch.name, testMatch1.name); - const newName = 'Updated Game Name'; - await database.gameDao.updateGameName( - gameId: testGame1.id, + const newName = 'Updated Match Name'; + await database.matchDao.updateMatchName( + matchId: testMatch1.id, newName: newName, ); - fetchedGame = await database.gameDao.getGameById(gameId: testGame1.id); - expect(fetchedGame.name, newName); + fetchedMatch = await database.matchDao.getMatchById( + matchId: testMatch1.id, + ); + expect(fetchedMatch.name, newName); }); }); } diff --git a/test/db_tests/group_game_test.dart b/test/db_tests/group_match_test.dart similarity index 50% rename from test/db_tests/group_game_test.dart rename to test/db_tests/group_match_test.dart index 1e9b8fc..7d812bd 100644 --- a/test/db_tests/group_game_test.dart +++ b/test/db_tests/group_match_test.dart @@ -1,10 +1,10 @@ import 'package:clock/clock.dart'; -import 'package:drift/drift.dart'; +import 'package:drift/drift.dart' hide isNotNull; import 'package:drift/native.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/game.dart'; import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/match.dart'; import 'package:game_tracker/data/dto/player.dart'; void main() { @@ -16,12 +16,12 @@ void main() { late Player testPlayer5; late Group testGroup1; late Group testGroup2; - late Game testgameWithGroup; - late Game testgameWithPlayers; + late Match testMatchWithGroup; + late Match testMatchWithPlayers; final fixedDate = DateTime(2025, 19, 11, 00, 11, 23); final fakeClock = Clock(() => fixedDate); - setUp(() { + setUp(() async { database = AppDatabase( DatabaseConnection( NativeDatabase.memory(), @@ -44,81 +44,94 @@ void main() { name: 'Test Group', members: [testPlayer3, testPlayer2], ); - testgameWithPlayers = Game( - name: 'Test Game with Players', + testMatchWithPlayers = Match( + name: 'Test Match with Players', players: [testPlayer4, testPlayer5], ); - testgameWithGroup = Game(name: 'Test Game with Group', group: testGroup1); + testMatchWithGroup = Match( + name: 'Test Match with Group', + group: testGroup1, + ); }); + await database.playerDao.addPlayersAsList( + players: [ + testPlayer1, + testPlayer2, + testPlayer3, + testPlayer4, + testPlayer5, + ], + ); + await database.groupDao.addGroupsAsList(groups: [testGroup1, testGroup2]); }); tearDown(() async { await database.close(); }); - group('Group-Game Tests', () { - test('Game has group works correctly', () async { - await database.gameDao.addGame(game: testgameWithPlayers); + group('Group-Match Tests', () { + test('matchHasGroup() has group works correctly', () async { + await database.matchDao.addMatch(match: testMatchWithPlayers); await database.groupDao.addGroup(group: testGroup1); - var gameHasGroup = await database.groupGameDao.gameHasGroup( - gameId: testgameWithPlayers.id, + var matchHasGroup = await database.groupMatchDao.matchHasGroup( + matchId: testMatchWithPlayers.id, ); - expect(gameHasGroup, false); + expect(matchHasGroup, false); - await database.groupGameDao.addGroupToGame( - gameId: testgameWithPlayers.id, + await database.groupMatchDao.addGroupToMatch( + matchId: testMatchWithPlayers.id, groupId: testGroup1.id, ); - gameHasGroup = await database.groupGameDao.gameHasGroup( - gameId: testgameWithPlayers.id, + matchHasGroup = await database.groupMatchDao.matchHasGroup( + matchId: testMatchWithPlayers.id, ); - expect(gameHasGroup, true); + expect(matchHasGroup, true); }); - test('Adding a group to a game works correctly', () async { - await database.gameDao.addGame(game: testgameWithPlayers); + test('Adding a group to a match works correctly', () async { + await database.matchDao.addMatch(match: testMatchWithPlayers); await database.groupDao.addGroup(group: testGroup1); - await database.groupGameDao.addGroupToGame( - gameId: testgameWithPlayers.id, + await database.groupMatchDao.addGroupToMatch( + matchId: testMatchWithPlayers.id, groupId: testGroup1.id, ); - var groupAdded = await database.groupGameDao.isGroupInGame( - gameId: testgameWithPlayers.id, + var groupAdded = await database.groupMatchDao.isGroupInMatch( + matchId: testMatchWithPlayers.id, groupId: testGroup1.id, ); expect(groupAdded, true); - groupAdded = await database.groupGameDao.isGroupInGame( - gameId: testgameWithPlayers.id, + groupAdded = await database.groupMatchDao.isGroupInMatch( + matchId: testMatchWithPlayers.id, groupId: '', ); expect(groupAdded, false); }); - test('Removing group from game works correctly', () async { - await database.gameDao.addGame(game: testgameWithGroup); + test('Removing group from match works correctly', () async { + await database.matchDao.addMatch(match: testMatchWithGroup); - final groupToRemove = testgameWithGroup.group!; + final groupToRemove = testMatchWithGroup.group!; - final removed = await database.groupGameDao.removeGroupFromGame( + final removed = await database.groupMatchDao.removeGroupFromMatch( groupId: groupToRemove.id, - gameId: testgameWithGroup.id, + matchId: testMatchWithGroup.id, ); expect(removed, true); - final result = await database.gameDao.getGameById( - gameId: testgameWithGroup.id, + final result = await database.matchDao.getMatchById( + matchId: testMatchWithGroup.id, ); expect(result.group, null); }); - test('Retrieving group of a game works correctly', () async { - await database.gameDao.addGame(game: testgameWithGroup); - final group = await database.groupGameDao.getGroupOfGame( - gameId: testgameWithGroup.id, + test('Retrieving group of a match works correctly', () async { + await database.matchDao.addMatch(match: testMatchWithGroup); + final group = await database.groupMatchDao.getGroupOfMatch( + matchId: testMatchWithGroup.id, ); if (group == null) { @@ -136,11 +149,11 @@ void main() { } }); - test('Updating the group of a game works correctly', () async { - await database.gameDao.addGame(game: testgameWithGroup); + test('Updating the group of a match works correctly', () async { + await database.matchDao.addMatch(match: testMatchWithGroup); - var group = await database.groupGameDao.getGroupOfGame( - gameId: testgameWithGroup.id, + var group = await database.groupMatchDao.getGroupOfMatch( + matchId: testMatchWithGroup.id, ); if (group == null) { @@ -153,13 +166,13 @@ void main() { } await database.groupDao.addGroup(group: testGroup2); - await database.groupGameDao.updateGroupOfGame( - gameId: testgameWithGroup.id, + await database.groupMatchDao.updateGroupOfMatch( + matchId: testMatchWithGroup.id, newGroupId: testGroup2.id, ); - group = await database.groupGameDao.getGroupOfGame( - gameId: testgameWithGroup.id, + group = await database.groupMatchDao.getGroupOfMatch( + matchId: testMatchWithGroup.id, ); if (group == null) { @@ -176,5 +189,33 @@ void main() { } } }); + + test('Adding the same group to seperate matches works correctly', () async { + final match1 = Match(name: 'Match 1', group: testGroup1); + final match2 = Match(name: 'Match 2', group: testGroup1); + + await Future.wait([ + database.matchDao.addMatch(match: match1), + database.matchDao.addMatch(match: match2), + ]); + + final group1 = await database.groupMatchDao.getGroupOfMatch( + matchId: match1.id, + ); + final group2 = await database.groupMatchDao.getGroupOfMatch( + matchId: match2.id, + ); + + expect(group1, isNotNull); + expect(group2, isNotNull); + + final groups = [group1!, group2!]; + for (final group in groups) { + expect(group.members.length, testGroup1.members.length); + expect(group.id, testGroup1.id); + expect(group.name, testGroup1.name); + expect(group.createdAt, testGroup1.createdAt); + } + }); }); } diff --git a/test/db_tests/player_game_test.dart b/test/db_tests/player_game_test.dart deleted file mode 100644 index 4e2616e..0000000 --- a/test/db_tests/player_game_test.dart +++ /dev/null @@ -1,183 +0,0 @@ -import 'package:clock/clock.dart'; -import 'package:drift/drift.dart'; -import 'package:drift/native.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:game_tracker/data/db/database.dart'; -import 'package:game_tracker/data/dto/game.dart'; -import 'package:game_tracker/data/dto/group.dart'; -import 'package:game_tracker/data/dto/player.dart'; - -void main() { - late AppDatabase database; - late Player testPlayer1; - late Player testPlayer2; - late Player testPlayer3; - late Player testPlayer4; - late Player testPlayer5; - late Player testPlayer6; - late Group testgroup; - late Game testGameOnlyGroup; - late Game testGameOnlyPlayers; - final fixedDate = DateTime(2025, 19, 11, 00, 11, 23); - final fakeClock = Clock(() => fixedDate); - - setUp(() { - database = AppDatabase( - DatabaseConnection( - NativeDatabase.memory(), - // Recommended for widget tests to avoid test errors. - closeStreamsSynchronously: true, - ), - ); - - withClock(fakeClock, () { - testPlayer1 = Player(name: 'Alice'); - testPlayer2 = Player(name: 'Bob'); - testPlayer3 = Player(name: 'Charlie'); - testPlayer4 = Player(name: 'Diana'); - testPlayer5 = Player(name: 'Eve'); - testPlayer6 = Player(name: 'Frank'); - testgroup = Group( - name: 'Test Group', - members: [testPlayer1, testPlayer2, testPlayer3], - ); - testGameOnlyGroup = Game(name: 'Test Game with Group', group: testgroup); - testGameOnlyPlayers = Game( - name: 'Test Game with Players', - players: [testPlayer4, testPlayer5, testPlayer6], - ); - }); - }); - tearDown(() async { - await database.close(); - }); - - group('Player-Game Tests', () { - test('Game has player works correctly', () async { - await database.gameDao.addGame(game: testGameOnlyGroup); - await database.playerDao.addPlayer(player: testPlayer1); - - var gameHasPlayers = await database.playerGameDao.gameHasPlayers( - gameId: testGameOnlyGroup.id, - ); - - expect(gameHasPlayers, false); - - await database.playerGameDao.addPlayerToGame( - gameId: testGameOnlyGroup.id, - playerId: testPlayer1.id, - ); - - gameHasPlayers = await database.playerGameDao.gameHasPlayers( - gameId: testGameOnlyGroup.id, - ); - - expect(gameHasPlayers, true); - }); - - test('Adding a player to a game works correctly', () async { - await database.gameDao.addGame(game: testGameOnlyGroup); - await database.playerDao.addPlayer(player: testPlayer5); - await database.playerGameDao.addPlayerToGame( - gameId: testGameOnlyGroup.id, - playerId: testPlayer5.id, - ); - - var playerAdded = await database.playerGameDao.isPlayerInGame( - gameId: testGameOnlyGroup.id, - playerId: testPlayer5.id, - ); - - expect(playerAdded, true); - - playerAdded = await database.playerGameDao.isPlayerInGame( - gameId: testGameOnlyGroup.id, - playerId: '', - ); - - expect(playerAdded, false); - }); - - test('Removing player from game works correctly', () async { - await database.gameDao.addGame(game: testGameOnlyPlayers); - - final playerToRemove = testGameOnlyPlayers.players![0]; - - final removed = await database.playerGameDao.removePlayerFromGame( - playerId: playerToRemove.id, - gameId: testGameOnlyPlayers.id, - ); - expect(removed, true); - - final result = await database.gameDao.getGameById( - gameId: testGameOnlyPlayers.id, - ); - expect(result.players!.length, testGameOnlyPlayers.players!.length - 1); - - final playerExists = result.players!.any( - (p) => p.id == playerToRemove.id, - ); - expect(playerExists, false); - }); - - test('Retrieving players of a game works correctly', () async { - await database.gameDao.addGame(game: testGameOnlyPlayers); - final players = await database.playerGameDao.getPlayersOfGame( - gameId: testGameOnlyPlayers.id, - ); - - if (players == null) { - fail('Players should not be null'); - } - - for (int i = 0; i < players.length; i++) { - expect(players[i].id, testGameOnlyPlayers.players![i].id); - expect(players[i].name, testGameOnlyPlayers.players![i].name); - expect(players[i].createdAt, testGameOnlyPlayers.players![i].createdAt); - } - }); - - test('Updating the games players works coreclty', () async { - await database.gameDao.addGame(game: testGameOnlyPlayers); - - final newPlayers = [testPlayer1, testPlayer2, testPlayer4]; - await database.playerDao.addPlayersAsList(players: newPlayers); - - // First, remove all existing players - final existingPlayers = await database.playerGameDao.getPlayersOfGame( - gameId: testGameOnlyPlayers.id, - ); - - if (existingPlayers == null || existingPlayers.isEmpty) { - fail('Existing players should not be null or empty'); - } - - await database.playerGameDao.updatePlayersFromGame( - gameId: testGameOnlyPlayers.id, - newPlayer: newPlayers, - ); - - final updatedPlayers = await database.playerGameDao.getPlayersOfGame( - gameId: testGameOnlyPlayers.id, - ); - - if (updatedPlayers == null) { - fail('Updated players should not be null'); - } - - expect(updatedPlayers.length, newPlayers.length); - - /// Create a map of new players for easy lookup - final testPlayers = {for (var p in newPlayers) p.id: p}; - - /// Verify each updated player matches the new players - for (final player in updatedPlayers) { - final testPlayer = testPlayers[player.id]!; - - expect(player.id, testPlayer.id); - expect(player.name, testPlayer.name); - expect(player.createdAt, testPlayer.createdAt); - } - }); - }); -} diff --git a/test/db_tests/player_match_test.dart b/test/db_tests/player_match_test.dart new file mode 100644 index 0000000..8a4f569 --- /dev/null +++ b/test/db_tests/player_match_test.dart @@ -0,0 +1,237 @@ +import 'package:clock/clock.dart'; +import 'package:drift/drift.dart' hide isNotNull; +import 'package:drift/native.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:game_tracker/data/db/database.dart'; +import 'package:game_tracker/data/dto/group.dart'; +import 'package:game_tracker/data/dto/match.dart'; +import 'package:game_tracker/data/dto/player.dart'; + +void main() { + late AppDatabase database; + late Player testPlayer1; + late Player testPlayer2; + late Player testPlayer3; + late Player testPlayer4; + late Player testPlayer5; + late Player testPlayer6; + late Group testgroup; + late Match testMatchOnlyGroup; + late Match testMatchOnlyPlayers; + final fixedDate = DateTime(2025, 19, 11, 00, 11, 23); + final fakeClock = Clock(() => fixedDate); + + setUp(() async { + database = AppDatabase( + DatabaseConnection( + NativeDatabase.memory(), + // Recommended for widget tests to avoid test errors. + closeStreamsSynchronously: true, + ), + ); + + withClock(fakeClock, () { + testPlayer1 = Player(name: 'Alice'); + testPlayer2 = Player(name: 'Bob'); + testPlayer3 = Player(name: 'Charlie'); + testPlayer4 = Player(name: 'Diana'); + testPlayer5 = Player(name: 'Eve'); + testPlayer6 = Player(name: 'Frank'); + testgroup = Group( + name: 'Test Group', + members: [testPlayer1, testPlayer2, testPlayer3], + ); + testMatchOnlyGroup = Match( + name: 'Test Match with Group', + group: testgroup, + ); + testMatchOnlyPlayers = Match( + name: 'Test Match with Players', + players: [testPlayer4, testPlayer5, testPlayer6], + ); + }); + await database.playerDao.addPlayersAsList( + players: [ + testPlayer1, + testPlayer2, + testPlayer3, + testPlayer4, + testPlayer5, + testPlayer6, + ], + ); + await database.groupDao.addGroup(group: testgroup); + }); + tearDown(() async { + await database.close(); + }); + + group('Player-Match Tests', () { + test('Match has player works correctly', () async { + await database.matchDao.addMatch(match: testMatchOnlyGroup); + await database.playerDao.addPlayer(player: testPlayer1); + + var matchHasPlayers = await database.playerMatchDao.matchHasPlayers( + matchId: testMatchOnlyGroup.id, + ); + + expect(matchHasPlayers, false); + + await database.playerMatchDao.addPlayerToMatch( + matchId: testMatchOnlyGroup.id, + playerId: testPlayer1.id, + ); + + matchHasPlayers = await database.playerMatchDao.matchHasPlayers( + matchId: testMatchOnlyGroup.id, + ); + + expect(matchHasPlayers, true); + }); + + test('Adding a player to a match works correctly', () async { + await database.matchDao.addMatch(match: testMatchOnlyGroup); + await database.playerDao.addPlayer(player: testPlayer5); + await database.playerMatchDao.addPlayerToMatch( + matchId: testMatchOnlyGroup.id, + playerId: testPlayer5.id, + ); + + var playerAdded = await database.playerMatchDao.isPlayerInMatch( + matchId: testMatchOnlyGroup.id, + playerId: testPlayer5.id, + ); + + expect(playerAdded, true); + + playerAdded = await database.playerMatchDao.isPlayerInMatch( + matchId: testMatchOnlyGroup.id, + playerId: '', + ); + + expect(playerAdded, false); + }); + + test('Removing player from match works correctly', () async { + await database.matchDao.addMatch(match: testMatchOnlyPlayers); + + final playerToRemove = testMatchOnlyPlayers.players![0]; + + final removed = await database.playerMatchDao.removePlayerFromMatch( + playerId: playerToRemove.id, + matchId: testMatchOnlyPlayers.id, + ); + expect(removed, true); + + final result = await database.matchDao.getMatchById( + matchId: testMatchOnlyPlayers.id, + ); + expect(result.players!.length, testMatchOnlyPlayers.players!.length - 1); + + final playerExists = result.players!.any( + (p) => p.id == playerToRemove.id, + ); + expect(playerExists, false); + }); + + test('Retrieving players of a match works correctly', () async { + await database.matchDao.addMatch(match: testMatchOnlyPlayers); + final players = await database.playerMatchDao.getPlayersOfMatch( + matchId: testMatchOnlyPlayers.id, + ); + + if (players == null) { + fail('Players should not be null'); + } + + for (int i = 0; i < players.length; i++) { + expect(players[i].id, testMatchOnlyPlayers.players![i].id); + expect(players[i].name, testMatchOnlyPlayers.players![i].name); + expect( + players[i].createdAt, + testMatchOnlyPlayers.players![i].createdAt, + ); + } + }); + + test('Updating the match players works coreclty', () async { + await database.matchDao.addMatch(match: testMatchOnlyPlayers); + + final newPlayers = [testPlayer1, testPlayer2, testPlayer4]; + await database.playerDao.addPlayersAsList(players: newPlayers); + + // First, remove all existing players + final existingPlayers = await database.playerMatchDao.getPlayersOfMatch( + matchId: testMatchOnlyPlayers.id, + ); + + if (existingPlayers == null || existingPlayers.isEmpty) { + fail('Existing players should not be null or empty'); + } + + await database.playerMatchDao.updatePlayersFromMatch( + matchId: testMatchOnlyPlayers.id, + newPlayer: newPlayers, + ); + + final updatedPlayers = await database.playerMatchDao.getPlayersOfMatch( + matchId: testMatchOnlyPlayers.id, + ); + + if (updatedPlayers == null) { + fail('Updated players should not be null'); + } + + expect(updatedPlayers.length, newPlayers.length); + + /// Create a map of new players for easy lookup + final testPlayers = {for (var p in newPlayers) p.id: p}; + + /// Verify each updated player matches the new players + for (final player in updatedPlayers) { + final testPlayer = testPlayers[player.id]!; + + expect(player.id, testPlayer.id); + expect(player.name, testPlayer.name); + expect(player.createdAt, testPlayer.createdAt); + } + }); + + test( + 'Adding the same player to seperate matches works correctly', + () async { + final playersList = [testPlayer1, testPlayer2, testPlayer3]; + final match1 = Match(name: 'Match 1', players: playersList); + final match2 = Match(name: 'Match 2', players: playersList); + + await Future.wait([ + database.matchDao.addMatch(match: match1), + database.matchDao.addMatch(match: match2), + ]); + + final players1 = await database.playerMatchDao.getPlayersOfMatch( + matchId: match1.id, + ); + final players2 = await database.playerMatchDao.getPlayersOfMatch( + matchId: match2.id, + ); + + expect(players1, isNotNull); + expect(players2, isNotNull); + + expect( + players1!.map((p) => p.id).toList(), + equals(players2!.map((p) => p.id).toList()), + ); + expect( + players1.map((p) => p.name).toList(), + equals(players2.map((p) => p.name).toList()), + ); + expect( + players1.map((p) => p.createdAt).toList(), + equals(players2.map((p) => p.createdAt).toList()), + ); + }, + ); + }); +}