diff --git a/.github/workflows/authentication_repository.yaml b/.github/workflows/authentication_repository.yaml new file mode 100644 index 00000000..74c81d10 --- /dev/null +++ b/.github/workflows/authentication_repository.yaml @@ -0,0 +1,22 @@ +name: authentication_repository + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + push: + paths: + - "packages/authentication_repository/**" + - ".github/workflows/authentication_repository.yaml" + + pull_request: + paths: + - "packages/authentication_repository/**" + - ".github/workflows/authentication_repository.yaml" + +jobs: + build: + uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/flutter_package.yml@v1 + with: + working_directory: packages/authentication_repository diff --git a/lib/app/view/app.dart b/lib/app/view/app.dart index 97cfec9b..528954a6 100644 --- a/lib/app/view/app.dart +++ b/lib/app/view/app.dart @@ -7,6 +7,7 @@ // ignore_for_file: public_member_api_docs +import 'package:authentication_repository/authentication_repository.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; @@ -15,16 +16,20 @@ import 'package:pinball/game/game.dart'; import 'package:pinball/l10n/l10n.dart'; import 'package:pinball/select_character/select_character.dart'; import 'package:pinball_audio/pinball_audio.dart'; +import 'package:pinball_ui/pinball_ui.dart'; class App extends StatelessWidget { const App({ Key? key, + required AuthenticationRepository authenticationRepository, required LeaderboardRepository leaderboardRepository, required PinballAudio pinballAudio, - }) : _leaderboardRepository = leaderboardRepository, + }) : _authenticationRepository = authenticationRepository, + _leaderboardRepository = leaderboardRepository, _pinballAudio = pinballAudio, super(key: key); + final AuthenticationRepository _authenticationRepository; final LeaderboardRepository _leaderboardRepository; final PinballAudio _pinballAudio; @@ -32,19 +37,21 @@ class App extends StatelessWidget { Widget build(BuildContext context) { return MultiRepositoryProvider( providers: [ + RepositoryProvider.value(value: _authenticationRepository), RepositoryProvider.value(value: _leaderboardRepository), RepositoryProvider.value(value: _pinballAudio), ], child: BlocProvider( create: (context) => CharacterThemeCubit(), - child: const MaterialApp( + child: MaterialApp( title: 'I/O Pinball', - localizationsDelegates: [ + theme: PinballTheme.standard, + localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, ], supportedLocales: AppLocalizations.supportedLocales, - home: PinballGamePage(), + home: const PinballGamePage(), ), ), ); diff --git a/lib/bootstrap.dart b/lib/bootstrap.dart index c0fa9240..bbd87f0c 100644 --- a/lib/bootstrap.dart +++ b/lib/bootstrap.dart @@ -12,6 +12,7 @@ import 'dart:developer'; import 'package:bloc/bloc.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/widgets.dart'; class AppBlocObserver extends BlocObserver { @@ -28,9 +29,12 @@ class AppBlocObserver extends BlocObserver { } } -Future bootstrap( - Future Function(FirebaseFirestore firestore) builder, -) async { +typedef BootstrapBuilder = Future Function( + FirebaseFirestore firestore, + FirebaseAuth firebaseAuth, +); + +Future bootstrap(BootstrapBuilder builder) async { WidgetsFlutterBinding.ensureInitialized(); FlutterError.onError = (details) { log(details.exceptionAsString(), stackTrace: details.stack); @@ -39,7 +43,12 @@ Future bootstrap( await runZonedGuarded( () async { await BlocOverrides.runZoned( - () async => runApp(await builder(FirebaseFirestore.instance)), + () async => runApp( + await builder( + FirebaseFirestore.instance, + FirebaseAuth.instance, + ), + ), blocObserver: AppBlocObserver(), ); }, diff --git a/lib/footer/footer.dart b/lib/footer/footer.dart new file mode 100644 index 00000000..df3dbd2f --- /dev/null +++ b/lib/footer/footer.dart @@ -0,0 +1,76 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:pinball/l10n/l10n.dart'; +import 'package:pinball_ui/pinball_ui.dart'; + +/// {@template footer} +/// Footer widget with links to the main tech stack. +/// {@endtemplate} +class Footer extends StatelessWidget { + /// {@macro footer} + const Footer({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.fromLTRB(50, 0, 50, 32), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: const [ + _MadeWithFlutterAndFirebase(), + _GoogleIO(), + ], + ), + ); + } +} + +class _GoogleIO extends StatelessWidget { + const _GoogleIO({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + final theme = Theme.of(context); + return Text( + l10n.footerGoogleIOText, + style: theme.textTheme.bodyText1!.copyWith(color: PinballColors.white), + ); + } +} + +class _MadeWithFlutterAndFirebase extends StatelessWidget { + const _MadeWithFlutterAndFirebase({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + final theme = Theme.of(context); + return RichText( + textAlign: TextAlign.center, + text: TextSpan( + text: l10n.footerMadeWithText, + style: theme.textTheme.bodyText1!.copyWith(color: PinballColors.white), + children: [ + TextSpan( + text: l10n.footerFlutterLinkText, + recognizer: TapGestureRecognizer() + ..onTap = () => openLink('https://flutter.dev'), + style: const TextStyle( + decoration: TextDecoration.underline, + ), + ), + const TextSpan(text: ' & '), + TextSpan( + text: l10n.footerFirebaseLinkText, + recognizer: TapGestureRecognizer() + ..onTap = () => openLink('https://firebase.google.com'), + style: const TextStyle( + decoration: TextDecoration.underline, + ), + ), + ], + ), + ); + } +} diff --git a/lib/game/components/android_acres.dart b/lib/game/components/android_acres.dart index 8b5fe718..2af7335f 100644 --- a/lib/game/components/android_acres.dart +++ b/lib/game/components/android_acres.dart @@ -6,8 +6,8 @@ import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_flame/pinball_flame.dart'; /// {@template android_acres} -/// Area positioned on the left side of the board containing the [Spaceship], -/// [SpaceshipRamp], [SpaceshipRail], and [AndroidBumper]s. +/// Area positioned on the left side of the board containing the +/// [AndroidSpaceship], [SpaceshipRamp], [SpaceshipRail], and [AndroidBumper]s. /// {@endtemplate} class AndroidAcres extends Blueprint { /// {@macro android_acres} @@ -23,7 +23,7 @@ class AndroidAcres extends Blueprint { children: [ ScoringBehavior(points: 20000), ], - )..initialPosition = Vector2(-32.6, -9.2), + )..initialPosition = Vector2(-32.8, -9.2), AndroidBumper.cow( children: [ ScoringBehavior(points: 20), @@ -32,7 +32,7 @@ class AndroidAcres extends Blueprint { ], blueprints: [ SpaceshipRamp(), - Spaceship(position: Vector2(-26.5, -28.5)), + AndroidSpaceship(position: Vector2(-26.5, -28.5)), SpaceshipRail(), ], ); diff --git a/lib/game/components/bottom_group.dart b/lib/game/components/bottom_group.dart index 5d0cf97e..921a8e58 100644 --- a/lib/game/components/bottom_group.dart +++ b/lib/game/components/bottom_group.dart @@ -16,6 +16,7 @@ class BottomGroup extends Component { _BottomGroupSide(side: BoardSide.right), _BottomGroupSide(side: BoardSide.left), ], + priority: RenderPriority.bottomGroup, ); } @@ -28,8 +29,7 @@ class _BottomGroupSide extends Component { /// {@macro bottom_group_side} _BottomGroupSide({ required BoardSide side, - }) : _side = side, - super(priority: RenderPriority.bottomGroup); + }) : _side = side; final BoardSide _side; diff --git a/lib/game/game_assets.dart b/lib/game/game_assets.dart index 72a96164..744593fb 100644 --- a/lib/game/game_assets.dart +++ b/lib/game/game_assets.dart @@ -13,6 +13,7 @@ extension PinballGameAssetsX on PinballGame { const dinoTheme = DinoTheme(); return [ + images.load(components.Assets.images.boardBackground.keyName), images.load(components.Assets.images.ball.ball.keyName), images.load(components.Assets.images.ball.flameEffect.keyName), images.load(components.Assets.images.signpost.inactive.keyName), @@ -50,41 +51,42 @@ extension PinballGameAssetsX on PinballGame { images.load(components.Assets.images.boundary.bottom.keyName), images.load(components.Assets.images.boundary.outer.keyName), images.load(components.Assets.images.boundary.outerBottom.keyName), - images.load(components.Assets.images.spaceship.saucer.keyName), - images.load(components.Assets.images.spaceship.bridge.keyName), - images.load(components.Assets.images.spaceship.ramp.boardOpening.keyName), + images.load(components.Assets.images.android.spaceship.saucer.keyName), + images + .load(components.Assets.images.android.spaceship.animatronic.keyName), + images.load(components.Assets.images.android.spaceship.lightBeam.keyName), + images.load(components.Assets.images.android.ramp.boardOpening.keyName), images.load( - components.Assets.images.spaceship.ramp.railingForeground.keyName, + components.Assets.images.android.ramp.railingForeground.keyName, ), images.load( - components.Assets.images.spaceship.ramp.railingBackground.keyName, + components.Assets.images.android.ramp.railingBackground.keyName, ), - images.load(components.Assets.images.spaceship.ramp.main.keyName), - images - .load(components.Assets.images.spaceship.ramp.arrow.inactive.keyName), + images.load(components.Assets.images.android.ramp.main.keyName), + images.load(components.Assets.images.android.ramp.arrow.inactive.keyName), images.load( - components.Assets.images.spaceship.ramp.arrow.active1.keyName, + components.Assets.images.android.ramp.arrow.active1.keyName, ), images.load( - components.Assets.images.spaceship.ramp.arrow.active2.keyName, + components.Assets.images.android.ramp.arrow.active2.keyName, ), images.load( - components.Assets.images.spaceship.ramp.arrow.active3.keyName, + components.Assets.images.android.ramp.arrow.active3.keyName, ), images.load( - components.Assets.images.spaceship.ramp.arrow.active4.keyName, + components.Assets.images.android.ramp.arrow.active4.keyName, ), images.load( - components.Assets.images.spaceship.ramp.arrow.active5.keyName, + components.Assets.images.android.ramp.arrow.active5.keyName, ), - images.load(components.Assets.images.spaceship.rail.main.keyName), - images.load(components.Assets.images.spaceship.rail.exit.keyName), - images.load(components.Assets.images.androidBumper.a.lit.keyName), - images.load(components.Assets.images.androidBumper.a.dimmed.keyName), - images.load(components.Assets.images.androidBumper.b.lit.keyName), - images.load(components.Assets.images.androidBumper.b.dimmed.keyName), - images.load(components.Assets.images.androidBumper.cow.lit.keyName), - images.load(components.Assets.images.androidBumper.cow.dimmed.keyName), + images.load(components.Assets.images.android.rail.main.keyName), + images.load(components.Assets.images.android.rail.exit.keyName), + images.load(components.Assets.images.android.bumper.a.lit.keyName), + images.load(components.Assets.images.android.bumper.a.dimmed.keyName), + images.load(components.Assets.images.android.bumper.b.lit.keyName), + images.load(components.Assets.images.android.bumper.b.dimmed.keyName), + images.load(components.Assets.images.android.bumper.cow.lit.keyName), + images.load(components.Assets.images.android.bumper.cow.dimmed.keyName), images.load(components.Assets.images.sparky.computer.top.keyName), images.load(components.Assets.images.sparky.computer.base.keyName), images.load(components.Assets.images.sparky.computer.glow.keyName), diff --git a/lib/game/pinball_game.dart b/lib/game/pinball_game.dart index 8bb0bc5c..9030bc6c 100644 --- a/lib/game/pinball_game.dart +++ b/lib/game/pinball_game.dart @@ -9,11 +9,10 @@ import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:pinball/game/game.dart'; -import 'package:pinball/gen/assets.gen.dart'; import 'package:pinball_audio/pinball_audio.dart'; -import 'package:pinball_components/pinball_components.dart' hide Assets; +import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_flame/pinball_flame.dart'; -import 'package:pinball_theme/pinball_theme.dart' hide Assets; +import 'package:pinball_theme/pinball_theme.dart'; class PinballGame extends Forge2DGame with @@ -46,10 +45,10 @@ class PinballGame extends Forge2DGame unawaited(add(gameFlowController = GameFlowController(this))); unawaited(add(CameraController(this))); unawaited(add(Backboard.waiting(position: Vector2(0, -88)))); + await add(BoardBackgroundSpriteComponent()); await add(Drain()); await add(BottomGroup()); unawaited(addFromBlueprint(Boundaries())); - unawaited(addFromBlueprint(LaunchRamp())); final launcher = Launcher(); unawaited(addFromBlueprint(launcher)); @@ -68,7 +67,7 @@ class PinballGame extends Forge2DGame ), ); - controller.attachTo(launcher.components.whereType().first); + controller.attachTo(launcher.components.whereType().single); await super.onLoad(); } @@ -186,26 +185,25 @@ class DebugPinballGame extends PinballGame with FPSCounter { @override Future onLoad() async { await super.onLoad(); - await _loadBackground(); await add(_DebugInformation()); } - // TODO(alestiago): Move to PinballGame once we have the real background - // component. - Future _loadBackground() async { - final sprite = await loadSprite( - Assets.images.components.background.path, - ); - final spriteComponent = SpriteComponent( - sprite: sprite, - size: Vector2(120, 160), - anchor: Anchor.center, - ) - ..position = Vector2(0, -7.8) - ..priority = RenderPriority.background; - - await add(spriteComponent); - } + // TODO(allisonryan0002): Remove after google letters have been correctly + // placed. + // Future _loadBackground() async { + // final sprite = await loadSprite( + // Assets.images.components.background.path, + // ); + // final spriteComponent = SpriteComponent( + // sprite: sprite, + // size: Vector2(120, 160), + // anchor: Anchor.center, + // ) + // ..position = Vector2(0, -7.8) + // ..priority = RenderPriority.boardBackground; + + // await add(spriteComponent); + // } @override void onTapUp(TapUpInfo info) { diff --git a/lib/game/view/widgets/game_hud.dart b/lib/game/view/widgets/game_hud.dart index e3c44877..605bceb4 100644 --- a/lib/game/view/widgets/game_hud.dart +++ b/lib/game/view/widgets/game_hud.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:pinball/game/game.dart'; import 'package:pinball/gen/gen.dart'; -import 'package:pinball/theme/app_colors.dart'; +import 'package:pinball_ui/pinball_ui.dart'; /// {@template game_hud} /// Overlay on the [PinballGame]. @@ -72,7 +72,7 @@ class _ScoreViewDecoration extends StatelessWidget { decoration: BoxDecoration( borderRadius: radius, border: Border.all( - color: AppColors.white, + color: PinballColors.white, width: borderWidth, ), image: DecorationImage( diff --git a/lib/game/view/widgets/round_count_display.dart b/lib/game/view/widgets/round_count_display.dart index b8f67c26..63e1fa43 100644 --- a/lib/game/view/widgets/round_count_display.dart +++ b/lib/game/view/widgets/round_count_display.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:pinball/game/game.dart'; import 'package:pinball/l10n/l10n.dart'; -import 'package:pinball/theme/theme.dart'; +import 'package:pinball_ui/pinball_ui.dart'; /// {@template round_count_display} /// Colored square indicating if a round is available. @@ -20,9 +20,7 @@ class RoundCountDisplay extends StatelessWidget { children: [ Text( l10n.rounds, - style: AppTextStyle.subtitle1.copyWith( - color: AppColors.yellow, - ), + style: Theme.of(context).textTheme.subtitle1, ), const SizedBox(width: 8), Row( @@ -53,9 +51,9 @@ class RoundIndicator extends StatelessWidget { @override Widget build(BuildContext context) { - final color = isActive ? AppColors.yellow : AppColors.yellow.withAlpha(128); + final color = + isActive ? PinballColors.yellow : PinballColors.yellow.withAlpha(128); const size = 8.0; - return Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Container( diff --git a/lib/game/view/widgets/score_view.dart b/lib/game/view/widgets/score_view.dart index 40b33c35..1fe57eb1 100644 --- a/lib/game/view/widgets/score_view.dart +++ b/lib/game/view/widgets/score_view.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:pinball/game/game.dart'; import 'package:pinball/l10n/l10n.dart'; -import 'package:pinball/theme/theme.dart'; import 'package:pinball_components/pinball_components.dart'; /// {@template score_view} @@ -38,9 +37,7 @@ class _GameOver extends StatelessWidget { return Text( l10n.gameOver, - style: AppTextStyle.headline1.copyWith( - color: AppColors.white, - ), + style: Theme.of(context).textTheme.headline1, ); } } @@ -58,9 +55,7 @@ class _ScoreDisplay extends StatelessWidget { children: [ Text( l10n.score.toLowerCase(), - style: AppTextStyle.subtitle1.copyWith( - color: AppColors.yellow, - ), + style: Theme.of(context).textTheme.subtitle1, ), const _ScoreText(), const RoundCountDisplay(), @@ -78,9 +73,7 @@ class _ScoreText extends StatelessWidget { return Text( score.formatScore(), - style: AppTextStyle.headline1.copyWith( - color: AppColors.white, - ), + style: Theme.of(context).textTheme.headline1, ); } } diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 19b12296..7691e2dd 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -107,5 +107,21 @@ "rounds": "Ball Ct:", "@rounds": { "description": "Text displayed on the scoreboard widget to indicate rounds left" + }, + "footerMadeWithText": "Made with ", + "@footerMadeWithText": { + "description": "Text shown on the footer which mentions technologies used to build the app." + }, + "footerFlutterLinkText": "Flutter", + "@footerFlutterLinkText": { + "description": "Text on the link shown on the footer which navigates to the Flutter page" + }, + "footerFirebaseLinkText": "Firebase", + "@footerFirebaseLinkText": { + "description": "Text on the link shown on the footer which navigates to the Firebase page" + }, + "footerGoogleIOText": "Google I/O", + "@footerGoogleIOText": { + "description": "Text shown on the footer which mentions Google I/O" } } \ No newline at end of file diff --git a/lib/l10n/arb/app_es.arb b/lib/l10n/arb/app_es.arb deleted file mode 100644 index 597a39d8..00000000 --- a/lib/l10n/arb/app_es.arb +++ /dev/null @@ -1,15 +0,0 @@ -{ - "@@locale": "es", - "play": "Jugar", - "@play": { - "description": "Text displayed on the landing page play button" - }, - "start": "Comienzo", - "@start": { - "description": "Text displayed on the character selection page start button" - }, - "characterSelectionTitle": "¡Elige a tu personaje!", - "@characterSelectionTitle": { - "description": "Title text displayed on the character selection page" - } -} \ No newline at end of file diff --git a/lib/main_development.dart b/lib/main_development.dart index 8944073d..529c66e2 100644 --- a/lib/main_development.dart +++ b/lib/main_development.dart @@ -5,16 +5,27 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +import 'dart:async'; + +import 'package:authentication_repository/authentication_repository.dart'; +import 'package:firebase_core/firebase_core.dart'; import 'package:leaderboard_repository/leaderboard_repository.dart'; import 'package:pinball/app/app.dart'; import 'package:pinball/bootstrap.dart'; import 'package:pinball_audio/pinball_audio.dart'; void main() { - bootstrap((firestore) async { + bootstrap((firestore, firebaseAuth) async { final leaderboardRepository = LeaderboardRepository(firestore); + final authenticationRepository = AuthenticationRepository(firebaseAuth); final pinballAudio = PinballAudio(); + unawaited( + Firebase.initializeApp().then( + (_) => authenticationRepository.authenticateAnonymously(), + ), + ); return App( + authenticationRepository: authenticationRepository, leaderboardRepository: leaderboardRepository, pinballAudio: pinballAudio, ); diff --git a/lib/main_production.dart b/lib/main_production.dart index 8944073d..529c66e2 100644 --- a/lib/main_production.dart +++ b/lib/main_production.dart @@ -5,16 +5,27 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +import 'dart:async'; + +import 'package:authentication_repository/authentication_repository.dart'; +import 'package:firebase_core/firebase_core.dart'; import 'package:leaderboard_repository/leaderboard_repository.dart'; import 'package:pinball/app/app.dart'; import 'package:pinball/bootstrap.dart'; import 'package:pinball_audio/pinball_audio.dart'; void main() { - bootstrap((firestore) async { + bootstrap((firestore, firebaseAuth) async { final leaderboardRepository = LeaderboardRepository(firestore); + final authenticationRepository = AuthenticationRepository(firebaseAuth); final pinballAudio = PinballAudio(); + unawaited( + Firebase.initializeApp().then( + (_) => authenticationRepository.authenticateAnonymously(), + ), + ); return App( + authenticationRepository: authenticationRepository, leaderboardRepository: leaderboardRepository, pinballAudio: pinballAudio, ); diff --git a/lib/main_staging.dart b/lib/main_staging.dart index 8944073d..529c66e2 100644 --- a/lib/main_staging.dart +++ b/lib/main_staging.dart @@ -5,16 +5,27 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +import 'dart:async'; + +import 'package:authentication_repository/authentication_repository.dart'; +import 'package:firebase_core/firebase_core.dart'; import 'package:leaderboard_repository/leaderboard_repository.dart'; import 'package:pinball/app/app.dart'; import 'package:pinball/bootstrap.dart'; import 'package:pinball_audio/pinball_audio.dart'; void main() { - bootstrap((firestore) async { + bootstrap((firestore, firebaseAuth) async { final leaderboardRepository = LeaderboardRepository(firestore); + final authenticationRepository = AuthenticationRepository(firebaseAuth); final pinballAudio = PinballAudio(); + unawaited( + Firebase.initializeApp().then( + (_) => authenticationRepository.authenticateAnonymously(), + ), + ); return App( + authenticationRepository: authenticationRepository, leaderboardRepository: leaderboardRepository, pinballAudio: pinballAudio, ); diff --git a/lib/start_game/widgets/how_to_play_dialog.dart b/lib/start_game/widgets/how_to_play_dialog.dart index 1665d35d..500a4288 100644 --- a/lib/start_game/widgets/how_to_play_dialog.dart +++ b/lib/start_game/widgets/how_to_play_dialog.dart @@ -5,7 +5,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:pinball/gen/gen.dart'; import 'package:pinball/l10n/l10n.dart'; -import 'package:pinball/theme/theme.dart'; import 'package:pinball_ui/pinball_ui.dart'; import 'package:platform_helper/platform_helper.dart'; @@ -122,7 +121,7 @@ class _MobileLaunchControls extends StatelessWidget { @override Widget build(BuildContext context) { final l10n = context.l10n; - const textStyle = AppTextStyle.subtitle3; + final textStyle = Theme.of(context).textTheme.headline3; return Column( children: [ Text( @@ -138,9 +137,7 @@ class _MobileLaunchControls extends StatelessWidget { ), TextSpan( text: l10n.launch, - style: textStyle.copyWith( - color: AppColors.blue, - ), + style: textStyle?.copyWith(color: PinballColors.blue), ), ], ), @@ -156,7 +153,7 @@ class _MobileFlipperControls extends StatelessWidget { @override Widget build(BuildContext context) { final l10n = context.l10n; - const textStyle = AppTextStyle.subtitle3; + final textStyle = Theme.of(context).textTheme.headline3; return Column( children: [ Text( @@ -172,9 +169,7 @@ class _MobileFlipperControls extends StatelessWidget { ), TextSpan( text: l10n.flip, - style: textStyle.copyWith( - color: AppColors.orange, - ), + style: textStyle?.copyWith(color: PinballColors.orange), ), ], ), @@ -207,21 +202,22 @@ class _HowToPlayHeader extends StatelessWidget { @override Widget build(BuildContext context) { final l10n = context.l10n; - const headerTextStyle = AppTextStyle.title; - + final textStyle = Theme.of(context).textTheme.headline3?.copyWith( + color: PinballColors.darkBlue, + ); return FittedBox( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( l10n.howToPlay, - style: headerTextStyle.copyWith( + style: textStyle?.copyWith( fontWeight: FontWeight.bold, ), ), Text( l10n.tipsForFlips, - style: headerTextStyle, + style: textStyle, ), ], ), @@ -241,7 +237,7 @@ class _DesktopLaunchControls extends StatelessWidget { children: [ Text( l10n.launchControls, - style: AppTextStyle.headline4, + style: Theme.of(context).textTheme.headline4, ), const SizedBox(height: 10), Wrap( @@ -270,7 +266,7 @@ class _DesktopFlipperControls extends StatelessWidget { children: [ Text( l10n.flipperControls, - style: AppTextStyle.subtitle2, + style: Theme.of(context).textTheme.subtitle2, ), const SizedBox(height: 10), Column( @@ -311,8 +307,9 @@ class KeyButton extends StatelessWidget { @override Widget build(BuildContext context) { + final textTheme = Theme.of(context).textTheme; final textStyle = - _control.isArrow ? AppTextStyle.headline1 : AppTextStyle.headline3; + _control.isArrow ? textTheme.headline1 : textTheme.headline3; const height = 60.0; final width = _control.isSpace ? height * 2.83 : height; return DecoratedBox( @@ -334,7 +331,7 @@ class KeyButton extends StatelessWidget { quarterTurns: _control.isDown ? 1 : 0, child: Text( _control.getCharacter(context), - style: textStyle.copyWith(color: AppColors.white), + style: textStyle?.copyWith(color: PinballColors.white), ), ), ), diff --git a/lib/theme/theme.dart b/lib/theme/theme.dart deleted file mode 100644 index c9e2f9e1..00000000 --- a/lib/theme/theme.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'app_colors.dart'; -export 'app_text_style.dart'; diff --git a/packages/authentication_repository/.gitignore b/packages/authentication_repository/.gitignore new file mode 100644 index 00000000..d6130351 --- /dev/null +++ b/packages/authentication_repository/.gitignore @@ -0,0 +1,39 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# VSCode related +.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json diff --git a/packages/authentication_repository/README.md b/packages/authentication_repository/README.md new file mode 100644 index 00000000..8f56b868 --- /dev/null +++ b/packages/authentication_repository/README.md @@ -0,0 +1,11 @@ +# authentication_repository + +[![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] +[![License: MIT][license_badge]][license_link] + +Repository to manage user authentication. + +[license_badge]: https://img.shields.io/badge/license-MIT-blue.svg +[license_link]: https://opensource.org/licenses/MIT +[very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg +[very_good_analysis_link]: https://pub.dev/packages/very_good_analysis \ No newline at end of file diff --git a/packages/authentication_repository/analysis_options.yaml b/packages/authentication_repository/analysis_options.yaml new file mode 100644 index 00000000..3742fc3d --- /dev/null +++ b/packages/authentication_repository/analysis_options.yaml @@ -0,0 +1 @@ +include: package:very_good_analysis/analysis_options.2.4.0.yaml \ No newline at end of file diff --git a/packages/authentication_repository/lib/authentication_repository.dart b/packages/authentication_repository/lib/authentication_repository.dart new file mode 100644 index 00000000..77b1b6b9 --- /dev/null +++ b/packages/authentication_repository/lib/authentication_repository.dart @@ -0,0 +1,3 @@ +library authentication_repository; + +export 'src/authentication_repository.dart'; diff --git a/packages/authentication_repository/lib/src/authentication_repository.dart b/packages/authentication_repository/lib/src/authentication_repository.dart new file mode 100644 index 00000000..9f252518 --- /dev/null +++ b/packages/authentication_repository/lib/src/authentication_repository.dart @@ -0,0 +1,36 @@ +import 'package:firebase_auth/firebase_auth.dart'; + +/// {@template authentication_exception} +/// Exception for authentication repository failures. +/// {@endtemplate} +class AuthenticationException implements Exception { + /// {@macro authentication_exception} + const AuthenticationException(this.error, this.stackTrace); + + /// The error that was caught. + final Object error; + + /// The Stacktrace associated with the [error]. + final StackTrace stackTrace; +} + +/// {@template authentication_repository} +/// Repository to manage user authentication. +/// {@endtemplate} +class AuthenticationRepository { + /// {@macro authentication_repository} + AuthenticationRepository(this._firebaseAuth); + + final FirebaseAuth _firebaseAuth; + + /// Sign in the existing user anonymously using [FirebaseAuth]. If the + /// authentication process can't be completed, it will throw an + /// [AuthenticationException]. + Future authenticateAnonymously() async { + try { + await _firebaseAuth.signInAnonymously(); + } on Exception catch (error, stackTrace) { + throw AuthenticationException(error, stackTrace); + } + } +} diff --git a/packages/authentication_repository/pubspec.yaml b/packages/authentication_repository/pubspec.yaml new file mode 100644 index 00000000..bac20507 --- /dev/null +++ b/packages/authentication_repository/pubspec.yaml @@ -0,0 +1,18 @@ +name: authentication_repository +description: Repository to manage user authentication. +version: 1.0.0+1 +publish_to: none + +environment: + sdk: ">=2.16.0 <3.0.0" + +dependencies: + firebase_auth: ^3.3.16 + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + mocktail: ^0.2.0 + very_good_analysis: ^2.4.0 \ No newline at end of file diff --git a/packages/authentication_repository/test/src/authentication_repository_test.dart b/packages/authentication_repository/test/src/authentication_repository_test.dart new file mode 100644 index 00000000..a179bb68 --- /dev/null +++ b/packages/authentication_repository/test/src/authentication_repository_test.dart @@ -0,0 +1,40 @@ +import 'package:authentication_repository/authentication_repository.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class MockFirebaseAuth extends Mock implements FirebaseAuth {} + +class MockUserCredential extends Mock implements UserCredential {} + +void main() { + late FirebaseAuth firebaseAuth; + late UserCredential userCredential; + late AuthenticationRepository authenticationRepository; + + group('AuthenticationRepository', () { + setUp(() { + firebaseAuth = MockFirebaseAuth(); + userCredential = MockUserCredential(); + authenticationRepository = AuthenticationRepository(firebaseAuth); + }); + + group('authenticateAnonymously', () { + test('completes if no exception is thrown', () async { + when(() => firebaseAuth.signInAnonymously()) + .thenAnswer((_) async => userCredential); + await authenticationRepository.authenticateAnonymously(); + verify(() => firebaseAuth.signInAnonymously()).called(1); + }); + + test('throws AuthenticationException when firebase auth fails', () async { + when(() => firebaseAuth.signInAnonymously()) + .thenThrow(Exception('oops')); + expect( + () => authenticationRepository.authenticateAnonymously(), + throwsA(isA()), + ); + }); + }); + }); +} diff --git a/packages/pinball_components/assets/images/android_bumper/a/dimmed.png b/packages/pinball_components/assets/images/android/bumper/a/dimmed.png similarity index 100% rename from packages/pinball_components/assets/images/android_bumper/a/dimmed.png rename to packages/pinball_components/assets/images/android/bumper/a/dimmed.png diff --git a/packages/pinball_components/assets/images/android_bumper/a/lit.png b/packages/pinball_components/assets/images/android/bumper/a/lit.png similarity index 100% rename from packages/pinball_components/assets/images/android_bumper/a/lit.png rename to packages/pinball_components/assets/images/android/bumper/a/lit.png diff --git a/packages/pinball_components/assets/images/android_bumper/b/dimmed.png b/packages/pinball_components/assets/images/android/bumper/b/dimmed.png similarity index 100% rename from packages/pinball_components/assets/images/android_bumper/b/dimmed.png rename to packages/pinball_components/assets/images/android/bumper/b/dimmed.png diff --git a/packages/pinball_components/assets/images/android_bumper/b/lit.png b/packages/pinball_components/assets/images/android/bumper/b/lit.png similarity index 100% rename from packages/pinball_components/assets/images/android_bumper/b/lit.png rename to packages/pinball_components/assets/images/android/bumper/b/lit.png diff --git a/packages/pinball_components/assets/images/android_bumper/cow/dimmed.png b/packages/pinball_components/assets/images/android/bumper/cow/dimmed.png similarity index 100% rename from packages/pinball_components/assets/images/android_bumper/cow/dimmed.png rename to packages/pinball_components/assets/images/android/bumper/cow/dimmed.png diff --git a/packages/pinball_components/assets/images/android_bumper/cow/lit.png b/packages/pinball_components/assets/images/android/bumper/cow/lit.png similarity index 100% rename from packages/pinball_components/assets/images/android_bumper/cow/lit.png rename to packages/pinball_components/assets/images/android/bumper/cow/lit.png diff --git a/packages/pinball_components/assets/images/spaceship/rail/exit.png b/packages/pinball_components/assets/images/android/rail/exit.png similarity index 100% rename from packages/pinball_components/assets/images/spaceship/rail/exit.png rename to packages/pinball_components/assets/images/android/rail/exit.png diff --git a/packages/pinball_components/assets/images/spaceship/rail/main.png b/packages/pinball_components/assets/images/android/rail/main.png similarity index 100% rename from packages/pinball_components/assets/images/spaceship/rail/main.png rename to packages/pinball_components/assets/images/android/rail/main.png diff --git a/packages/pinball_components/assets/images/spaceship/ramp/arrow/active1.png b/packages/pinball_components/assets/images/android/ramp/arrow/active1.png similarity index 100% rename from packages/pinball_components/assets/images/spaceship/ramp/arrow/active1.png rename to packages/pinball_components/assets/images/android/ramp/arrow/active1.png diff --git a/packages/pinball_components/assets/images/spaceship/ramp/arrow/active2.png b/packages/pinball_components/assets/images/android/ramp/arrow/active2.png similarity index 100% rename from packages/pinball_components/assets/images/spaceship/ramp/arrow/active2.png rename to packages/pinball_components/assets/images/android/ramp/arrow/active2.png diff --git a/packages/pinball_components/assets/images/spaceship/ramp/arrow/active3.png b/packages/pinball_components/assets/images/android/ramp/arrow/active3.png similarity index 100% rename from packages/pinball_components/assets/images/spaceship/ramp/arrow/active3.png rename to packages/pinball_components/assets/images/android/ramp/arrow/active3.png diff --git a/packages/pinball_components/assets/images/spaceship/ramp/arrow/active4.png b/packages/pinball_components/assets/images/android/ramp/arrow/active4.png similarity index 100% rename from packages/pinball_components/assets/images/spaceship/ramp/arrow/active4.png rename to packages/pinball_components/assets/images/android/ramp/arrow/active4.png diff --git a/packages/pinball_components/assets/images/spaceship/ramp/arrow/active5.png b/packages/pinball_components/assets/images/android/ramp/arrow/active5.png similarity index 100% rename from packages/pinball_components/assets/images/spaceship/ramp/arrow/active5.png rename to packages/pinball_components/assets/images/android/ramp/arrow/active5.png diff --git a/packages/pinball_components/assets/images/spaceship/ramp/arrow/inactive.png b/packages/pinball_components/assets/images/android/ramp/arrow/inactive.png similarity index 100% rename from packages/pinball_components/assets/images/spaceship/ramp/arrow/inactive.png rename to packages/pinball_components/assets/images/android/ramp/arrow/inactive.png diff --git a/packages/pinball_components/assets/images/spaceship/ramp/board-opening.png b/packages/pinball_components/assets/images/android/ramp/board-opening.png similarity index 100% rename from packages/pinball_components/assets/images/spaceship/ramp/board-opening.png rename to packages/pinball_components/assets/images/android/ramp/board-opening.png diff --git a/packages/pinball_components/assets/images/spaceship/ramp/main.png b/packages/pinball_components/assets/images/android/ramp/main.png similarity index 100% rename from packages/pinball_components/assets/images/spaceship/ramp/main.png rename to packages/pinball_components/assets/images/android/ramp/main.png diff --git a/packages/pinball_components/assets/images/spaceship/ramp/railing-background.png b/packages/pinball_components/assets/images/android/ramp/railing-background.png similarity index 100% rename from packages/pinball_components/assets/images/spaceship/ramp/railing-background.png rename to packages/pinball_components/assets/images/android/ramp/railing-background.png diff --git a/packages/pinball_components/assets/images/spaceship/ramp/railing-foreground.png b/packages/pinball_components/assets/images/android/ramp/railing-foreground.png similarity index 100% rename from packages/pinball_components/assets/images/spaceship/ramp/railing-foreground.png rename to packages/pinball_components/assets/images/android/ramp/railing-foreground.png diff --git a/packages/pinball_components/assets/images/android/spaceship/animatronic.png b/packages/pinball_components/assets/images/android/spaceship/animatronic.png new file mode 100644 index 00000000..d4b165f3 Binary files /dev/null and b/packages/pinball_components/assets/images/android/spaceship/animatronic.png differ diff --git a/packages/pinball_components/assets/images/android/spaceship/light-beam.png b/packages/pinball_components/assets/images/android/spaceship/light-beam.png new file mode 100644 index 00000000..eb33725d Binary files /dev/null and b/packages/pinball_components/assets/images/android/spaceship/light-beam.png differ diff --git a/packages/pinball_components/assets/images/android/spaceship/saucer.png b/packages/pinball_components/assets/images/android/spaceship/saucer.png new file mode 100644 index 00000000..6c77525a Binary files /dev/null and b/packages/pinball_components/assets/images/android/spaceship/saucer.png differ diff --git a/packages/pinball_components/assets/images/board-background.png b/packages/pinball_components/assets/images/board-background.png new file mode 100644 index 00000000..979a0873 Binary files /dev/null and b/packages/pinball_components/assets/images/board-background.png differ diff --git a/packages/pinball_components/assets/images/spaceship/bridge.png b/packages/pinball_components/assets/images/spaceship/bridge.png deleted file mode 100644 index 6ebb143e..00000000 Binary files a/packages/pinball_components/assets/images/spaceship/bridge.png and /dev/null differ diff --git a/packages/pinball_components/assets/images/spaceship/saucer.png b/packages/pinball_components/assets/images/spaceship/saucer.png deleted file mode 100644 index 4cd65522..00000000 Binary files a/packages/pinball_components/assets/images/spaceship/saucer.png and /dev/null differ diff --git a/packages/pinball_components/lib/gen/assets.gen.dart b/packages/pinball_components/lib/gen/assets.gen.dart index 26dbb254..94022534 100644 --- a/packages/pinball_components/lib/gen/assets.gen.dart +++ b/packages/pinball_components/lib/gen/assets.gen.dart @@ -10,11 +10,14 @@ import 'package:flutter/widgets.dart'; class $AssetsImagesGen { const $AssetsImagesGen(); - $AssetsImagesAndroidBumperGen get androidBumper => - const $AssetsImagesAndroidBumperGen(); + $AssetsImagesAndroidGen get android => const $AssetsImagesAndroidGen(); $AssetsImagesBackboardGen get backboard => const $AssetsImagesBackboardGen(); $AssetsImagesBallGen get ball => const $AssetsImagesBallGen(); $AssetsImagesBaseboardGen get baseboard => const $AssetsImagesBaseboardGen(); + + /// File path: assets/images/board-background.png + AssetGenImage get boardBackground => + const AssetGenImage('assets/images/board-background.png'); $AssetsImagesBoundaryGen get boundary => const $AssetsImagesBoundaryGen(); $AssetsImagesDashGen get dash => const $AssetsImagesDashGen(); $AssetsImagesDinoGen get dino => const $AssetsImagesDinoGen(); @@ -29,19 +32,18 @@ class $AssetsImagesGen { $AssetsImagesPlungerGen get plunger => const $AssetsImagesPlungerGen(); $AssetsImagesSignpostGen get signpost => const $AssetsImagesSignpostGen(); $AssetsImagesSlingshotGen get slingshot => const $AssetsImagesSlingshotGen(); - $AssetsImagesSpaceshipGen get spaceship => const $AssetsImagesSpaceshipGen(); $AssetsImagesSparkyGen get sparky => const $AssetsImagesSparkyGen(); } -class $AssetsImagesAndroidBumperGen { - const $AssetsImagesAndroidBumperGen(); +class $AssetsImagesAndroidGen { + const $AssetsImagesAndroidGen(); - $AssetsImagesAndroidBumperAGen get a => - const $AssetsImagesAndroidBumperAGen(); - $AssetsImagesAndroidBumperBGen get b => - const $AssetsImagesAndroidBumperBGen(); - $AssetsImagesAndroidBumperCowGen get cow => - const $AssetsImagesAndroidBumperCowGen(); + $AssetsImagesAndroidBumperGen get bumper => + const $AssetsImagesAndroidBumperGen(); + $AssetsImagesAndroidRailGen get rail => const $AssetsImagesAndroidRailGen(); + $AssetsImagesAndroidRampGen get ramp => const $AssetsImagesAndroidRampGen(); + $AssetsImagesAndroidSpaceshipGen get spaceship => + const $AssetsImagesAndroidSpaceshipGen(); } class $AssetsImagesBackboardGen { @@ -246,23 +248,6 @@ class $AssetsImagesSlingshotGen { const AssetGenImage('assets/images/slingshot/upper.png'); } -class $AssetsImagesSpaceshipGen { - const $AssetsImagesSpaceshipGen(); - - /// File path: assets/images/spaceship/bridge.png - AssetGenImage get bridge => - const AssetGenImage('assets/images/spaceship/bridge.png'); - - $AssetsImagesSpaceshipRailGen get rail => - const $AssetsImagesSpaceshipRailGen(); - $AssetsImagesSpaceshipRampGen get ramp => - const $AssetsImagesSpaceshipRampGen(); - - /// File path: assets/images/spaceship/saucer.png - AssetGenImage get saucer => - const AssetGenImage('assets/images/spaceship/saucer.png'); -} - class $AssetsImagesSparkyGen { const $AssetsImagesSparkyGen(); @@ -276,40 +261,66 @@ class $AssetsImagesSparkyGen { const $AssetsImagesSparkyComputerGen(); } -class $AssetsImagesAndroidBumperAGen { - const $AssetsImagesAndroidBumperAGen(); +class $AssetsImagesAndroidBumperGen { + const $AssetsImagesAndroidBumperGen(); - /// File path: assets/images/android_bumper/a/dimmed.png - AssetGenImage get dimmed => - const AssetGenImage('assets/images/android_bumper/a/dimmed.png'); + $AssetsImagesAndroidBumperAGen get a => + const $AssetsImagesAndroidBumperAGen(); + $AssetsImagesAndroidBumperBGen get b => + const $AssetsImagesAndroidBumperBGen(); + $AssetsImagesAndroidBumperCowGen get cow => + const $AssetsImagesAndroidBumperCowGen(); +} - /// File path: assets/images/android_bumper/a/lit.png - AssetGenImage get lit => - const AssetGenImage('assets/images/android_bumper/a/lit.png'); +class $AssetsImagesAndroidRailGen { + const $AssetsImagesAndroidRailGen(); + + /// File path: assets/images/android/rail/exit.png + AssetGenImage get exit => + const AssetGenImage('assets/images/android/rail/exit.png'); + + /// File path: assets/images/android/rail/main.png + AssetGenImage get main => + const AssetGenImage('assets/images/android/rail/main.png'); } -class $AssetsImagesAndroidBumperBGen { - const $AssetsImagesAndroidBumperBGen(); +class $AssetsImagesAndroidRampGen { + const $AssetsImagesAndroidRampGen(); - /// File path: assets/images/android_bumper/b/dimmed.png - AssetGenImage get dimmed => - const AssetGenImage('assets/images/android_bumper/b/dimmed.png'); + $AssetsImagesAndroidRampArrowGen get arrow => + const $AssetsImagesAndroidRampArrowGen(); - /// File path: assets/images/android_bumper/b/lit.png - AssetGenImage get lit => - const AssetGenImage('assets/images/android_bumper/b/lit.png'); + /// File path: assets/images/android/ramp/board-opening.png + AssetGenImage get boardOpening => + const AssetGenImage('assets/images/android/ramp/board-opening.png'); + + /// File path: assets/images/android/ramp/main.png + AssetGenImage get main => + const AssetGenImage('assets/images/android/ramp/main.png'); + + /// File path: assets/images/android/ramp/railing-background.png + AssetGenImage get railingBackground => + const AssetGenImage('assets/images/android/ramp/railing-background.png'); + + /// File path: assets/images/android/ramp/railing-foreground.png + AssetGenImage get railingForeground => + const AssetGenImage('assets/images/android/ramp/railing-foreground.png'); } -class $AssetsImagesAndroidBumperCowGen { - const $AssetsImagesAndroidBumperCowGen(); +class $AssetsImagesAndroidSpaceshipGen { + const $AssetsImagesAndroidSpaceshipGen(); - /// File path: assets/images/android_bumper/cow/dimmed.png - AssetGenImage get dimmed => - const AssetGenImage('assets/images/android_bumper/cow/dimmed.png'); + /// File path: assets/images/android/spaceship/animatronic.png + AssetGenImage get animatronic => + const AssetGenImage('assets/images/android/spaceship/animatronic.png'); - /// File path: assets/images/android_bumper/cow/lit.png - AssetGenImage get lit => - const AssetGenImage('assets/images/android_bumper/cow/lit.png'); + /// File path: assets/images/android/spaceship/light-beam.png + AssetGenImage get lightBeam => + const AssetGenImage('assets/images/android/spaceship/light-beam.png'); + + /// File path: assets/images/android/spaceship/saucer.png + AssetGenImage get saucer => + const AssetGenImage('assets/images/android/spaceship/saucer.png'); } class $AssetsImagesDashBumperGen { @@ -393,41 +404,6 @@ class $AssetsImagesMultiplierX6Gen { const AssetGenImage('assets/images/multiplier/x6/lit.png'); } -class $AssetsImagesSpaceshipRailGen { - const $AssetsImagesSpaceshipRailGen(); - - /// File path: assets/images/spaceship/rail/exit.png - AssetGenImage get exit => - const AssetGenImage('assets/images/spaceship/rail/exit.png'); - - /// File path: assets/images/spaceship/rail/main.png - AssetGenImage get main => - const AssetGenImage('assets/images/spaceship/rail/main.png'); -} - -class $AssetsImagesSpaceshipRampGen { - const $AssetsImagesSpaceshipRampGen(); - - $AssetsImagesSpaceshipRampArrowGen get arrow => - const $AssetsImagesSpaceshipRampArrowGen(); - - /// File path: assets/images/spaceship/ramp/board-opening.png - AssetGenImage get boardOpening => - const AssetGenImage('assets/images/spaceship/ramp/board-opening.png'); - - /// File path: assets/images/spaceship/ramp/main.png - AssetGenImage get main => - const AssetGenImage('assets/images/spaceship/ramp/main.png'); - - /// File path: assets/images/spaceship/ramp/railing-background.png - AssetGenImage get railingBackground => const AssetGenImage( - 'assets/images/spaceship/ramp/railing-background.png'); - - /// File path: assets/images/spaceship/ramp/railing-foreground.png - AssetGenImage get railingForeground => const AssetGenImage( - 'assets/images/spaceship/ramp/railing-foreground.png'); -} - class $AssetsImagesSparkyBumperGen { const $AssetsImagesSparkyBumperGen(); @@ -452,6 +428,70 @@ class $AssetsImagesSparkyComputerGen { const AssetGenImage('assets/images/sparky/computer/top.png'); } +class $AssetsImagesAndroidBumperAGen { + const $AssetsImagesAndroidBumperAGen(); + + /// File path: assets/images/android/bumper/a/dimmed.png + AssetGenImage get dimmed => + const AssetGenImage('assets/images/android/bumper/a/dimmed.png'); + + /// File path: assets/images/android/bumper/a/lit.png + AssetGenImage get lit => + const AssetGenImage('assets/images/android/bumper/a/lit.png'); +} + +class $AssetsImagesAndroidBumperBGen { + const $AssetsImagesAndroidBumperBGen(); + + /// File path: assets/images/android/bumper/b/dimmed.png + AssetGenImage get dimmed => + const AssetGenImage('assets/images/android/bumper/b/dimmed.png'); + + /// File path: assets/images/android/bumper/b/lit.png + AssetGenImage get lit => + const AssetGenImage('assets/images/android/bumper/b/lit.png'); +} + +class $AssetsImagesAndroidBumperCowGen { + const $AssetsImagesAndroidBumperCowGen(); + + /// File path: assets/images/android/bumper/cow/dimmed.png + AssetGenImage get dimmed => + const AssetGenImage('assets/images/android/bumper/cow/dimmed.png'); + + /// File path: assets/images/android/bumper/cow/lit.png + AssetGenImage get lit => + const AssetGenImage('assets/images/android/bumper/cow/lit.png'); +} + +class $AssetsImagesAndroidRampArrowGen { + const $AssetsImagesAndroidRampArrowGen(); + + /// File path: assets/images/android/ramp/arrow/active1.png + AssetGenImage get active1 => + const AssetGenImage('assets/images/android/ramp/arrow/active1.png'); + + /// File path: assets/images/android/ramp/arrow/active2.png + AssetGenImage get active2 => + const AssetGenImage('assets/images/android/ramp/arrow/active2.png'); + + /// File path: assets/images/android/ramp/arrow/active3.png + AssetGenImage get active3 => + const AssetGenImage('assets/images/android/ramp/arrow/active3.png'); + + /// File path: assets/images/android/ramp/arrow/active4.png + AssetGenImage get active4 => + const AssetGenImage('assets/images/android/ramp/arrow/active4.png'); + + /// File path: assets/images/android/ramp/arrow/active5.png + AssetGenImage get active5 => + const AssetGenImage('assets/images/android/ramp/arrow/active5.png'); + + /// File path: assets/images/android/ramp/arrow/inactive.png + AssetGenImage get inactive => + const AssetGenImage('assets/images/android/ramp/arrow/inactive.png'); +} + class $AssetsImagesDashBumperAGen { const $AssetsImagesDashBumperAGen(); @@ -488,34 +528,6 @@ class $AssetsImagesDashBumperMainGen { const AssetGenImage('assets/images/dash/bumper/main/inactive.png'); } -class $AssetsImagesSpaceshipRampArrowGen { - const $AssetsImagesSpaceshipRampArrowGen(); - - /// File path: assets/images/spaceship/ramp/arrow/active1.png - AssetGenImage get active1 => - const AssetGenImage('assets/images/spaceship/ramp/arrow/active1.png'); - - /// File path: assets/images/spaceship/ramp/arrow/active2.png - AssetGenImage get active2 => - const AssetGenImage('assets/images/spaceship/ramp/arrow/active2.png'); - - /// File path: assets/images/spaceship/ramp/arrow/active3.png - AssetGenImage get active3 => - const AssetGenImage('assets/images/spaceship/ramp/arrow/active3.png'); - - /// File path: assets/images/spaceship/ramp/arrow/active4.png - AssetGenImage get active4 => - const AssetGenImage('assets/images/spaceship/ramp/arrow/active4.png'); - - /// File path: assets/images/spaceship/ramp/arrow/active5.png - AssetGenImage get active5 => - const AssetGenImage('assets/images/spaceship/ramp/arrow/active5.png'); - - /// File path: assets/images/spaceship/ramp/arrow/inactive.png - AssetGenImage get inactive => - const AssetGenImage('assets/images/spaceship/ramp/arrow/inactive.png'); -} - class $AssetsImagesSparkyBumperAGen { const $AssetsImagesSparkyBumperAGen(); diff --git a/packages/pinball_components/lib/src/components/android_bumper/android_bumper.dart b/packages/pinball_components/lib/src/components/android_bumper/android_bumper.dart index 4cefc28d..e1a3857e 100644 --- a/packages/pinball_components/lib/src/components/android_bumper/android_bumper.dart +++ b/packages/pinball_components/lib/src/components/android_bumper/android_bumper.dart @@ -10,7 +10,7 @@ import 'package:pinball_flame/pinball_flame.dart'; export 'cubit/android_bumper_cubit.dart'; /// {@template android_bumper} -/// Bumper for area under the [Spaceship]. +/// Bumper for area under the [AndroidSpaceship]. /// {@endtemplate} class AndroidBumper extends BodyComponent with InitialPosition { /// {@macro android_bumper} @@ -46,8 +46,8 @@ class AndroidBumper extends BodyComponent with InitialPosition { }) : this._( majorRadius: 3.52, minorRadius: 2.97, - litAssetPath: Assets.images.androidBumper.a.lit.keyName, - dimmedAssetPath: Assets.images.androidBumper.a.dimmed.keyName, + litAssetPath: Assets.images.android.bumper.a.lit.keyName, + dimmedAssetPath: Assets.images.android.bumper.a.dimmed.keyName, spritePosition: Vector2(0, -0.1), bloc: AndroidBumperCubit(), children: children, @@ -59,8 +59,8 @@ class AndroidBumper extends BodyComponent with InitialPosition { }) : this._( majorRadius: 3.19, minorRadius: 2.79, - litAssetPath: Assets.images.androidBumper.b.lit.keyName, - dimmedAssetPath: Assets.images.androidBumper.b.dimmed.keyName, + litAssetPath: Assets.images.android.bumper.b.lit.keyName, + dimmedAssetPath: Assets.images.android.bumper.b.dimmed.keyName, spritePosition: Vector2(0, -0.1), bloc: AndroidBumperCubit(), children: children, @@ -72,8 +72,8 @@ class AndroidBumper extends BodyComponent with InitialPosition { }) : this._( majorRadius: 3.4, minorRadius: 2.9, - litAssetPath: Assets.images.androidBumper.cow.lit.keyName, - dimmedAssetPath: Assets.images.androidBumper.cow.dimmed.keyName, + litAssetPath: Assets.images.android.bumper.cow.lit.keyName, + dimmedAssetPath: Assets.images.android.bumper.cow.dimmed.keyName, spritePosition: Vector2(0, -0.68), bloc: AndroidBumperCubit(), children: children, diff --git a/packages/pinball_components/lib/src/components/android_spaceship.dart b/packages/pinball_components/lib/src/components/android_spaceship.dart new file mode 100644 index 00000000..1dcf6780 --- /dev/null +++ b/packages/pinball_components/lib/src/components/android_spaceship.dart @@ -0,0 +1,209 @@ +// ignore_for_file: public_member_api_docs + +import 'dart:async'; +import 'dart:math' as math; + +import 'package:flame/components.dart'; +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:pinball_components/gen/assets.gen.dart'; +import 'package:pinball_components/pinball_components.dart' hide Assets; +import 'package:pinball_flame/pinball_flame.dart'; + +class AndroidSpaceship extends Blueprint { + AndroidSpaceship({required Vector2 position}) + : super( + components: [ + _SpaceshipSaucer()..initialPosition = position, + _SpaceshipSaucerSpriteAnimationComponent()..position = position, + _LightBeamSpriteComponent()..position = position + Vector2(2.5, 5), + _AndroidHead()..initialPosition = position + Vector2(0.5, 0.25), + _SpaceshipHole( + outsideLayer: Layer.spaceshipExitRail, + outsidePriority: RenderPriority.ballOnSpaceshipRail, + )..initialPosition = position - Vector2(5.3, -5.4), + _SpaceshipHole( + outsideLayer: Layer.board, + outsidePriority: RenderPriority.ballOnBoard, + )..initialPosition = position - Vector2(-7.5, -1.1), + ], + ); +} + +class _SpaceshipSaucer extends BodyComponent with InitialPosition, Layered { + _SpaceshipSaucer() : super(renderBody: false) { + layer = Layer.spaceship; + } + + @override + Body createBody() { + final shape = _SpaceshipSaucerShape(); + final bodyDef = BodyDef( + position: initialPosition, + userData: this, + angle: -1.7, + ); + + return world.createBody(bodyDef)..createFixtureFromShape(shape); + } +} + +class _SpaceshipSaucerShape extends ChainShape { + _SpaceshipSaucerShape() { + const minorRadius = 9.75; + const majorRadius = 11.9; + + createChain( + [ + for (var angle = 0.2618; angle <= 6.0214; angle += math.pi / 180) + Vector2( + minorRadius * math.cos(angle), + majorRadius * math.sin(angle), + ), + ], + ); + } +} + +class _SpaceshipSaucerSpriteAnimationComponent extends SpriteAnimationComponent + with HasGameRef { + _SpaceshipSaucerSpriteAnimationComponent() + : super( + anchor: Anchor.center, + priority: RenderPriority.spaceshipSaucer, + ); + + @override + Future onLoad() async { + await super.onLoad(); + + final spriteSheet = gameRef.images.fromCache( + Assets.images.android.spaceship.saucer.keyName, + ); + + const amountPerRow = 5; + const amountPerColumn = 3; + final textureSize = Vector2( + spriteSheet.width / amountPerRow, + spriteSheet.height / amountPerColumn, + ); + size = textureSize / 10; + + animation = SpriteAnimation.fromFrameData( + spriteSheet, + SpriteAnimationData.sequenced( + amount: amountPerRow * amountPerColumn, + amountPerRow: amountPerRow, + stepTime: 1 / 24, + textureSize: textureSize, + ), + ); + } +} + +// TODO(allisonryan0002): add pulsing behavior. +class _LightBeamSpriteComponent extends SpriteComponent with HasGameRef { + _LightBeamSpriteComponent() + : super( + anchor: Anchor.center, + priority: RenderPriority.spaceshipLightBeam, + ); + + @override + Future onLoad() async { + await super.onLoad(); + final sprite = Sprite( + gameRef.images.fromCache( + Assets.images.android.spaceship.lightBeam.keyName, + ), + ); + this.sprite = sprite; + size = sprite.originalSize / 10; + } +} + +class _AndroidHead extends BodyComponent with InitialPosition, Layered { + _AndroidHead() + : super( + priority: RenderPriority.androidHead, + children: [_AndroidHeadSpriteAnimationComponent()], + renderBody: false, + ) { + layer = Layer.spaceship; + } + + @override + Body createBody() { + final shape = EllipseShape( + center: Vector2.zero(), + majorRadius: 3.1, + minorRadius: 2, + )..rotate(1.4); + // TODO(allisonryan0002): use bumping behavior. + final fixtureDef = FixtureDef( + shape, + restitution: 0.1, + ); + final bodyDef = BodyDef(position: initialPosition); + + return world.createBody(bodyDef)..createFixture(fixtureDef); + } +} + +class _AndroidHeadSpriteAnimationComponent extends SpriteAnimationComponent + with HasGameRef { + _AndroidHeadSpriteAnimationComponent() + : super( + anchor: Anchor.center, + position: Vector2(-0.24, -2.6), + ); + + @override + Future onLoad() async { + await super.onLoad(); + + final spriteSheet = gameRef.images.fromCache( + Assets.images.android.spaceship.animatronic.keyName, + ); + + const amountPerRow = 18; + const amountPerColumn = 4; + final textureSize = Vector2( + spriteSheet.width / amountPerRow, + spriteSheet.height / amountPerColumn, + ); + size = textureSize / 10; + + animation = SpriteAnimation.fromFrameData( + spriteSheet, + SpriteAnimationData.sequenced( + amount: amountPerRow * amountPerColumn, + amountPerRow: amountPerRow, + stepTime: 1 / 24, + textureSize: textureSize, + ), + ); + } +} + +class _SpaceshipHole extends LayerSensor { + _SpaceshipHole({required Layer outsideLayer, required int outsidePriority}) + : super( + insideLayer: Layer.spaceship, + outsideLayer: outsideLayer, + orientation: LayerEntranceOrientation.down, + insidePriority: RenderPriority.ballOnSpaceship, + outsidePriority: outsidePriority, + ) { + layer = Layer.spaceship; + } + + @override + Shape get shape { + return ArcShape( + center: Vector2(0, -3.2), + arcRadius: 5, + angle: 1, + rotation: -2, + ); + } +} diff --git a/packages/pinball_components/lib/src/components/ball.dart b/packages/pinball_components/lib/src/components/ball.dart index 1c9c1270..64c7d884 100644 --- a/packages/pinball_components/lib/src/components/ball.dart +++ b/packages/pinball_components/lib/src/components/ball.dart @@ -115,7 +115,7 @@ class Ball extends BodyComponent math.pow(defaultGravity, 2) - math.pow(positionalXForce, 2), ); - body.gravityOverride = Vector2(positionalXForce, positionalYForce); + body.gravityOverride = Vector2(-positionalXForce, positionalYForce); } } diff --git a/packages/pinball_components/lib/src/components/board_background_sprite_component.dart b/packages/pinball_components/lib/src/components/board_background_sprite_component.dart new file mode 100644 index 00000000..1a4e34c6 --- /dev/null +++ b/packages/pinball_components/lib/src/components/board_background_sprite_component.dart @@ -0,0 +1,26 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flame/components.dart'; +import 'package:pinball_components/pinball_components.dart'; + +class BoardBackgroundSpriteComponent extends SpriteComponent with HasGameRef { + BoardBackgroundSpriteComponent() + : super( + anchor: Anchor.center, + priority: RenderPriority.boardBackground, + position: Vector2(0, -1), + ); + + @override + Future onLoad() async { + await super.onLoad(); + + final sprite = Sprite( + gameRef.images.fromCache( + Assets.images.boardBackground.keyName, + ), + ); + this.sprite = sprite; + size = sprite.originalSize / 10; + } +} diff --git a/packages/pinball_components/lib/src/components/components.dart b/packages/pinball_components/lib/src/components/components.dart index f16aa0a6..2781030e 100644 --- a/packages/pinball_components/lib/src/components/components.dart +++ b/packages/pinball_components/lib/src/components/components.dart @@ -1,7 +1,9 @@ export 'android_bumper/android_bumper.dart'; +export 'android_spaceship.dart'; export 'backboard/backboard.dart'; export 'ball.dart'; export 'baseboard.dart'; +export 'board_background_sprite_component.dart'; export 'board_dimensions.dart'; export 'board_side.dart'; export 'boundaries.dart'; @@ -27,7 +29,6 @@ export 'score_text.dart'; export 'shapes/shapes.dart'; export 'signpost.dart'; export 'slingshot.dart'; -export 'spaceship.dart'; export 'spaceship_rail.dart'; export 'spaceship_ramp.dart'; export 'sparky_animatronic.dart'; diff --git a/packages/pinball_components/lib/src/components/render_priority.dart b/packages/pinball_components/lib/src/components/render_priority.dart index e79d1f59..b11a5209 100644 --- a/packages/pinball_components/lib/src/components/render_priority.dart +++ b/packages/pinball_components/lib/src/components/render_priority.dart @@ -20,7 +20,7 @@ abstract class RenderPriority { static const int ballOnSpaceshipRamp = _above + spaceshipRampBackgroundRailing; - /// Render priority for the [Ball] while it's on the [Spaceship]. + /// Render priority for the [Ball] while it's on the [AndroidSpaceship]. static const int ballOnSpaceship = _above + spaceshipSaucer; /// Render priority for the [Ball] while it's on the [SpaceshipRail]. @@ -33,13 +33,13 @@ abstract class RenderPriority { // TODO(allisonryan0002): fix this magic priority. Could bump all priorities // so there are no negatives. - static const int background = 3 * _below + _base; + static const int boardBackground = 3 * _below + _base; // Boundaries static const int bottomBoundary = _above + dinoBottomWall; - static const int outerBoundary = _above + background; + static const int outerBoundary = _above + boardBackground; static const int outerBottomBoundary = _above + rocket; @@ -93,7 +93,7 @@ abstract class RenderPriority { static const int spaceshipSaucer = _above + ballOnSpaceshipRail; - static const int spaceshipSaucerWall = _above + spaceshipSaucer; + static const int spaceshipLightBeam = _below + spaceshipSaucer; static const int androidHead = _above + spaceshipSaucer; diff --git a/packages/pinball_components/lib/src/components/spaceship.dart b/packages/pinball_components/lib/src/components/spaceship.dart deleted file mode 100644 index a52df81d..00000000 --- a/packages/pinball_components/lib/src/components/spaceship.dart +++ /dev/null @@ -1,246 +0,0 @@ -import 'dart:async'; -import 'dart:math'; - -import 'package:flame/components.dart'; -import 'package:flame_forge2d/flame_forge2d.dart'; -import 'package:pinball_components/gen/assets.gen.dart'; -import 'package:pinball_components/pinball_components.dart' hide Assets; -import 'package:pinball_flame/pinball_flame.dart'; - -/// {@template spaceship} -/// A [Blueprint] which creates the spaceship feature. -/// {@endtemplate} -class Spaceship extends Blueprint { - /// {@macro spaceship} - Spaceship({required Vector2 position}) - : super( - components: [ - SpaceshipSaucer()..initialPosition = position, - _SpaceshipEntrance()..initialPosition = position, - AndroidHead()..initialPosition = position, - _SpaceshipHole( - outsideLayer: Layer.spaceshipExitRail, - outsidePriority: RenderPriority.ballOnSpaceshipRail, - )..initialPosition = position - Vector2(5.2, -4.8), - _SpaceshipHole( - outsideLayer: Layer.board, - outsidePriority: RenderPriority.ballOnBoard, - )..initialPosition = position - Vector2(-7.2, -0.8), - SpaceshipWall()..initialPosition = position, - ], - ); - - /// Total size of the spaceship. - static final size = Vector2(25, 19); -} - -/// {@template spaceship_saucer} -/// A [BodyComponent] for the base, or the saucer of the spaceship -/// {@endtemplate} -class SpaceshipSaucer extends BodyComponent with InitialPosition, Layered { - /// {@macro spaceship_saucer} - SpaceshipSaucer() - : super( - priority: RenderPriority.spaceshipSaucer, - renderBody: false, - children: [ - _SpaceshipSaucerSpriteComponent(), - ], - ) { - layer = Layer.spaceship; - } - - @override - Body createBody() { - final shape = CircleShape()..radius = 3; - final fixtureDef = FixtureDef( - shape, - isSensor: true, - ); - final bodyDef = BodyDef( - position: initialPosition, - userData: this, - ); - - return world.createBody(bodyDef)..createFixture(fixtureDef); - } -} - -class _SpaceshipSaucerSpriteComponent extends SpriteComponent with HasGameRef { - _SpaceshipSaucerSpriteComponent() - : super( - anchor: Anchor.center, - // TODO(alestiago): Refactor to use sprite orignial size instead. - size: Spaceship.size, - ); - - @override - Future onLoad() async { - await super.onLoad(); - - // TODO(alestiago): Use cached sprite. - sprite = await gameRef.loadSprite( - Assets.images.spaceship.saucer.keyName, - ); - } -} - -/// {@template spaceship_bridge} -/// A [BodyComponent] that provides both the collision and the rotation -/// animation for the bridge. -/// {@endtemplate} -class AndroidHead extends BodyComponent with InitialPosition, Layered { - /// {@macro spaceship_bridge} - AndroidHead() - : super( - priority: RenderPriority.androidHead, - children: [_AndroidHeadSpriteAnimation()], - renderBody: false, - ) { - layer = Layer.spaceship; - } - - @override - Body createBody() { - final circleShape = CircleShape()..radius = 2; - - final bodyDef = BodyDef( - position: initialPosition, - userData: this, - ); - - return world.createBody(bodyDef) - ..createFixture( - FixtureDef(circleShape)..restitution = 0.4, - ); - } -} - -class _AndroidHeadSpriteAnimation extends SpriteAnimationComponent - with HasGameRef { - @override - Future onLoad() async { - await super.onLoad(); - - final image = await gameRef.images.load( - Assets.images.spaceship.bridge.keyName, - ); - size = Vector2(8.2, 10); - position = Vector2(0, -2); - anchor = Anchor.center; - - final data = SpriteAnimationData.sequenced( - amount: 72, - amountPerRow: 24, - stepTime: 0.05, - textureSize: size * 10, - ); - animation = SpriteAnimation.fromFrameData(image, data); - } -} - -class _SpaceshipEntrance extends LayerSensor { - _SpaceshipEntrance() - : super( - insideLayer: Layer.spaceship, - orientation: LayerEntranceOrientation.up, - insidePriority: RenderPriority.ballOnSpaceship, - ) { - layer = Layer.spaceship; - } - - @override - Shape get shape { - final radius = Spaceship.size.y / 2; - return PolygonShape() - ..setAsEdge( - Vector2( - radius * cos(20 * pi / 180), - radius * sin(20 * pi / 180), - )..rotate(90 * pi / 180), - Vector2( - radius * cos(340 * pi / 180), - radius * sin(340 * pi / 180), - )..rotate(90 * pi / 180), - ); - } -} - -class _SpaceshipHole extends LayerSensor { - _SpaceshipHole({required Layer outsideLayer, required int outsidePriority}) - : super( - insideLayer: Layer.spaceship, - outsideLayer: outsideLayer, - orientation: LayerEntranceOrientation.down, - insidePriority: RenderPriority.ballOnSpaceship, - outsidePriority: outsidePriority, - ) { - layer = Layer.spaceship; - } - - @override - Shape get shape { - return ArcShape( - center: Vector2(0, -3.2), - arcRadius: 5, - angle: 1, - rotation: -2, - ); - } -} - -/// {@template spaceship_wall_shape} -/// The [ChainShape] that defines the shape of the [SpaceshipWall]. -/// {@endtemplate} -class _SpaceshipWallShape extends ChainShape { - /// {@macro spaceship_wall_shape} - _SpaceshipWallShape() { - final minorRadius = (Spaceship.size.y - 2) / 2; - final majorRadius = (Spaceship.size.x - 2) / 2; - - createChain( - [ - // TODO(alestiago): Try converting this logic to radian. - for (var angle = 20; angle <= 340; angle++) - Vector2( - minorRadius * cos(angle * pi / 180), - majorRadius * sin(angle * pi / 180), - ), - ], - ); - } -} - -/// {@template spaceship_wall} -/// A [BodyComponent] that provides the collision for the wall -/// surrounding the spaceship. -/// -/// It has a small opening to allow the [Ball] to get inside the spaceship -/// saucer. -/// -/// It also contains the [SpriteComponent] for the lower wall -/// {@endtemplate} -class SpaceshipWall extends BodyComponent with InitialPosition, Layered { - /// {@macro spaceship_wall} - SpaceshipWall() - : super( - priority: RenderPriority.spaceshipSaucerWall, - renderBody: false, - ) { - layer = Layer.spaceship; - } - - @override - Body createBody() { - final shape = _SpaceshipWallShape(); - final fixtureDef = FixtureDef(shape); - - final bodyDef = BodyDef( - position: initialPosition, - userData: this, - angle: -1.7, - ); - - return world.createBody(bodyDef)..createFixture(fixtureDef); - } -} diff --git a/packages/pinball_components/lib/src/components/spaceship_rail.dart b/packages/pinball_components/lib/src/components/spaceship_rail.dart index 91540c62..df9fc16c 100644 --- a/packages/pinball_components/lib/src/components/spaceship_rail.dart +++ b/packages/pinball_components/lib/src/components/spaceship_rail.dart @@ -6,7 +6,7 @@ import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_flame/pinball_flame.dart'; /// {@template spaceship_rail} -/// A [Blueprint] for the rail exiting the [Spaceship]. +/// A [Blueprint] for the rail exiting the [AndroidSpaceship]. /// {@endtemplate} class SpaceshipRail extends Blueprint { /// {@macro spaceship_rail} @@ -116,7 +116,7 @@ class _SpaceshipRailSpriteComponent extends SpriteComponent with HasGameRef { final sprite = Sprite( gameRef.images.fromCache( - Assets.images.spaceship.rail.main.keyName, + Assets.images.android.rail.main.keyName, ), ); this.sprite = sprite; @@ -139,7 +139,7 @@ class _SpaceshipRailExitSpriteComponent extends SpriteComponent final sprite = Sprite( gameRef.images.fromCache( - Assets.images.spaceship.rail.exit.keyName, + Assets.images.android.rail.exit.keyName, ), ); this.sprite = sprite; diff --git a/packages/pinball_components/lib/src/components/spaceship_ramp.dart b/packages/pinball_components/lib/src/components/spaceship_ramp.dart index c9a1d574..6a034daa 100644 --- a/packages/pinball_components/lib/src/components/spaceship_ramp.dart +++ b/packages/pinball_components/lib/src/components/spaceship_ramp.dart @@ -8,7 +8,7 @@ import 'package:pinball_components/pinball_components.dart' hide Assets; import 'package:pinball_flame/pinball_flame.dart'; /// {@template spaceship_ramp} -/// A [Blueprint] which creates the ramp leading into the [Spaceship]. +/// A [Blueprint] which creates the ramp leading into the [AndroidSpaceship]. /// {@endtemplate} class SpaceshipRamp extends Blueprint { /// {@macro spaceship_ramp} @@ -73,17 +73,17 @@ extension on SpaceshipRampArrowSpriteState { String get path { switch (this) { case SpaceshipRampArrowSpriteState.inactive: - return Assets.images.spaceship.ramp.arrow.inactive.keyName; + return Assets.images.android.ramp.arrow.inactive.keyName; case SpaceshipRampArrowSpriteState.active1: - return Assets.images.spaceship.ramp.arrow.active1.keyName; + return Assets.images.android.ramp.arrow.active1.keyName; case SpaceshipRampArrowSpriteState.active2: - return Assets.images.spaceship.ramp.arrow.active2.keyName; + return Assets.images.android.ramp.arrow.active2.keyName; case SpaceshipRampArrowSpriteState.active3: - return Assets.images.spaceship.ramp.arrow.active3.keyName; + return Assets.images.android.ramp.arrow.active3.keyName; case SpaceshipRampArrowSpriteState.active4: - return Assets.images.spaceship.ramp.arrow.active4.keyName; + return Assets.images.android.ramp.arrow.active4.keyName; case SpaceshipRampArrowSpriteState.active5: - return Assets.images.spaceship.ramp.arrow.active5.keyName; + return Assets.images.android.ramp.arrow.active5.keyName; } } @@ -161,7 +161,7 @@ class _SpaceshipRampBackgroundRailingSpriteComponent extends SpriteComponent await super.onLoad(); final sprite = Sprite( gameRef.images.fromCache( - Assets.images.spaceship.ramp.railingBackground.keyName, + Assets.images.android.ramp.railingBackground.keyName, ), ); this.sprite = sprite; @@ -182,7 +182,7 @@ class _SpaceshipRampBackgroundRampSpriteComponent extends SpriteComponent await super.onLoad(); final sprite = Sprite( gameRef.images.fromCache( - Assets.images.spaceship.ramp.main.keyName, + Assets.images.android.ramp.main.keyName, ), ); this.sprite = sprite; @@ -234,7 +234,7 @@ class _SpaceshipRampBoardOpeningSpriteComponent extends SpriteComponent await super.onLoad(); final sprite = Sprite( gameRef.images.fromCache( - Assets.images.spaceship.ramp.boardOpening.keyName, + Assets.images.android.ramp.boardOpening.keyName, ), ); this.sprite = sprite; @@ -304,7 +304,7 @@ class _SpaceshipRampForegroundRailingSpriteComponent extends SpriteComponent await super.onLoad(); final sprite = Sprite( gameRef.images.fromCache( - Assets.images.spaceship.ramp.railingForeground.keyName, + Assets.images.android.ramp.railingForeground.keyName, ), ); this.sprite = sprite; diff --git a/packages/pinball_components/pubspec.yaml b/packages/pinball_components/pubspec.yaml index 37f9bd63..29b4e31a 100644 --- a/packages/pinball_components/pubspec.yaml +++ b/packages/pinball_components/pubspec.yaml @@ -57,16 +57,16 @@ flutter: - assets/images/dash/bumper/a/ - assets/images/dash/bumper/b/ - assets/images/dash/bumper/main/ - - assets/images/spaceship/ - - assets/images/spaceship/rail/ - - assets/images/spaceship/ramp/ - - assets/images/spaceship/ramp/arrow/ + - assets/images/android/spaceship/ + - assets/images/android/rail/ + - assets/images/android/ramp/ + - assets/images/android/ramp/arrow/ + - assets/images/android/bumper/a/ + - assets/images/android/bumper/b/ + - assets/images/android/bumper/cow/ - assets/images/kicker/ - assets/images/plunger/ - assets/images/slingshot/ - - assets/images/android_bumper/a/ - - assets/images/android_bumper/b/ - - assets/images/android_bumper/cow/ - assets/images/sparky/ - assets/images/sparky/computer/ - assets/images/sparky/bumper/a/ diff --git a/packages/pinball_components/sandbox/lib/stories/android_acres/android_bumper_a_game.dart b/packages/pinball_components/sandbox/lib/stories/android_acres/android_bumper_a_game.dart index 4dcd1cb8..32638c2d 100644 --- a/packages/pinball_components/sandbox/lib/stories/android_acres/android_bumper_a_game.dart +++ b/packages/pinball_components/sandbox/lib/stories/android_acres/android_bumper_a_game.dart @@ -9,8 +9,8 @@ class AndroidBumperAGame extends BallGame { : super( color: const Color(0xFF0000FF), imagesFileNames: [ - Assets.images.androidBumper.a.lit.keyName, - Assets.images.androidBumper.a.dimmed.keyName, + Assets.images.android.bumper.a.lit.keyName, + Assets.images.android.bumper.a.dimmed.keyName, ], ); diff --git a/packages/pinball_components/sandbox/lib/stories/android_acres/android_bumper_b_game.dart b/packages/pinball_components/sandbox/lib/stories/android_acres/android_bumper_b_game.dart index e504fe1e..bfd4206c 100644 --- a/packages/pinball_components/sandbox/lib/stories/android_acres/android_bumper_b_game.dart +++ b/packages/pinball_components/sandbox/lib/stories/android_acres/android_bumper_b_game.dart @@ -9,8 +9,8 @@ class AndroidBumperBGame extends BallGame { : super( color: const Color(0xFF0000FF), imagesFileNames: [ - Assets.images.androidBumper.b.lit.keyName, - Assets.images.androidBumper.b.dimmed.keyName, + Assets.images.android.bumper.b.lit.keyName, + Assets.images.android.bumper.b.dimmed.keyName, ], ); diff --git a/packages/pinball_components/sandbox/lib/stories/android_acres/android_bumper_cow_game.dart b/packages/pinball_components/sandbox/lib/stories/android_acres/android_bumper_cow_game.dart index 3b0aa828..ac1bc6fe 100644 --- a/packages/pinball_components/sandbox/lib/stories/android_acres/android_bumper_cow_game.dart +++ b/packages/pinball_components/sandbox/lib/stories/android_acres/android_bumper_cow_game.dart @@ -8,8 +8,8 @@ class AndroidBumperCowGame extends BallGame { AndroidBumperCowGame() : super( imagesFileNames: [ - Assets.images.androidBumper.cow.lit.keyName, - Assets.images.androidBumper.cow.dimmed.keyName, + Assets.images.android.bumper.cow.lit.keyName, + Assets.images.android.bumper.cow.dimmed.keyName, ], ); diff --git a/packages/pinball_components/sandbox/lib/stories/android_acres/android_spaceship_game.dart b/packages/pinball_components/sandbox/lib/stories/android_acres/android_spaceship_game.dart new file mode 100644 index 00000000..076b2d2b --- /dev/null +++ b/packages/pinball_components/sandbox/lib/stories/android_acres/android_spaceship_game.dart @@ -0,0 +1,38 @@ +import 'dart:async'; + +import 'package:flame/input.dart'; +import 'package:pinball_components/pinball_components.dart'; +import 'package:pinball_flame/pinball_flame.dart'; +import 'package:sandbox/stories/ball/basic_ball_game.dart'; + +class AndroidSpaceshipGame extends BallGame { + AndroidSpaceshipGame() + : super( + ballPriority: RenderPriority.ballOnSpaceship, + ballLayer: Layer.spaceship, + imagesFileNames: [ + Assets.images.android.spaceship.saucer.keyName, + Assets.images.android.spaceship.animatronic.keyName, + Assets.images.android.spaceship.lightBeam.keyName, + ], + ); + + static const description = ''' + Shows how the AndroidSpaceship is rendered. + + - Activate the "trace" parameter to overlay the body. + - Tap anywhere on the screen to spawn a Ball into the game. +'''; + + @override + Future onLoad() async { + await super.onLoad(); + + camera.followVector2(Vector2.zero()); + await addFromBlueprint( + AndroidSpaceship(position: Vector2.zero()), + ); + + await traceAllBodies(); + } +} diff --git a/packages/pinball_components/sandbox/lib/stories/android_acres/spaceship_game.dart b/packages/pinball_components/sandbox/lib/stories/android_acres/spaceship_game.dart deleted file mode 100644 index ad897dd4..00000000 --- a/packages/pinball_components/sandbox/lib/stories/android_acres/spaceship_game.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'dart:async'; - -import 'package:flame/input.dart'; -import 'package:flutter/material.dart'; -import 'package:pinball_components/pinball_components.dart'; -import 'package:pinball_flame/pinball_flame.dart'; -import 'package:sandbox/common/common.dart'; - -class SpaceshipGame extends AssetsGame with TapDetector { - static const description = ''' - Shows how a Spaceship works. - - - Tap anywhere on the screen to spawn a Ball into the game. -'''; - - @override - Future onLoad() async { - await super.onLoad(); - - camera.followVector2(Vector2.zero()); - await addFromBlueprint( - Spaceship(position: Vector2.zero()), - ); - await ready(); - } - - @override - void onTapUp(TapUpInfo info) { - add( - Ball(baseColor: Colors.blue) - ..initialPosition = info.eventPosition.game - ..layer = Layer.spaceshipEntranceRamp, - ); - } -} diff --git a/packages/pinball_components/sandbox/lib/stories/android_acres/spaceship_rail_game.dart b/packages/pinball_components/sandbox/lib/stories/android_acres/spaceship_rail_game.dart index 4bd067fa..87bac14d 100644 --- a/packages/pinball_components/sandbox/lib/stories/android_acres/spaceship_rail_game.dart +++ b/packages/pinball_components/sandbox/lib/stories/android_acres/spaceship_rail_game.dart @@ -13,8 +13,8 @@ class SpaceshipRailGame extends BallGame { ballPriority: RenderPriority.ballOnSpaceshipRail, ballLayer: Layer.spaceshipExitRail, imagesFileNames: [ - Assets.images.spaceship.rail.main.keyName, - Assets.images.spaceship.rail.exit.keyName, + Assets.images.android.rail.main.keyName, + Assets.images.android.rail.exit.keyName, ], ); diff --git a/packages/pinball_components/sandbox/lib/stories/android_acres/spaceship_ramp_game.dart b/packages/pinball_components/sandbox/lib/stories/android_acres/spaceship_ramp_game.dart index 1817f40a..43944a37 100644 --- a/packages/pinball_components/sandbox/lib/stories/android_acres/spaceship_ramp_game.dart +++ b/packages/pinball_components/sandbox/lib/stories/android_acres/spaceship_ramp_game.dart @@ -14,16 +14,16 @@ class SpaceshipRampGame extends BallGame with KeyboardEvents { ballPriority: RenderPriority.ballOnSpaceshipRamp, ballLayer: Layer.spaceshipEntranceRamp, imagesFileNames: [ - Assets.images.spaceship.ramp.railingBackground.keyName, - Assets.images.spaceship.ramp.main.keyName, - Assets.images.spaceship.ramp.boardOpening.keyName, - Assets.images.spaceship.ramp.railingForeground.keyName, - Assets.images.spaceship.ramp.arrow.inactive.keyName, - Assets.images.spaceship.ramp.arrow.active1.keyName, - Assets.images.spaceship.ramp.arrow.active2.keyName, - Assets.images.spaceship.ramp.arrow.active3.keyName, - Assets.images.spaceship.ramp.arrow.active4.keyName, - Assets.images.spaceship.ramp.arrow.active5.keyName, + Assets.images.android.ramp.railingBackground.keyName, + Assets.images.android.ramp.main.keyName, + Assets.images.android.ramp.boardOpening.keyName, + Assets.images.android.ramp.railingForeground.keyName, + Assets.images.android.ramp.arrow.inactive.keyName, + Assets.images.android.ramp.arrow.active1.keyName, + Assets.images.android.ramp.arrow.active2.keyName, + Assets.images.android.ramp.arrow.active3.keyName, + Assets.images.android.ramp.arrow.active4.keyName, + Assets.images.android.ramp.arrow.active5.keyName, ], ); diff --git a/packages/pinball_components/sandbox/lib/stories/android_acres/stories.dart b/packages/pinball_components/sandbox/lib/stories/android_acres/stories.dart index d8f84671..ec4a783e 100644 --- a/packages/pinball_components/sandbox/lib/stories/android_acres/stories.dart +++ b/packages/pinball_components/sandbox/lib/stories/android_acres/stories.dart @@ -3,7 +3,7 @@ import 'package:sandbox/common/common.dart'; import 'package:sandbox/stories/android_acres/android_bumper_a_game.dart'; import 'package:sandbox/stories/android_acres/android_bumper_b_game.dart'; import 'package:sandbox/stories/android_acres/android_bumper_cow_game.dart'; -import 'package:sandbox/stories/android_acres/spaceship_game.dart'; +import 'package:sandbox/stories/android_acres/android_spaceship_game.dart'; import 'package:sandbox/stories/android_acres/spaceship_rail_game.dart'; import 'package:sandbox/stories/android_acres/spaceship_ramp_game.dart'; @@ -25,9 +25,9 @@ void addAndroidAcresStories(Dashbook dashbook) { gameBuilder: (_) => AndroidBumperCowGame(), ) ..addGame( - title: 'Spaceship', - description: SpaceshipGame.description, - gameBuilder: (_) => SpaceshipGame(), + title: 'Android Spaceship', + description: AndroidSpaceshipGame.description, + gameBuilder: (_) => AndroidSpaceshipGame(), ) ..addGame( title: 'Spaceship Rail', diff --git a/packages/pinball_components/test/src/components/android_bumper/android_bumper_test.dart b/packages/pinball_components/test/src/components/android_bumper/android_bumper_test.dart index 831330c0..a5256b79 100644 --- a/packages/pinball_components/test/src/components/android_bumper/android_bumper_test.dart +++ b/packages/pinball_components/test/src/components/android_bumper/android_bumper_test.dart @@ -13,12 +13,12 @@ import '../../../helpers/helpers.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); final assets = [ - Assets.images.androidBumper.a.lit.keyName, - Assets.images.androidBumper.a.dimmed.keyName, - Assets.images.androidBumper.b.lit.keyName, - Assets.images.androidBumper.b.dimmed.keyName, - Assets.images.androidBumper.cow.lit.keyName, - Assets.images.androidBumper.cow.dimmed.keyName, + Assets.images.android.bumper.a.lit.keyName, + Assets.images.android.bumper.a.dimmed.keyName, + Assets.images.android.bumper.b.lit.keyName, + Assets.images.android.bumper.b.dimmed.keyName, + Assets.images.android.bumper.cow.lit.keyName, + Assets.images.android.bumper.cow.dimmed.keyName, ]; final flameTester = FlameTester(() => TestGame(assets)); diff --git a/packages/pinball_components/test/src/components/android_spaceship_test.dart b/packages/pinball_components/test/src/components/android_spaceship_test.dart new file mode 100644 index 00000000..92219a64 --- /dev/null +++ b/packages/pinball_components/test/src/components/android_spaceship_test.dart @@ -0,0 +1,66 @@ +// ignore_for_file: cascade_invocations + +import 'package:flame/components.dart'; +import 'package:flame_test/flame_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball_components/pinball_components.dart'; +import 'package:pinball_flame/pinball_flame.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + group('AndroidSpaceship', () { + group('Spaceship', () { + final assets = [ + Assets.images.android.spaceship.saucer.keyName, + Assets.images.android.spaceship.animatronic.keyName, + Assets.images.android.spaceship.lightBeam.keyName, + ]; + final flameTester = FlameTester(() => TestGame(assets)); + + flameTester.test('loads correctly', (game) async { + await game.addFromBlueprint(AndroidSpaceship(position: Vector2.zero())); + await game.ready(); + }); + + flameTester.testGameWidget( + 'renders correctly', + setUp: (game, tester) async { + await game.images.loadAll(assets); + await game + .addFromBlueprint(AndroidSpaceship(position: Vector2.zero())); + game.camera.followVector2(Vector2.zero()); + await game.ready(); + await tester.pump(); + }, + verify: (game, tester) async { + final animationDuration = game + .descendants() + .whereType() + .last + .animation! + .totalDuration(); + + await expectLater( + find.byGame(), + matchesGoldenFile('golden/android_spaceship/start.png'), + ); + + game.update(animationDuration * 0.5); + await tester.pump(); + await expectLater( + find.byGame(), + matchesGoldenFile('golden/android_spaceship/middle.png'), + ); + + game.update(animationDuration * 0.5); + await tester.pump(); + await expectLater( + find.byGame(), + matchesGoldenFile('golden/android_spaceship/end.png'), + ); + }, + ); + }); + }); +} diff --git a/packages/pinball_components/test/src/components/board_background_sprite_component_test.dart b/packages/pinball_components/test/src/components/board_background_sprite_component_test.dart new file mode 100644 index 00000000..df35594f --- /dev/null +++ b/packages/pinball_components/test/src/components/board_background_sprite_component_test.dart @@ -0,0 +1,48 @@ +// ignore_for_file: cascade_invocations + +import 'package:flame/components.dart'; +import 'package:flame_test/flame_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball_components/pinball_components.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + final assets = [ + Assets.images.boardBackground.keyName, + ]; + final flameTester = FlameTester(() => TestGame(assets)); + + group('BoardBackgroundSpriteComponent', () { + flameTester.test( + 'loads correctly', + (game) async { + final boardBackground = BoardBackgroundSpriteComponent(); + await game.ensureAdd(boardBackground); + + expect(game.contains(boardBackground), isTrue); + }, + ); + + flameTester.testGameWidget( + 'renders correctly', + setUp: (game, tester) async { + await game.images.loadAll(assets); + final boardBackground = BoardBackgroundSpriteComponent(); + await game.ensureAdd(boardBackground); + await tester.pump(); + + game.camera + ..followVector2(Vector2.zero()) + ..zoom = 3.7; + }, + verify: (game, tester) async { + await expectLater( + find.byGame(), + matchesGoldenFile('golden/board-background.png'), + ); + }, + ); + }); +} diff --git a/packages/pinball_components/test/src/components/golden/android_spaceship/end.png b/packages/pinball_components/test/src/components/golden/android_spaceship/end.png new file mode 100644 index 00000000..c2a0631a Binary files /dev/null and b/packages/pinball_components/test/src/components/golden/android_spaceship/end.png differ diff --git a/packages/pinball_components/test/src/components/golden/android_spaceship/middle.png b/packages/pinball_components/test/src/components/golden/android_spaceship/middle.png new file mode 100644 index 00000000..c6651abd Binary files /dev/null and b/packages/pinball_components/test/src/components/golden/android_spaceship/middle.png differ diff --git a/packages/pinball_components/test/src/components/golden/android_spaceship/start.png b/packages/pinball_components/test/src/components/golden/android_spaceship/start.png new file mode 100644 index 00000000..25e8863a Binary files /dev/null and b/packages/pinball_components/test/src/components/golden/android_spaceship/start.png differ diff --git a/packages/pinball_components/test/src/components/golden/board-background.png b/packages/pinball_components/test/src/components/golden/board-background.png new file mode 100644 index 00000000..789c5465 Binary files /dev/null and b/packages/pinball_components/test/src/components/golden/board-background.png differ diff --git a/packages/pinball_components/test/src/components/golden/spaceship.png b/packages/pinball_components/test/src/components/golden/spaceship.png deleted file mode 100644 index d43db8c7..00000000 Binary files a/packages/pinball_components/test/src/components/golden/spaceship.png and /dev/null differ diff --git a/packages/pinball_components/test/src/components/spaceship_rail_test.dart b/packages/pinball_components/test/src/components/spaceship_rail_test.dart index bc5a7f75..a24b0a17 100644 --- a/packages/pinball_components/test/src/components/spaceship_rail_test.dart +++ b/packages/pinball_components/test/src/components/spaceship_rail_test.dart @@ -12,8 +12,8 @@ void main() { group('SpaceshipRail', () { TestWidgetsFlutterBinding.ensureInitialized(); final assets = [ - Assets.images.spaceship.rail.main.keyName, - Assets.images.spaceship.rail.exit.keyName, + Assets.images.android.rail.main.keyName, + Assets.images.android.rail.exit.keyName, ]; final flameTester = FlameTester(() => TestGame(assets)); diff --git a/packages/pinball_components/test/src/components/spaceship_ramp_test.dart b/packages/pinball_components/test/src/components/spaceship_ramp_test.dart index a65ba18b..1f5a231a 100644 --- a/packages/pinball_components/test/src/components/spaceship_ramp_test.dart +++ b/packages/pinball_components/test/src/components/spaceship_ramp_test.dart @@ -11,16 +11,16 @@ import '../../helpers/helpers.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); final assets = [ - Assets.images.spaceship.ramp.boardOpening.keyName, - Assets.images.spaceship.ramp.railingForeground.keyName, - Assets.images.spaceship.ramp.railingBackground.keyName, - Assets.images.spaceship.ramp.main.keyName, - Assets.images.spaceship.ramp.arrow.inactive.keyName, - Assets.images.spaceship.ramp.arrow.active1.keyName, - Assets.images.spaceship.ramp.arrow.active2.keyName, - Assets.images.spaceship.ramp.arrow.active3.keyName, - Assets.images.spaceship.ramp.arrow.active4.keyName, - Assets.images.spaceship.ramp.arrow.active5.keyName, + Assets.images.android.ramp.boardOpening.keyName, + Assets.images.android.ramp.railingForeground.keyName, + Assets.images.android.ramp.railingBackground.keyName, + Assets.images.android.ramp.main.keyName, + Assets.images.android.ramp.arrow.inactive.keyName, + Assets.images.android.ramp.arrow.active1.keyName, + Assets.images.android.ramp.arrow.active2.keyName, + Assets.images.android.ramp.arrow.active3.keyName, + Assets.images.android.ramp.arrow.active4.keyName, + Assets.images.android.ramp.arrow.active5.keyName, ]; final flameTester = FlameTester(() => TestGame(assets)); diff --git a/packages/pinball_components/test/src/components/spaceship_test.dart b/packages/pinball_components/test/src/components/spaceship_test.dart deleted file mode 100644 index c9a90746..00000000 --- a/packages/pinball_components/test/src/components/spaceship_test.dart +++ /dev/null @@ -1,56 +0,0 @@ -// ignore_for_file: cascade_invocations - -import 'package:flame_forge2d/flame_forge2d.dart'; -import 'package:flame_test/flame_test.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mocktail/mocktail.dart'; -import 'package:pinball_components/pinball_components.dart'; -import 'package:pinball_flame/pinball_flame.dart'; - -import '../../helpers/helpers.dart'; - -void main() { - group('Spaceship', () { - late Filter filterData; - late Fixture fixture; - late Body body; - late Ball ball; - late Forge2DGame game; - - setUp(() { - filterData = MockFilter(); - - fixture = MockFixture(); - when(() => fixture.filterData).thenReturn(filterData); - - body = MockBody(); - when(() => body.fixtures).thenReturn([fixture]); - - game = MockGame(); - - ball = MockBall(); - when(() => ball.gameRef).thenReturn(game); - when(() => ball.body).thenReturn(body); - }); - - group('Spaceship', () { - final tester = FlameTester(TestGame.new); - - tester.testGameWidget( - 'renders correctly', - setUp: (game, tester) async { - final position = Vector2(30, -30); - await game.addFromBlueprint(Spaceship(position: position)); - game.camera.followVector2(position); - await game.ready(); - }, - verify: (game, tester) async { - await expectLater( - find.byGame(), - matchesGoldenFile('golden/spaceship.png'), - ); - }, - ); - }); - }); -} diff --git a/packages/pinball_flame/lib/src/contact_behavior.dart b/packages/pinball_flame/lib/src/contact_behavior.dart index 79112398..ff715b12 100644 --- a/packages/pinball_flame/lib/src/contact_behavior.dart +++ b/packages/pinball_flame/lib/src/contact_behavior.dart @@ -1,95 +1,105 @@ import 'package:flame/components.dart'; import 'package:flame_forge2d/flame_forge2d.dart'; -import 'package:flutter/material.dart'; import 'package:pinball_flame/pinball_flame.dart'; /// Appends a new [ContactCallbacks] to the parent. /// /// This is a convenience class for adding a [ContactCallbacks] to the parent. -/// In constract with just adding a [ContactCallbacks] to the parent's body -/// userData, this class respects the previous [ContactCallbacks] in the -/// parent's body userData, if any. Hence, it avoids overriding any previous -/// [ContactCallbacks] in the parent. +/// In contrast with just assigning a [ContactCallbacks] to a userData, this +/// class respects the previous userData. /// -/// It does so by grouping the [ContactCallbacks] in a [_ContactCallbacksGroup], -/// and resetting the parent's userData accordingly. +/// It does so by grouping the userData in a [_UserData], and resetting the +/// parent's userData accordingly. // TODO(alestiago): Make use of generics to infer the type of the contact. // https://github.com/VGVentures/pinball/pull/234#discussion_r859182267 -// TODO(alestiago): Consider if there is a need to support adjusting a fixture's -// userData. class ContactBehavior extends Component with ContactCallbacks, ParentIsA { + final _fixturesUserData = {}; + + /// Specifies which fixtures should be considered for contact. + /// + /// Fixtures are identifiable by their userData. + /// + /// If no fixtures are specified, the [ContactCallbacks] is applied to the + /// entire body, hence all fixtures are considered. + void applyTo(Iterable userData) => _fixturesUserData.addAll(userData); + @override - @mustCallSuper Future onLoad() async { - final userData = parent.body.userData; - if (userData is _ContactCallbacksGroup) { - userData.addContactCallbacks(this); - } else if (userData is ContactCallbacks) { - final contactCallbacksGroup = _ContactCallbacksGroup() - ..addContactCallbacks(userData) - ..addContactCallbacks(this); - parent.body.userData = contactCallbacksGroup; + if (_fixturesUserData.isNotEmpty) { + for (final fixture in _targetedFixtures) { + fixture.userData = _UserData.fromFixture(fixture)..add(this); + } } else { - parent.body.userData = this; + parent.body.userData = _UserData.fromBody(parent.body)..add(this); } } + + Iterable get _targetedFixtures => + parent.body.fixtures.where((fixture) { + if (_fixturesUserData.contains(fixture.userData)) return true; + + final userData = fixture.userData; + if (userData is _UserData) { + return _fixturesUserData.contains(userData.value); + } + + return false; + }); } -class _ContactCallbacksGroup implements ContactCallbacks { - final List _contactCallbacks = []; +class _UserData with ContactCallbacks { + _UserData._(Object? userData) : _userData = [userData]; + + factory _UserData._fromUserData(Object? userData) { + if (userData is _UserData) return userData; + return _UserData._(userData); + } + + factory _UserData.fromFixture(Fixture fixture) => + _UserData._fromUserData(fixture.userData); + + factory _UserData.fromBody(Body body) => + _UserData._fromUserData(body.userData); + + final List _userData; + + Iterable get _contactCallbacks => + _userData.whereType(); + + Object? get value => _userData.first; + + void add(Object? userData) => _userData.add(userData); @override - @mustCallSuper void beginContact(Object other, Contact contact) { - onBeginContact?.call(other, contact); + super.beginContact(other, contact); for (final callback in _contactCallbacks) { callback.beginContact(other, contact); } } @override - @mustCallSuper void endContact(Object other, Contact contact) { - onEndContact?.call(other, contact); + super.endContact(other, contact); for (final callback in _contactCallbacks) { callback.endContact(other, contact); } } @override - @mustCallSuper void preSolve(Object other, Contact contact, Manifold oldManifold) { - onPreSolve?.call(other, contact, oldManifold); + super.preSolve(other, contact, oldManifold); for (final callback in _contactCallbacks) { callback.preSolve(other, contact, oldManifold); } } @override - @mustCallSuper void postSolve(Object other, Contact contact, ContactImpulse impulse) { - onPostSolve?.call(other, contact, impulse); + super.postSolve(other, contact, impulse); for (final callback in _contactCallbacks) { callback.postSolve(other, contact, impulse); } } - - void addContactCallbacks(ContactCallbacks callback) { - _contactCallbacks.add(callback); - } - - @override - void Function(Object other, Contact contact)? onBeginContact; - - @override - void Function(Object other, Contact contact)? onEndContact; - - @override - void Function(Object other, Contact contact, ContactImpulse impulse)? - onPostSolve; - - @override - void Function(Object other, Contact contact, Manifold oldManifold)? - onPreSolve; } diff --git a/packages/pinball_flame/test/src/contact_behavior_test.dart b/packages/pinball_flame/test/src/contact_behavior_test.dart index 630156ed..cf7fe35a 100644 --- a/packages/pinball_flame/test/src/contact_behavior_test.dart +++ b/packages/pinball_flame/test/src/contact_behavior_test.dart @@ -58,28 +58,78 @@ void main() { late Contact contact; late Manifold manifold; late ContactImpulse contactImpulse; + late FixtureDef fixtureDef; setUp(() { other = Object(); contact = _MockContact(); manifold = _MockManifold(); contactImpulse = _MockContactImpulse(); + fixtureDef = FixtureDef(CircleShape()); }); flameTester.test( - 'should add a new ContactCallbacks to the parent', + "should add a new ContactCallbacks to the parent's body userData " + 'when not applied to fixtures', (game) async { final parent = _TestBodyComponent(); final contactBehavior = ContactBehavior(); await parent.add(contactBehavior); await game.ensureAdd(parent); - expect(parent.body.userData, contactBehavior); + expect(parent.body.userData, isA()); }, ); flameTester.test( - "should respect the previous ContactCallbacks in the parent's userData", + 'should add a new ContactCallbacks to the targeted fixture ', + (game) async { + final parent = _TestBodyComponent(); + + await game.ensureAdd(parent); + final fixture1 = + parent.body.createFixture(fixtureDef..userData = 'foo'); + final fixture2 = parent.body.createFixture(fixtureDef..userData = null); + final contactBehavior = ContactBehavior() + ..applyTo( + [fixture1.userData!], + ); + + await parent.ensureAdd(contactBehavior); + + expect(parent.body.userData, isNull); + expect(fixture1.userData, isA()); + expect(fixture2.userData, isNull); + }, + ); + + flameTester.test( + 'should add a new ContactCallbacks to the targeted fixtures ', + (game) async { + final parent = _TestBodyComponent(); + + await game.ensureAdd(parent); + final fixture1 = + parent.body.createFixture(fixtureDef..userData = 'foo'); + final fixture2 = + parent.body.createFixture(fixtureDef..userData = 'boo'); + final contactBehavior = ContactBehavior() + ..applyTo([ + fixture1.userData!, + fixture2.userData!, + ]); + + await parent.ensureAdd(contactBehavior); + + expect(parent.body.userData, isNull); + expect(fixture1.userData, isA()); + expect(fixture2.userData, isA()); + }, + ); + + flameTester.test( + "should respect the previous ContactCallbacks in the parent's userData " + 'when not applied to fixtures', (game) async { final parent = _TestBodyComponent(); await game.ensureAdd(parent); @@ -113,41 +163,94 @@ void main() { }, ); - flameTester.test('can group multiple ContactBehaviors and keep listening', - (game) async { - final parent = _TestBodyComponent(); - await game.ensureAdd(parent); - - final contactBehavior1 = _TestContactBehavior(); - final contactBehavior2 = _TestContactBehavior(); - final contactBehavior3 = _TestContactBehavior(); - await parent.ensureAddAll([ - contactBehavior1, - contactBehavior2, - contactBehavior3, - ]); - - final contactCallbacks = parent.body.userData! as ContactCallbacks; - - contactCallbacks.beginContact(other, contact); - expect(contactBehavior1.beginContactCallsCount, equals(1)); - expect(contactBehavior2.beginContactCallsCount, equals(1)); - expect(contactBehavior3.beginContactCallsCount, equals(1)); - - contactCallbacks.endContact(other, contact); - expect(contactBehavior1.endContactCallsCount, equals(1)); - expect(contactBehavior2.endContactCallsCount, equals(1)); - expect(contactBehavior3.endContactCallsCount, equals(1)); - - contactCallbacks.preSolve(other, contact, manifold); - expect(contactBehavior1.preSolveContactCallsCount, equals(1)); - expect(contactBehavior2.preSolveContactCallsCount, equals(1)); - expect(contactBehavior3.preSolveContactCallsCount, equals(1)); - - contactCallbacks.postSolve(other, contact, contactImpulse); - expect(contactBehavior1.postSolveContactCallsCount, equals(1)); - expect(contactBehavior2.postSolveContactCallsCount, equals(1)); - expect(contactBehavior3.postSolveContactCallsCount, equals(1)); - }); + flameTester.test( + 'can group multiple ContactBehaviors and keep listening', + (game) async { + final parent = _TestBodyComponent(); + await game.ensureAdd(parent); + + final contactBehavior1 = _TestContactBehavior(); + final contactBehavior2 = _TestContactBehavior(); + final contactBehavior3 = _TestContactBehavior(); + await parent.ensureAddAll([ + contactBehavior1, + contactBehavior2, + contactBehavior3, + ]); + + final contactCallbacks = parent.body.userData! as ContactCallbacks; + + contactCallbacks.beginContact(other, contact); + expect(contactBehavior1.beginContactCallsCount, equals(1)); + expect(contactBehavior2.beginContactCallsCount, equals(1)); + expect(contactBehavior3.beginContactCallsCount, equals(1)); + + contactCallbacks.endContact(other, contact); + expect(contactBehavior1.endContactCallsCount, equals(1)); + expect(contactBehavior2.endContactCallsCount, equals(1)); + expect(contactBehavior3.endContactCallsCount, equals(1)); + + contactCallbacks.preSolve(other, contact, manifold); + expect(contactBehavior1.preSolveContactCallsCount, equals(1)); + expect(contactBehavior2.preSolveContactCallsCount, equals(1)); + expect(contactBehavior3.preSolveContactCallsCount, equals(1)); + + contactCallbacks.postSolve(other, contact, contactImpulse); + expect(contactBehavior1.postSolveContactCallsCount, equals(1)); + expect(contactBehavior2.postSolveContactCallsCount, equals(1)); + expect(contactBehavior3.postSolveContactCallsCount, equals(1)); + }, + ); + + flameTester.test( + 'can group multiple ContactBehaviors and keep listening ' + 'when applied to a fixture', + (game) async { + final parent = _TestBodyComponent(); + await game.ensureAdd(parent); + + final fixture = parent.body.createFixture(fixtureDef..userData = 'foo'); + + final contactBehavior1 = _TestContactBehavior() + ..applyTo( + [fixture.userData!], + ); + final contactBehavior2 = _TestContactBehavior() + ..applyTo( + [fixture.userData!], + ); + final contactBehavior3 = _TestContactBehavior() + ..applyTo( + [fixture.userData!], + ); + await parent.ensureAddAll([ + contactBehavior1, + contactBehavior2, + contactBehavior3, + ]); + + final contactCallbacks = fixture.userData! as ContactCallbacks; + + contactCallbacks.beginContact(other, contact); + expect(contactBehavior1.beginContactCallsCount, equals(1)); + expect(contactBehavior2.beginContactCallsCount, equals(1)); + expect(contactBehavior3.beginContactCallsCount, equals(1)); + + contactCallbacks.endContact(other, contact); + expect(contactBehavior1.endContactCallsCount, equals(1)); + expect(contactBehavior2.endContactCallsCount, equals(1)); + expect(contactBehavior3.endContactCallsCount, equals(1)); + + contactCallbacks.preSolve(other, contact, manifold); + expect(contactBehavior1.preSolveContactCallsCount, equals(1)); + expect(contactBehavior2.preSolveContactCallsCount, equals(1)); + expect(contactBehavior3.preSolveContactCallsCount, equals(1)); + + contactCallbacks.postSolve(other, contact, contactImpulse); + expect(contactBehavior1.postSolveContactCallsCount, equals(1)); + expect(contactBehavior2.postSolveContactCallsCount, equals(1)); + expect(contactBehavior3.postSolveContactCallsCount, equals(1)); + }, + ); }); } diff --git a/packages/pinball_ui/fonts/PixeloidMono-1G8ae.ttf b/packages/pinball_ui/fonts/PixeloidMono-1G8ae.ttf new file mode 100644 index 00000000..a797c1e1 Binary files /dev/null and b/packages/pinball_ui/fonts/PixeloidMono-1G8ae.ttf differ diff --git a/packages/pinball_ui/fonts/PixeloidSans-nR3g1.ttf b/packages/pinball_ui/fonts/PixeloidSans-nR3g1.ttf new file mode 100644 index 00000000..2f9a03b4 Binary files /dev/null and b/packages/pinball_ui/fonts/PixeloidSans-nR3g1.ttf differ diff --git a/packages/pinball_ui/fonts/PixeloidSansBold-RpeJo.ttf b/packages/pinball_ui/fonts/PixeloidSansBold-RpeJo.ttf new file mode 100644 index 00000000..81194f5d Binary files /dev/null and b/packages/pinball_ui/fonts/PixeloidSansBold-RpeJo.ttf differ diff --git a/packages/pinball_ui/lib/gen/fonts.gen.dart b/packages/pinball_ui/lib/gen/fonts.gen.dart new file mode 100644 index 00000000..5f77da16 --- /dev/null +++ b/packages/pinball_ui/lib/gen/fonts.gen.dart @@ -0,0 +1,16 @@ +/// GENERATED CODE - DO NOT MODIFY BY HAND +/// ***************************************************** +/// FlutterGen +/// ***************************************************** + +// ignore_for_file: directives_ordering,unnecessary_import + +class FontFamily { + FontFamily._(); + + /// Font family: PixeloidMono + static const String pixeloidMono = 'PixeloidMono'; + + /// Font family: PixeloidSans + static const String pixeloidSans = 'PixeloidSans'; +} diff --git a/packages/pinball_ui/lib/pinball_ui.dart b/packages/pinball_ui/lib/pinball_ui.dart index b46adf95..332286ed 100644 --- a/packages/pinball_ui/lib/pinball_ui.dart +++ b/packages/pinball_ui/lib/pinball_ui.dart @@ -1,3 +1,8 @@ library pinball_ui; +export 'package:url_launcher/url_launcher.dart'; +export 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; + export 'src/dialog/dialog.dart'; +export 'src/external_links/external_links.dart'; +export 'src/theme/theme.dart'; diff --git a/packages/pinball_ui/lib/src/external_links/external_links.dart b/packages/pinball_ui/lib/src/external_links/external_links.dart new file mode 100644 index 00000000..8e4792ea --- /dev/null +++ b/packages/pinball_ui/lib/src/external_links/external_links.dart @@ -0,0 +1,12 @@ +import 'package:flutter/foundation.dart'; +import 'package:url_launcher/url_launcher.dart'; + +/// Opens the given [url] in a new tab of the host browser +Future openLink(String url, {VoidCallback? onError}) async { + final uri = Uri.parse(url); + if (await canLaunchUrl(uri)) { + await launchUrl(uri); + } else if (onError != null) { + onError(); + } +} diff --git a/lib/theme/app_colors.dart b/packages/pinball_ui/lib/src/theme/pinball_colors.dart similarity index 92% rename from lib/theme/app_colors.dart rename to packages/pinball_ui/lib/src/theme/pinball_colors.dart index a12d3edc..5db27229 100644 --- a/lib/theme/app_colors.dart +++ b/packages/pinball_ui/lib/src/theme/pinball_colors.dart @@ -1,17 +1,11 @@ // ignore_for_file: public_member_api_docs - import 'package:flutter/material.dart'; -abstract class AppColors { +abstract class PinballColors { static const Color white = Color(0xFFFFFFFF); - static const Color darkBlue = Color(0xFF0C32A4); - static const Color yellow = Color(0xFFFFEE02); - static const Color orange = Color(0xFFE5AB05); - static const Color blue = Color(0xFF4B94F6); - static const Color transparent = Color(0x00000000); } diff --git a/lib/theme/app_text_style.dart b/packages/pinball_ui/lib/src/theme/pinball_text_style.dart similarity index 64% rename from lib/theme/app_text_style.dart rename to packages/pinball_ui/lib/src/theme/pinball_text_style.dart index 084936e9..378078fa 100644 --- a/lib/theme/app_text_style.dart +++ b/packages/pinball_ui/lib/src/theme/pinball_text_style.dart @@ -1,17 +1,18 @@ // ignore_for_file: public_member_api_docs import 'package:flutter/widgets.dart'; -import 'package:pinball/theme/theme.dart'; -import 'package:pinball_components/pinball_components.dart'; +import 'package:pinball_ui/gen/fonts.gen.dart'; +import 'package:pinball_ui/pinball_ui.dart'; const _fontPackage = 'pinball_components'; const _primaryFontFamily = FontFamily.pixeloidSans; -abstract class AppTextStyle { +abstract class PinballTextStyle { static const headline1 = TextStyle( fontSize: 28, package: _fontPackage, fontFamily: _primaryFontFamily, + color: PinballColors.white, ); static const headline2 = TextStyle( @@ -21,36 +22,22 @@ abstract class AppTextStyle { ); static const headline3 = TextStyle( - color: AppColors.white, + color: PinballColors.white, fontSize: 20, package: _fontPackage, fontFamily: _primaryFontFamily, + fontWeight: FontWeight.bold, ); static const headline4 = TextStyle( - color: AppColors.white, + color: PinballColors.white, fontSize: 16, package: _fontPackage, fontFamily: _primaryFontFamily, ); - static const title = TextStyle( - color: AppColors.darkBlue, - fontSize: 20, - package: _fontPackage, - fontFamily: _primaryFontFamily, - ); - - static const subtitle3 = TextStyle( - color: AppColors.white, - fontSize: 20, - fontWeight: FontWeight.bold, - package: _fontPackage, - fontFamily: _primaryFontFamily, - ); - static const subtitle2 = TextStyle( - color: AppColors.white, + color: PinballColors.white, fontSize: 16, package: _fontPackage, fontFamily: _primaryFontFamily, @@ -60,5 +47,6 @@ abstract class AppTextStyle { fontSize: 10, fontFamily: _primaryFontFamily, package: _fontPackage, + color: PinballColors.yellow, ); } diff --git a/packages/pinball_ui/lib/src/theme/pinball_theme.dart b/packages/pinball_ui/lib/src/theme/pinball_theme.dart new file mode 100644 index 00000000..cf62b2ef --- /dev/null +++ b/packages/pinball_ui/lib/src/theme/pinball_theme.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:pinball_ui/pinball_ui.dart'; + +/// Pinball theme +class PinballTheme { + /// Standard [ThemeData] for Pinball UI + static ThemeData get standard { + return ThemeData( + textTheme: _textTheme, + ); + } + + static TextTheme get _textTheme { + return const TextTheme( + headline1: PinballTextStyle.headline1, + headline2: PinballTextStyle.headline2, + headline3: PinballTextStyle.headline3, + headline4: PinballTextStyle.headline4, + subtitle1: PinballTextStyle.subtitle1, + subtitle2: PinballTextStyle.subtitle2, + ); + } +} diff --git a/packages/pinball_ui/lib/src/theme/theme.dart b/packages/pinball_ui/lib/src/theme/theme.dart new file mode 100644 index 00000000..71c78942 --- /dev/null +++ b/packages/pinball_ui/lib/src/theme/theme.dart @@ -0,0 +1,3 @@ +export 'pinball_colors.dart'; +export 'pinball_text_style.dart'; +export 'pinball_theme.dart'; diff --git a/packages/pinball_ui/pubspec.yaml b/packages/pinball_ui/pubspec.yaml index 79c65338..a89f7a67 100644 --- a/packages/pinball_ui/pubspec.yaml +++ b/packages/pinball_ui/pubspec.yaml @@ -9,19 +9,29 @@ environment: dependencies: flutter: sdk: flutter + url_launcher: ^6.1.0 dev_dependencies: flutter_test: sdk: flutter + mocktail: ^0.3.0 test: ^1.19.2 very_good_analysis: ^2.4.0 flutter: uses-material-design: true generate: true - assets: - assets/images/dialog/ + fonts: + - family: PixeloidSans + fonts: + - asset: fonts/PixeloidSans-nR3g1.ttf + - asset: fonts/PixeloidSansBold-RpeJo.ttf + weight: 700 + - family: PixeloidMono + fonts: + - asset: fonts/PixeloidMono-1G8ae.ttf flutter_gen: line_length: 80 diff --git a/packages/pinball_ui/test/src/external_links/external_links_test.dart b/packages/pinball_ui/test/src/external_links/external_links_test.dart new file mode 100644 index 00000000..83cc2d63 --- /dev/null +++ b/packages/pinball_ui/test/src/external_links/external_links_test.dart @@ -0,0 +1,81 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:pinball_ui/pinball_ui.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +class MockUrlLauncher extends Mock + with MockPlatformInterfaceMixin + implements UrlLauncherPlatform {} + +void main() { + late UrlLauncherPlatform urlLauncher; + + setUp(() { + urlLauncher = MockUrlLauncher(); + UrlLauncherPlatform.instance = urlLauncher; + }); + + group('openLink', () { + test('launches the link', () async { + when( + () => urlLauncher.canLaunch(any()), + ).thenAnswer( + (_) async => true, + ); + when( + () => urlLauncher.launch( + any(), + useSafariVC: any(named: 'useSafariVC'), + useWebView: any(named: 'useWebView'), + enableJavaScript: any(named: 'enableJavaScript'), + enableDomStorage: any(named: 'enableDomStorage'), + universalLinksOnly: any(named: 'universalLinksOnly'), + headers: any(named: 'headers'), + ), + ).thenAnswer( + (_) async => true, + ); + await openLink('uri'); + verify( + () => urlLauncher.launch( + any(), + useSafariVC: any(named: 'useSafariVC'), + useWebView: any(named: 'useWebView'), + enableJavaScript: any(named: 'enableJavaScript'), + enableDomStorage: any(named: 'enableDomStorage'), + universalLinksOnly: any(named: 'universalLinksOnly'), + headers: any(named: 'headers'), + ), + ); + }); + + test('executes the onError callback when it cannot launch', () async { + var wasCalled = false; + when( + () => urlLauncher.canLaunch(any()), + ).thenAnswer( + (_) async => false, + ); + when( + () => urlLauncher.launch( + any(), + useSafariVC: any(named: 'useSafariVC'), + useWebView: any(named: 'useWebView'), + enableJavaScript: any(named: 'enableJavaScript'), + enableDomStorage: any(named: 'enableDomStorage'), + universalLinksOnly: any(named: 'universalLinksOnly'), + headers: any(named: 'headers'), + ), + ).thenAnswer( + (_) async => true, + ); + await openLink( + 'url', + onError: () { + wasCalled = true; + }, + ); + await expectLater(wasCalled, isTrue); + }); + }); +} diff --git a/packages/pinball_ui/test/src/theme/pinball_colors_test.dart b/packages/pinball_ui/test/src/theme/pinball_colors_test.dart new file mode 100644 index 00000000..36e45c0d --- /dev/null +++ b/packages/pinball_ui/test/src/theme/pinball_colors_test.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball_ui/pinball_ui.dart'; + +void main() { + group('PinballColors', () { + test('white is 0xFFFFFFFF', () { + expect(PinballColors.white, const Color(0xFFFFFFFF)); + }); + + test('darkBlue is 0xFF0C32A4', () { + expect(PinballColors.darkBlue, const Color(0xFF0C32A4)); + }); + + test('yellow is 0xFFFFEE02', () { + expect(PinballColors.yellow, const Color(0xFFFFEE02)); + }); + + test('orange is 0xFFE5AB05', () { + expect(PinballColors.orange, const Color(0xFFE5AB05)); + }); + + test('blue is 0xFF4B94F6', () { + expect(PinballColors.blue, const Color(0xFF4B94F6)); + }); + + test('transparent is 0x00000000', () { + expect(PinballColors.transparent, const Color(0x00000000)); + }); + }); +} diff --git a/packages/pinball_ui/test/src/theme/pinball_text_style_test.dart b/packages/pinball_ui/test/src/theme/pinball_text_style_test.dart new file mode 100644 index 00000000..60b382f3 --- /dev/null +++ b/packages/pinball_ui/test/src/theme/pinball_text_style_test.dart @@ -0,0 +1,41 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball_ui/pinball_ui.dart'; + +void main() { + group('PinballTextStyle', () { + test('headline1 has fontSize 28 and white color', () { + const style = PinballTextStyle.headline1; + expect(style.fontSize, 28); + expect(style.color, PinballColors.white); + }); + + test('headline2 has fontSize 24', () { + const style = PinballTextStyle.headline2; + expect(style.fontSize, 24); + }); + + test('headline3 has fontSize 20 and white color', () { + const style = PinballTextStyle.headline3; + expect(style.fontSize, 20); + expect(style.color, PinballColors.white); + }); + + test('headline4 has fontSize 16 and white color', () { + const style = PinballTextStyle.headline4; + expect(style.fontSize, 16); + expect(style.color, PinballColors.white); + }); + + test('subtitle1 has fontSize 10 and yellow color', () { + const style = PinballTextStyle.subtitle1; + expect(style.fontSize, 10); + expect(style.color, PinballColors.yellow); + }); + + test('subtitle2 has fontSize 16 and white color', () { + const style = PinballTextStyle.subtitle2; + expect(style.fontSize, 16); + expect(style.color, PinballColors.white); + }); + }); +} diff --git a/packages/pinball_ui/test/src/theme/pinball_theme_test.dart b/packages/pinball_ui/test/src/theme/pinball_theme_test.dart new file mode 100644 index 00000000..915927f8 --- /dev/null +++ b/packages/pinball_ui/test/src/theme/pinball_theme_test.dart @@ -0,0 +1,98 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball_ui/pinball_ui.dart'; + +void main() { + group('PinballTheme', () { + group('standard', () { + test('headline1 matches PinballTextStyle#headline1', () { + expect( + PinballTheme.standard.textTheme.headline1!.fontSize, + PinballTextStyle.headline1.fontSize, + ); + expect( + PinballTheme.standard.textTheme.headline1!.color, + PinballTextStyle.headline1.color, + ); + expect( + PinballTheme.standard.textTheme.headline1!.fontFamily, + PinballTextStyle.headline1.fontFamily, + ); + }); + + test('headline2 matches PinballTextStyle#headline2', () { + expect( + PinballTheme.standard.textTheme.headline2!.fontSize, + PinballTextStyle.headline2.fontSize, + ); + expect( + PinballTheme.standard.textTheme.headline2!.fontFamily, + PinballTextStyle.headline2.fontFamily, + ); + expect( + PinballTheme.standard.textTheme.headline2!.fontWeight, + PinballTextStyle.headline2.fontWeight, + ); + }); + + test('headline3 matches PinballTextStyle#headline3', () { + expect( + PinballTheme.standard.textTheme.headline3!.fontSize, + PinballTextStyle.headline3.fontSize, + ); + expect( + PinballTheme.standard.textTheme.headline3!.color, + PinballTextStyle.headline3.color, + ); + expect( + PinballTheme.standard.textTheme.headline3!.fontFamily, + PinballTextStyle.headline3.fontFamily, + ); + }); + + test('headline4 matches PinballTextStyle#headline4', () { + expect( + PinballTheme.standard.textTheme.headline4!.fontSize, + PinballTextStyle.headline4.fontSize, + ); + expect( + PinballTheme.standard.textTheme.headline4!.color, + PinballTextStyle.headline4.color, + ); + expect( + PinballTheme.standard.textTheme.headline4!.fontFamily, + PinballTextStyle.headline4.fontFamily, + ); + }); + + test('subtitle1 matches PinballTextStyle#subtitle1', () { + expect( + PinballTheme.standard.textTheme.subtitle1!.fontSize, + PinballTextStyle.subtitle1.fontSize, + ); + expect( + PinballTheme.standard.textTheme.subtitle1!.color, + PinballTextStyle.subtitle1.color, + ); + expect( + PinballTheme.standard.textTheme.subtitle1!.fontFamily, + PinballTextStyle.subtitle1.fontFamily, + ); + }); + + test('subtitle2 matches PinballTextStyle#subtitle2', () { + expect( + PinballTheme.standard.textTheme.subtitle2!.fontSize, + PinballTextStyle.subtitle2.fontSize, + ); + expect( + PinballTheme.standard.textTheme.subtitle2!.color, + PinballTextStyle.subtitle2.color, + ); + expect( + PinballTheme.standard.textTheme.subtitle2!.fontFamily, + PinballTextStyle.subtitle2.fontFamily, + ); + }); + }); + }); +} diff --git a/pubspec.lock b/pubspec.lock index ab39378a..db5233c3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -36,6 +36,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.20.1" + authentication_repository: + dependency: "direct main" + description: + path: "packages/authentication_repository" + relative: true + source: path + version: "1.0.0+1" bloc: dependency: "direct main" description: @@ -169,13 +176,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.2" - firebase_core: + firebase_auth: + dependency: "direct main" + description: + name: firebase_auth + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.16" + firebase_auth_platform_interface: dependency: transitive + description: + name: firebase_auth_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "6.2.4" + firebase_auth_web: + dependency: transitive + description: + name: firebase_auth_web + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.13" + firebase_core: + dependency: "direct main" description: name: firebase_core url: "https://pub.dartlang.org" source: hosted - version: "1.13.1" + version: "1.15.0" firebase_core_platform_interface: dependency: transitive description: @@ -189,7 +217,7 @@ packages: name: firebase_core_web url: "https://pub.dartlang.org" source: hosted - version: "1.6.1" + version: "1.6.2" flame: dependency: "direct main" description: @@ -672,6 +700,62 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" + url_launcher: + dependency: transitive + description: + name: url_launcher + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.0" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.16" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.15" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.5" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.9" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" uuid: dependency: transitive description: @@ -744,4 +828,4 @@ packages: version: "3.1.0" sdks: dart: ">=2.16.0 <3.0.0" - flutter: ">=2.8.0" + flutter: ">=2.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index 51c85cd5..fa08f453 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,9 +7,13 @@ environment: sdk: ">=2.16.0 <3.0.0" dependencies: + authentication_repository: + path: packages/authentication_repository bloc: ^8.0.2 cloud_firestore: ^3.1.10 equatable: ^2.0.3 + firebase_auth: ^3.3.16 + firebase_core: ^1.15.0 flame: ^1.1.1 flame_bloc: ^1.2.0 flame_forge2d: diff --git a/test/app/view/app_test.dart b/test/app/view/app_test.dart index 9fc79b5d..83e37499 100644 --- a/test/app/view/app_test.dart +++ b/test/app/view/app_test.dart @@ -5,6 +5,7 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. +import 'package:authentication_repository/authentication_repository.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:leaderboard_repository/leaderboard_repository.dart'; import 'package:mocktail/mocktail.dart'; @@ -16,19 +17,21 @@ import '../../helpers/mocks.dart'; void main() { group('App', () { + late AuthenticationRepository authenticationRepository; late LeaderboardRepository leaderboardRepository; late PinballAudio pinballAudio; setUp(() { + authenticationRepository = MockAuthenticationRepository(); leaderboardRepository = MockLeaderboardRepository(); pinballAudio = MockPinballAudio(); - when(pinballAudio.load).thenAnswer((_) => Future.value()); }); testWidgets('renders PinballGamePage', (tester) async { await tester.pumpWidget( App( + authenticationRepository: authenticationRepository, leaderboardRepository: leaderboardRepository, pinballAudio: pinballAudio, ), diff --git a/test/footer/footer_test.dart b/test/footer/footer_test.dart new file mode 100644 index 00000000..c18d76e7 --- /dev/null +++ b/test/footer/footer_test.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:pinball/footer/footer.dart'; +import 'package:pinball_ui/pinball_ui.dart'; + +import '../helpers/helpers.dart'; + +void main() { + group('Footer', () { + late UrlLauncherPlatform urlLauncher; + + setUp(() async { + urlLauncher = MockUrlLauncher(); + UrlLauncherPlatform.instance = urlLauncher; + }); + testWidgets('renders "Made with..." and "Google I/O"', (tester) async { + await tester.pumpApp(const Footer()); + expect(find.text('Google I/O'), findsOneWidget); + expect( + find.byWidgetPredicate( + (widget) => + widget is RichText && + widget.text.toPlainText() == 'Made with Flutter & Firebase', + ), + findsOneWidget, + ); + }); + + testWidgets( + 'tapping on "Flutter" opens the flutter website', + (tester) async { + when(() => urlLauncher.canLaunch(any())).thenAnswer((_) async => true); + when( + () => urlLauncher.launch( + any(), + useSafariVC: any(named: 'useSafariVC'), + useWebView: any(named: 'useWebView'), + enableJavaScript: any(named: 'enableJavaScript'), + enableDomStorage: any(named: 'enableDomStorage'), + universalLinksOnly: any(named: 'universalLinksOnly'), + headers: any(named: 'headers'), + ), + ).thenAnswer((_) async => true); + await tester.pumpApp(const Footer()); + final flutterTextFinder = find.byWidgetPredicate( + (widget) => widget is RichText && tapTextSpan(widget, 'Flutter'), + ); + await tester.tap(flutterTextFinder); + await tester.pumpAndSettle(); + verify( + () => urlLauncher.launch( + 'https://flutter.dev', + useSafariVC: any(named: 'useSafariVC'), + useWebView: any(named: 'useWebView'), + enableJavaScript: any(named: 'enableJavaScript'), + enableDomStorage: any(named: 'enableDomStorage'), + universalLinksOnly: any(named: 'universalLinksOnly'), + headers: any(named: 'headers'), + ), + ); + }, + ); + + testWidgets( + 'tapping on "Firebase" opens the firebase website', + (tester) async { + when(() => urlLauncher.canLaunch(any())).thenAnswer((_) async => true); + when( + () => urlLauncher.launch( + any(), + useSafariVC: any(named: 'useSafariVC'), + useWebView: any(named: 'useWebView'), + enableJavaScript: any(named: 'enableJavaScript'), + enableDomStorage: any(named: 'enableDomStorage'), + universalLinksOnly: any(named: 'universalLinksOnly'), + headers: any(named: 'headers'), + ), + ).thenAnswer((_) async => true); + await tester.pumpApp(const Footer()); + final firebaseTextFinder = find.byWidgetPredicate( + (widget) => widget is RichText && tapTextSpan(widget, 'Firebase'), + ); + await tester.tap(firebaseTextFinder); + await tester.pumpAndSettle(); + verify( + () => urlLauncher.launch( + 'https://firebase.google.com', + useSafariVC: any(named: 'useSafariVC'), + useWebView: any(named: 'useWebView'), + enableJavaScript: any(named: 'enableJavaScript'), + enableDomStorage: any(named: 'enableDomStorage'), + universalLinksOnly: any(named: 'universalLinksOnly'), + headers: any(named: 'headers'), + ), + ); + }, + ); + }); +} diff --git a/test/game/components/android_acres_test.dart b/test/game/components/android_acres_test.dart index 01ab5d7b..aef6a812 100644 --- a/test/game/components/android_acres_test.dart +++ b/test/game/components/android_acres_test.dart @@ -11,24 +11,27 @@ import '../../helpers/helpers.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); final assets = [ - Assets.images.spaceship.ramp.boardOpening.keyName, - Assets.images.spaceship.ramp.railingForeground.keyName, - Assets.images.spaceship.ramp.railingBackground.keyName, - Assets.images.spaceship.ramp.main.keyName, - Assets.images.spaceship.ramp.arrow.inactive.keyName, - Assets.images.spaceship.ramp.arrow.active1.keyName, - Assets.images.spaceship.ramp.arrow.active2.keyName, - Assets.images.spaceship.ramp.arrow.active3.keyName, - Assets.images.spaceship.ramp.arrow.active4.keyName, - Assets.images.spaceship.ramp.arrow.active5.keyName, - Assets.images.spaceship.rail.main.keyName, - Assets.images.spaceship.rail.exit.keyName, - Assets.images.androidBumper.a.lit.keyName, - Assets.images.androidBumper.a.dimmed.keyName, - Assets.images.androidBumper.b.lit.keyName, - Assets.images.androidBumper.b.dimmed.keyName, - Assets.images.androidBumper.cow.lit.keyName, - Assets.images.androidBumper.cow.dimmed.keyName, + Assets.images.android.spaceship.saucer.keyName, + Assets.images.android.spaceship.animatronic.keyName, + Assets.images.android.spaceship.lightBeam.keyName, + Assets.images.android.ramp.boardOpening.keyName, + Assets.images.android.ramp.railingForeground.keyName, + Assets.images.android.ramp.railingBackground.keyName, + Assets.images.android.ramp.main.keyName, + Assets.images.android.ramp.arrow.inactive.keyName, + Assets.images.android.ramp.arrow.active1.keyName, + Assets.images.android.ramp.arrow.active2.keyName, + Assets.images.android.ramp.arrow.active3.keyName, + Assets.images.android.ramp.arrow.active4.keyName, + Assets.images.android.ramp.arrow.active5.keyName, + Assets.images.android.rail.main.keyName, + Assets.images.android.rail.exit.keyName, + Assets.images.android.bumper.a.lit.keyName, + Assets.images.android.bumper.a.dimmed.keyName, + Assets.images.android.bumper.b.lit.keyName, + Assets.images.android.bumper.b.dimmed.keyName, + Assets.images.android.bumper.cow.lit.keyName, + Assets.images.android.bumper.cow.dimmed.keyName, ]; final flameTester = FlameTester( () => EmptyPinballTestGame(assets: assets), @@ -48,7 +51,7 @@ void main() { 'a Spaceship', (game) async { expect( - AndroidAcres().blueprints.whereType().single, + AndroidAcres().blueprints.whereType().single, isNotNull, ); }, diff --git a/test/game/pinball_game_test.dart b/test/game/pinball_game_test.dart index a9c6ac78..41fb1812 100644 --- a/test/game/pinball_game_test.dart +++ b/test/game/pinball_game_test.dart @@ -15,15 +15,16 @@ import '../helpers/helpers.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); final assets = [ - Assets.images.androidBumper.a.lit.keyName, - Assets.images.androidBumper.a.dimmed.keyName, - Assets.images.androidBumper.b.lit.keyName, - Assets.images.androidBumper.b.dimmed.keyName, - Assets.images.androidBumper.cow.lit.keyName, - Assets.images.androidBumper.cow.dimmed.keyName, + Assets.images.android.bumper.a.lit.keyName, + Assets.images.android.bumper.a.dimmed.keyName, + Assets.images.android.bumper.b.lit.keyName, + Assets.images.android.bumper.b.dimmed.keyName, + Assets.images.android.bumper.cow.lit.keyName, + Assets.images.android.bumper.cow.dimmed.keyName, Assets.images.backboard.backboardScores.keyName, Assets.images.backboard.backboardGameOver.keyName, Assets.images.backboard.display.keyName, + Assets.images.boardBackground.keyName, Assets.images.ball.ball.keyName, Assets.images.ball.flameEffect.keyName, Assets.images.baseboard.left.keyName, @@ -73,20 +74,22 @@ void main() { Assets.images.signpost.active3.keyName, Assets.images.slingshot.upper.keyName, Assets.images.slingshot.lower.keyName, - Assets.images.spaceship.saucer.keyName, - Assets.images.spaceship.bridge.keyName, - Assets.images.spaceship.ramp.boardOpening.keyName, - Assets.images.spaceship.ramp.railingForeground.keyName, - Assets.images.spaceship.ramp.railingBackground.keyName, - Assets.images.spaceship.ramp.main.keyName, - Assets.images.spaceship.ramp.arrow.inactive.keyName, - Assets.images.spaceship.ramp.arrow.active1.keyName, - Assets.images.spaceship.ramp.arrow.active2.keyName, - Assets.images.spaceship.ramp.arrow.active3.keyName, - Assets.images.spaceship.ramp.arrow.active4.keyName, - Assets.images.spaceship.ramp.arrow.active5.keyName, - Assets.images.spaceship.rail.main.keyName, - Assets.images.spaceship.rail.exit.keyName, + Assets.images.android.spaceship.saucer.keyName, + Assets.images.android.spaceship.animatronic.keyName, + Assets.images.android.spaceship.lightBeam.keyName, + Assets.images.android.ramp.boardOpening.keyName, + Assets.images.android.ramp.railingForeground.keyName, + Assets.images.android.ramp.railingBackground.keyName, + Assets.images.android.ramp.main.keyName, + Assets.images.android.ramp.arrow.inactive.keyName, + Assets.images.android.ramp.arrow.active1.keyName, + Assets.images.android.ramp.arrow.active2.keyName, + Assets.images.android.ramp.arrow.active3.keyName, + Assets.images.android.ramp.arrow.active4.keyName, + Assets.images.android.ramp.arrow.active5.keyName, + Assets.images.android.rail.main.keyName, + Assets.images.android.rail.exit.keyName, + Assets.images.sparky.animatronic.keyName, Assets.images.sparky.computer.top.keyName, Assets.images.sparky.computer.base.keyName, Assets.images.sparky.computer.glow.keyName, diff --git a/test/game/view/widgets/game_hud_test.dart b/test/game/view/widgets/game_hud_test.dart index d101d06e..79cc4f33 100644 --- a/test/game/view/widgets/game_hud_test.dart +++ b/test/game/view/widgets/game_hud_test.dart @@ -15,6 +15,7 @@ import 'package:mocktail/mocktail.dart'; import 'package:pinball/game/game.dart'; import 'package:pinball/l10n/l10n.dart'; import 'package:pinball_components/pinball_components.dart' hide Assets; +import 'package:pinball_ui/pinball_ui.dart'; import '../../../helpers/helpers.dart'; @@ -56,6 +57,7 @@ void main() { Future _pumpAppWithWidget(WidgetTester tester) async { await tester.pumpWidget( MaterialApp( + theme: PinballTheme.standard, localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, diff --git a/test/game/view/widgets/round_count_display_test.dart b/test/game/view/widgets/round_count_display_test.dart index 8f5f7f13..335a1c32 100644 --- a/test/game/view/widgets/round_count_display_test.dart +++ b/test/game/view/widgets/round_count_display_test.dart @@ -2,7 +2,7 @@ import 'package:bloc_test/bloc_test.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pinball/game/game.dart'; -import 'package:pinball/theme/app_colors.dart'; +import 'package:pinball_ui/pinball_ui.dart'; import '../../../helpers/helpers.dart'; @@ -108,7 +108,7 @@ void main() { expect( find.byWidgetPredicate( - (widget) => widget is Container && widget.color == AppColors.yellow, + (widget) => widget is Container && widget.color == PinballColors.yellow, ), findsOneWidget, ); @@ -125,7 +125,7 @@ void main() { find.byWidgetPredicate( (widget) => widget is Container && - widget.color == AppColors.yellow.withAlpha(128), + widget.color == PinballColors.yellow.withAlpha(128), ), findsOneWidget, ); diff --git a/test/helpers/helpers.dart b/test/helpers/helpers.dart index 8732035a..58b4b126 100644 --- a/test/helpers/helpers.dart +++ b/test/helpers/helpers.dart @@ -12,3 +12,4 @@ export 'mocks.dart'; export 'navigator.dart'; export 'pump_app.dart'; export 'test_games.dart'; +export 'text_span.dart'; diff --git a/test/helpers/mocks.dart b/test/helpers/mocks.dart index 1578c3e0..1d3ad3c7 100644 --- a/test/helpers/mocks.dart +++ b/test/helpers/mocks.dart @@ -1,3 +1,4 @@ +import 'package:authentication_repository/authentication_repository.dart'; import 'package:flame/components.dart'; import 'package:flame/game.dart'; import 'package:flame/input.dart'; @@ -11,6 +12,8 @@ import 'package:pinball/select_character/select_character.dart'; import 'package:pinball/start_game/start_game.dart'; import 'package:pinball_audio/pinball_audio.dart'; import 'package:pinball_components/pinball_components.dart'; +import 'package:pinball_ui/pinball_ui.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; class MockPinballGame extends Mock implements PinballGame {} @@ -34,6 +37,9 @@ class MockGameState extends Mock implements GameState {} class MockCharacterThemeCubit extends Mock implements CharacterThemeCubit {} +class MockAuthenticationRepository extends Mock + implements AuthenticationRepository {} + class MockLeaderboardRepository extends Mock implements LeaderboardRepository {} class MockRawKeyDownEvent extends Mock implements RawKeyDownEvent { @@ -94,3 +100,7 @@ class MockMultiplier extends Mock implements Multiplier {} class MockMultipliersGroup extends Mock implements Multipliers {} class MockMultiplierCubit extends Mock implements MultiplierCubit {} + +class MockUrlLauncher extends Mock + with MockPlatformInterfaceMixin + implements UrlLauncherPlatform {} diff --git a/test/helpers/pump_app.dart b/test/helpers/pump_app.dart index 2c112426..be67d4d0 100644 --- a/test/helpers/pump_app.dart +++ b/test/helpers/pump_app.dart @@ -17,6 +17,7 @@ import 'package:pinball/l10n/l10n.dart'; import 'package:pinball/select_character/select_character.dart'; import 'package:pinball/start_game/start_game.dart'; import 'package:pinball_audio/pinball_audio.dart'; +import 'package:pinball_ui/pinball_ui.dart'; import 'helpers.dart'; @@ -85,6 +86,7 @@ extension PumpApp on WidgetTester { ), ], child: MaterialApp( + theme: PinballTheme.standard, localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, diff --git a/test/helpers/text_span.dart b/test/helpers/text_span.dart new file mode 100644 index 00000000..c98d33d9 --- /dev/null +++ b/test/helpers/text_span.dart @@ -0,0 +1,17 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/widgets.dart'; + +bool tapTextSpan(RichText richText, String text) { + final isTapped = !richText.text.visitChildren( + (visitor) => _findTextAndTap(visitor, text), + ); + return isTapped; +} + +bool _findTextAndTap(InlineSpan visitor, String text) { + if (visitor is TextSpan && visitor.text == text) { + (visitor.recognizer as TapGestureRecognizer?)?.onTap?.call(); + return false; + } + return true; +} diff --git a/web/__/firebase/8.10.1/firebase-app.js b/web/__/firebase/8.10.1/firebase-app.js new file mode 100644 index 00000000..c688d1c4 --- /dev/null +++ b/web/__/firebase/8.10.1/firebase-app.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).firebase=t()}(this,function(){"use strict";var r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};var n=function(){return(n=Object.assign||function(e){for(var t,n=1,r=arguments.length;na[0]&&t[1]=e.length?void 0:e)&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function f(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,i,o=n.call(e),a=[];try{for(;(void 0===t||0"})):"Error",e=this.serviceName+": "+e+" ("+o+").";return new c(o,e,i)},v);function v(e,t,n){this.service=e,this.serviceName=t,this.errors=n}var m=/\{\$([^}]+)}/g;function y(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function g(e,t){t=new b(e,t);return t.subscribe.bind(t)}var b=(I.prototype.next=function(t){this.forEachObserver(function(e){e.next(t)})},I.prototype.error=function(t){this.forEachObserver(function(e){e.error(t)}),this.close(t)},I.prototype.complete=function(){this.forEachObserver(function(e){e.complete()}),this.close()},I.prototype.subscribe=function(e,t,n){var r,i=this;if(void 0===e&&void 0===t&&void 0===n)throw new Error("Missing Observer.");void 0===(r=function(e,t){if("object"!=typeof e||null===e)return!1;for(var n=0,r=t;n=(null!=o?o:e.logLevel)&&a({level:R[t].toLowerCase(),message:i,args:n,type:e.name})}}(n[e])}var H=((H={})["no-app"]="No Firebase App '{$appName}' has been created - call Firebase App.initializeApp()",H["bad-app-name"]="Illegal App name: '{$appName}",H["duplicate-app"]="Firebase App named '{$appName}' already exists",H["app-deleted"]="Firebase App named '{$appName}' already deleted",H["invalid-app-argument"]="firebase.{$appName}() takes either no argument or a Firebase App instance.",H["invalid-log-argument"]="First argument to `onLog` must be null or a function.",H),V=new d("app","Firebase",H),B="@firebase/app",M="[DEFAULT]",U=((H={})[B]="fire-core",H["@firebase/analytics"]="fire-analytics",H["@firebase/app-check"]="fire-app-check",H["@firebase/auth"]="fire-auth",H["@firebase/database"]="fire-rtdb",H["@firebase/functions"]="fire-fn",H["@firebase/installations"]="fire-iid",H["@firebase/messaging"]="fire-fcm",H["@firebase/performance"]="fire-perf",H["@firebase/remote-config"]="fire-rc",H["@firebase/storage"]="fire-gcs",H["@firebase/firestore"]="fire-fst",H["fire-js"]="fire-js",H["firebase-wrapper"]="fire-js-all",H),W=new z("@firebase/app"),G=(Object.defineProperty($.prototype,"automaticDataCollectionEnabled",{get:function(){return this.checkDestroyed_(),this.automaticDataCollectionEnabled_},set:function(e){this.checkDestroyed_(),this.automaticDataCollectionEnabled_=e},enumerable:!1,configurable:!0}),Object.defineProperty($.prototype,"name",{get:function(){return this.checkDestroyed_(),this.name_},enumerable:!1,configurable:!0}),Object.defineProperty($.prototype,"options",{get:function(){return this.checkDestroyed_(),this.options_},enumerable:!1,configurable:!0}),$.prototype.delete=function(){var t=this;return new Promise(function(e){t.checkDestroyed_(),e()}).then(function(){return t.firebase_.INTERNAL.removeApp(t.name_),Promise.all(t.container.getProviders().map(function(e){return e.delete()}))}).then(function(){t.isDeleted_=!0})},$.prototype._getService=function(e,t){void 0===t&&(t=M),this.checkDestroyed_();var n=this.container.getProvider(e);return n.isInitialized()||"EXPLICIT"!==(null===(e=n.getComponent())||void 0===e?void 0:e.instantiationMode)||n.initialize(),n.getImmediate({identifier:t})},$.prototype._removeServiceInstance=function(e,t){void 0===t&&(t=M),this.container.getProvider(e).clearInstance(t)},$.prototype._addComponent=function(t){try{this.container.addComponent(t)}catch(e){W.debug("Component "+t.name+" failed to register with FirebaseApp "+this.name,e)}},$.prototype._addOrOverwriteComponent=function(e){this.container.addOrOverwriteComponent(e)},$.prototype.toJSON=function(){return{name:this.name,automaticDataCollectionEnabled:this.automaticDataCollectionEnabled,options:this.options}},$.prototype.checkDestroyed_=function(){if(this.isDeleted_)throw V.create("app-deleted",{appName:this.name_})},$);function $(e,t,n){var r=this;this.firebase_=n,this.isDeleted_=!1,this.name_=t.name,this.automaticDataCollectionEnabled_=t.automaticDataCollectionEnabled||!1,this.options_=h(void 0,e),this.container=new S(t.name),this._addComponent(new O("app",function(){return r},"PUBLIC")),this.firebase_.INTERNAL.components.forEach(function(e){return r._addComponent(e)})}G.prototype.name&&G.prototype.options||G.prototype.delete||console.log("dc");var K="8.10.1";function Y(a){var s={},l=new Map,c={__esModule:!0,initializeApp:function(e,t){void 0===t&&(t={});"object"==typeof t&&null!==t||(t={name:t});var n=t;void 0===n.name&&(n.name=M);t=n.name;if("string"!=typeof t||!t)throw V.create("bad-app-name",{appName:String(t)});if(y(s,t))throw V.create("duplicate-app",{appName:t});n=new a(e,n,c);return s[t]=n},app:u,registerVersion:function(e,t,n){var r=null!==(i=U[e])&&void 0!==i?i:e;n&&(r+="-"+n);var i=r.match(/\s|\//),e=t.match(/\s|\//);i||e?(n=['Unable to register library "'+r+'" with version "'+t+'":'],i&&n.push('library name "'+r+'" contains illegal characters (whitespace or "/")'),i&&e&&n.push("and"),e&&n.push('version name "'+t+'" contains illegal characters (whitespace or "/")'),W.warn(n.join(" "))):o(new O(r+"-version",function(){return{library:r,version:t}},"VERSION"))},setLogLevel:T,onLog:function(e,t){if(null!==e&&"function"!=typeof e)throw V.create("invalid-log-argument");x(e,t)},apps:null,SDK_VERSION:K,INTERNAL:{registerComponent:o,removeApp:function(e){delete s[e]},components:l,useAsService:function(e,t){return"serverAuth"!==t?t:null}}};function u(e){if(!y(s,e=e||M))throw V.create("no-app",{appName:e});return s[e]}function o(n){var e,r=n.name;if(l.has(r))return W.debug("There were multiple attempts to register component "+r+"."),"PUBLIC"===n.type?c[r]:null;l.set(r,n),"PUBLIC"===n.type&&(e=function(e){if("function"!=typeof(e=void 0===e?u():e)[r])throw V.create("invalid-app-argument",{appName:r});return e[r]()},void 0!==n.serviceProps&&h(e,n.serviceProps),c[r]=e,a.prototype[r]=function(){for(var e=[],t=0;t>>0),i=0;function r(t,e,n){return t.call.apply(t.bind,arguments)}function g(e,n,t){if(!e)throw Error();if(2/g,Q=/"/g,tt=/'/g,et=/\x00/g,nt=/[\x00&<>"']/;function it(t,e){return-1!=t.indexOf(e)}function rt(t,e){return t"}else o=void 0===t?"undefined":null===t?"null":typeof t;D("Argument is not a %s (or a non-Element, non-Location mock); got: %s",e,o)}}function dt(t,e){this.a=t===gt&&e||"",this.b=mt}function pt(t){return t instanceof dt&&t.constructor===dt&&t.b===mt?t.a:(D("expected object of type Const, got '"+t+"'"),"type_error:Const")}dt.prototype.ta=!0,dt.prototype.sa=function(){return this.a},dt.prototype.toString=function(){return"Const{"+this.a+"}"};var vt,mt={},gt={};function bt(){if(void 0===vt){var t=null,e=l.trustedTypes;if(e&&e.createPolicy){try{t=e.createPolicy("goog#html",{createHTML:I,createScript:I,createScriptURL:I})}catch(t){l.console&&l.console.error(t.message)}vt=t}else vt=t}return vt}function yt(t,e){this.a=e===At?t:""}function wt(t){return t instanceof yt&&t.constructor===yt?t.a:(D("expected object of type TrustedResourceUrl, got '"+t+"' of type "+d(t)),"type_error:TrustedResourceUrl")}function It(t,n){var e,i=pt(t);if(!Et.test(i))throw Error("Invalid TrustedResourceUrl format: "+i);return t=i.replace(Tt,function(t,e){if(!Object.prototype.hasOwnProperty.call(n,e))throw Error('Found marker, "'+e+'", in format string, "'+i+'", but no valid label mapping found in args: '+JSON.stringify(n));return(t=n[e])instanceof dt?pt(t):encodeURIComponent(String(t))}),e=t,t=bt(),new yt(e=t?t.createScriptURL(e):e,At)}yt.prototype.ta=!0,yt.prototype.sa=function(){return this.a.toString()},yt.prototype.toString=function(){return"TrustedResourceUrl{"+this.a+"}"};var Tt=/%{(\w+)}/g,Et=/^((https:)?\/\/[0-9a-z.:[\]-]+\/|\/[^/\\]|[^:/\\%]+\/|[^:/\\%]*[?#]|about:blank#)/i,At={};function kt(t,e){this.a=e===Dt?t:""}function St(t){return t instanceof kt&&t.constructor===kt?t.a:(D("expected object of type SafeUrl, got '"+t+"' of type "+d(t)),"type_error:SafeUrl")}kt.prototype.ta=!0,kt.prototype.sa=function(){return this.a.toString()},kt.prototype.toString=function(){return"SafeUrl{"+this.a+"}"};var Nt=/^(?:audio\/(?:3gpp2|3gpp|aac|L16|midi|mp3|mp4|mpeg|oga|ogg|opus|x-m4a|x-matroska|x-wav|wav|webm)|font\/\w+|image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|x-icon)|text\/csv|video\/(?:mpeg|mp4|ogg|webm|quicktime|x-matroska))(?:;\w+=(?:\w+|"[\w;,= ]+"))*$/i,_t=/^data:(.*);base64,[a-z0-9+\/]+=*$/i,Ot=/^(?:(?:https?|mailto|ftp):|[^:/?#]*(?:[/?#]|$))/i;function Ct(t){return t instanceof kt?t:(t="object"==typeof t&&t.ta?t.sa():String(t),t=Ot.test(t)||(e=(t=(t=String(t)).replace(/(%0A|%0D)/g,"")).match(_t))&&Nt.test(e[1])?new kt(t,Dt):null);var e}function Rt(t){return t instanceof kt?t:(t="object"==typeof t&&t.ta?t.sa():String(t),new kt(t=!Ot.test(t)?"about:invalid#zClosurez":t,Dt))}var Dt={},Pt=new kt("about:invalid#zClosurez",Dt);function Lt(t,e,n){this.a=n===xt?t:""}Lt.prototype.ta=!0,Lt.prototype.sa=function(){return this.a.toString()},Lt.prototype.toString=function(){return"SafeHtml{"+this.a+"}"};var xt={};function Mt(t,e,n,i){return t=t instanceof kt?t:Rt(t),e=e||l,n=n instanceof dt?pt(n):n||"",e.open(St(t),n,i,void 0)}function jt(t){for(var e=t.split("%s"),n="",i=Array.prototype.slice.call(arguments,1);i.length&&1")?t.replace(Z,">"):t).indexOf('"')?t.replace(Q,"""):t).indexOf("'")?t.replace(tt,"'"):t).indexOf("\0")&&(t=t.replace(et,"�"))),t}function Vt(t){return Vt[" "](t),t}Vt[" "]=a;var Ft,qt=at("Opera"),Ht=at("Trident")||at("MSIE"),Kt=at("Edge"),Gt=Kt||Ht,Bt=at("Gecko")&&!(it(J.toLowerCase(),"webkit")&&!at("Edge"))&&!(at("Trident")||at("MSIE"))&&!at("Edge"),Wt=it(J.toLowerCase(),"webkit")&&!at("Edge");function Xt(){var t=l.document;return t?t.documentMode:void 0}t:{var Jt="",Yt=(Yt=J,Bt?/rv:([^\);]+)(\)|;)/.exec(Yt):Kt?/Edge\/([\d\.]+)/.exec(Yt):Ht?/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(Yt):Wt?/WebKit\/(\S+)/.exec(Yt):qt?/(?:Version)[ \/]?(\S+)/.exec(Yt):void 0);if(Yt&&(Jt=Yt?Yt[1]:""),Ht){Yt=Xt();if(null!=Yt&&Yt>parseFloat(Jt)){Ft=String(Yt);break t}}Ft=Jt}var zt={};function $t(s){return t=s,e=function(){for(var t=0,e=Y(String(Ft)).split("."),n=Y(String(s)).split("."),i=Math.max(e.length,n.length),r=0;0==t&&r"),i=i.join("")),i=ae(n,i),r&&("string"==typeof r?i.className=r:Array.isArray(r)?i.className=r.join(" "):ee(i,r)),2>>0);function ln(e){return v(e)?e:(e[hn]||(e[hn]=function(t){return e.handleEvent(t)}),e[hn])}function fn(){Pe.call(this),this.v=new Je(this),(this.bc=this).hb=null}function dn(t,e,n,i,r){t.v.add(String(e),n,!1,i,r)}function pn(t,e,n,i,r){t.v.add(String(e),n,!0,i,r)}function vn(t,e,n,i){if(!(e=t.v.a[String(e)]))return!0;e=e.concat();for(var r=!0,o=0;o>4&15).toString(16)+(15&t).toString(16)}An.prototype.toString=function(){var t=[],e=this.c;e&&t.push(Pn(e,xn,!0),":");var n=this.a;return!n&&"file"!=e||(t.push("//"),(e=this.l)&&t.push(Pn(e,xn,!0),"@"),t.push(encodeURIComponent(String(n)).replace(/%25([0-9a-fA-F]{2})/g,"%$1")),null!=(n=this.g)&&t.push(":",String(n))),(n=this.f)&&(this.a&&"/"!=n.charAt(0)&&t.push("/"),t.push(Pn(n,"/"==n.charAt(0)?jn:Mn,!0))),(n=this.b.toString())&&t.push("?",n),(n=this.h)&&t.push("#",Pn(n,Vn)),t.join("")},An.prototype.resolve=function(t){var e=new An(this),n=!!t.c;n?kn(e,t.c):n=!!t.l,n?e.l=t.l:n=!!t.a,n?e.a=t.a:n=null!=t.g;var i=t.f;if(n)Sn(e,t.g);else if(n=!!t.f)if("/"!=i.charAt(0)&&(this.a&&!this.f?i="/"+i:-1!=(r=e.f.lastIndexOf("/"))&&(i=e.f.substr(0,r+1)+i)),".."==(r=i)||"."==r)i="";else if(it(r,"./")||it(r,"/.")){for(var i=0==r.lastIndexOf("/",0),r=r.split("/"),o=[],a=0;a2*t.c&&In(t)))}function Gn(t,e){return qn(t),e=Xn(t,e),Tn(t.a.b,e)}function Bn(t,e,n){Kn(t,e),0',t=new Lt(t=(i=bt())?i.createHTML(t):t,0,xt),i=a.document)&&(i.write((o=t)instanceof Lt&&o.constructor===Lt?o.a:(D("expected object of type SafeHtml, got '"+o+"' of type "+d(o)),"type_error:SafeHtml")),i.close())):(a=Mt(e,i,n,a))&&t.noopener&&(a.opener=null),a)try{a.focus()}catch(t){}return a}var oi=/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/,ai=/^[^@]+@[^@]+$/;function si(){var e=null;return new fe(function(t){"complete"==l.document.readyState?t():(e=function(){t()},en(window,"load",e))}).o(function(t){throw nn(window,"load",e),t})}function ui(t){return t=t||bi(),!("file:"!==Ei()&&"ionic:"!==Ei()||!t.toLowerCase().match(/iphone|ipad|ipod|android/))}function ci(){var t=l.window;try{return t&&t!=t.top}catch(t){return}}function hi(){return void 0!==l.WorkerGlobalScope&&"function"==typeof l.importScripts}function li(){return Zl.default.INTERNAL.hasOwnProperty("reactNative")?"ReactNative":Zl.default.INTERNAL.hasOwnProperty("node")?"Node":hi()?"Worker":"Browser"}function fi(){var t=li();return"ReactNative"===t||"Node"===t}var di="Firefox",pi="Chrome";function vi(t){var e=t.toLowerCase();return it(e,"opera/")||it(e,"opr/")||it(e,"opios/")?"Opera":it(e,"iemobile")?"IEMobile":it(e,"msie")||it(e,"trident/")?"IE":it(e,"edge/")?"Edge":it(e,"firefox/")?di:it(e,"silk/")?"Silk":it(e,"blackberry")?"Blackberry":it(e,"webos")?"Webos":!it(e,"safari/")||it(e,"chrome/")||it(e,"crios/")||it(e,"android")?!it(e,"chrome/")&&!it(e,"crios/")||it(e,"edge/")?it(e,"android")?"Android":(t=t.match(/([a-zA-Z\d\.]+)\/[a-zA-Z\d\.]*$/))&&2==t.length?t[1]:"Other":pi:"Safari"}var mi={md:"FirebaseCore-web",od:"FirebaseUI-web"};function gi(t,e){e=e||[];var n,i=[],r={};for(n in mi)r[mi[n]]=!0;for(n=0;n>4),64!=a&&(t(o<<4&240|a>>2),64!=s&&t(a<<6&192|s))}}(t,function(t){e.push(t)}),e}function Pr(t){var e=xr(t);if(!(e&&e.sub&&e.iss&&e.aud&&e.exp))throw Error("Invalid JWT");this.h=t,this.a=e.exp,this.i=e.sub,t=Date.now()/1e3,this.g=e.iat||(t>this.a?this.a:t),this.b=e.provider_id||e.firebase&&e.firebase.sign_in_provider||null,this.f=e.firebase&&e.firebase.tenant||null,this.c=!!e.is_anonymous||"anonymous"==this.b}function Lr(t){try{return new Pr(t)}catch(t){return null}}function xr(t){if(!t)return null;if(3!=(t=t.split(".")).length)return null;for(var e=(4-(t=t[1]).length%4)%4,n=0;n>10)),t[n++]=String.fromCharCode(56320+(1023&a))):(r=i[e++],o=i[e++],t[n++]=String.fromCharCode((15&s)<<12|(63&r)<<6|63&o))}return JSON.parse(t.join(""))}catch(t){}return null}Pr.prototype.T=function(){return this.f},Pr.prototype.l=function(){return this.c},Pr.prototype.toString=function(){return this.h};var Mr="oauth_consumer_key oauth_nonce oauth_signature oauth_signature_method oauth_timestamp oauth_token oauth_version".split(" "),jr=["client_id","response_type","scope","redirect_uri","state"],Ur={nd:{Ja:"locale",va:700,ua:600,fa:"facebook.com",Ya:jr},pd:{Ja:null,va:500,ua:750,fa:"github.com",Ya:jr},qd:{Ja:"hl",va:515,ua:680,fa:"google.com",Ya:jr},wd:{Ja:"lang",va:485,ua:705,fa:"twitter.com",Ya:Mr},kd:{Ja:"locale",va:640,ua:600,fa:"apple.com",Ya:[]}};function Vr(t){for(var e in Ur)if(Ur[e].fa==t)return Ur[e];return null}function Fr(t){var e={};e["facebook.com"]=Br,e["google.com"]=Xr,e["github.com"]=Wr,e["twitter.com"]=Jr;var n=t&&t[Hr];try{if(n)return new(e[n]||Gr)(t);if(void 0!==t[qr])return new Kr(t)}catch(t){}return null}var qr="idToken",Hr="providerId";function Kr(t){var e,n=t[Hr];if(n||!t[qr]||(e=Lr(t[qr]))&&e.b&&(n=e.b),!n)throw Error("Invalid additional user info!");e=!1,void 0!==t.isNewUser?e=!!t.isNewUser:"identitytoolkit#SignupNewUserResponse"===t.kind&&(e=!0),Fi(this,"providerId",n="anonymous"==n||"custom"==n?null:n),Fi(this,"isNewUser",e)}function Gr(t){Kr.call(this,t),Fi(this,"profile",Ki((t=Ni(t.rawUserInfo||"{}"))||{}))}function Br(t){if(Gr.call(this,t),"facebook.com"!=this.providerId)throw Error("Invalid provider ID!")}function Wr(t){if(Gr.call(this,t),"github.com"!=this.providerId)throw Error("Invalid provider ID!");Fi(this,"username",this.profile&&this.profile.login||null)}function Xr(t){if(Gr.call(this,t),"google.com"!=this.providerId)throw Error("Invalid provider ID!")}function Jr(t){if(Gr.call(this,t),"twitter.com"!=this.providerId)throw Error("Invalid provider ID!");Fi(this,"username",t.screenName||null)}function Yr(t){var e=On(i=Cn(t),"link"),n=On(Cn(e),"link"),i=On(i,"deep_link_id");return On(Cn(i),"link")||i||n||e||t}function zr(t,e){if(!t&&!e)throw new T("internal-error","Internal assert: no raw session string available");if(t&&e)throw new T("internal-error","Internal assert: unable to determine the session type");this.a=t||null,this.b=e||null,this.type=this.a?$r:Zr}w(Gr,Kr),w(Br,Gr),w(Wr,Gr),w(Xr,Gr),w(Jr,Gr);var $r="enroll",Zr="signin";function Qr(){}function to(t,n){return t.then(function(t){if(t[Ka]){var e=Lr(t[Ka]);if(!e||n!=e.i)throw new T("user-mismatch");return t}throw new T("user-mismatch")}).o(function(t){throw t&&t.code&&t.code==k+"user-not-found"?new T("user-mismatch"):t})}function eo(t,e){if(!e)throw new T("internal-error","failed to construct a credential");this.a=e,Fi(this,"providerId",t),Fi(this,"signInMethod",t)}function no(t){return{pendingToken:t.a,requestUri:"http://localhost"}}function io(t){if(t&&t.providerId&&t.signInMethod&&0==t.providerId.indexOf("saml.")&&t.pendingToken)try{return new eo(t.providerId,t.pendingToken)}catch(t){}return null}function ro(t,e,n){if(this.a=null,e.idToken||e.accessToken)e.idToken&&Fi(this,"idToken",e.idToken),e.accessToken&&Fi(this,"accessToken",e.accessToken),e.nonce&&!e.pendingToken&&Fi(this,"nonce",e.nonce),e.pendingToken&&(this.a=e.pendingToken);else{if(!e.oauthToken||!e.oauthTokenSecret)throw new T("internal-error","failed to construct a credential");Fi(this,"accessToken",e.oauthToken),Fi(this,"secret",e.oauthTokenSecret)}Fi(this,"providerId",t),Fi(this,"signInMethod",n)}function oo(t){var e={};return t.idToken&&(e.id_token=t.idToken),t.accessToken&&(e.access_token=t.accessToken),t.secret&&(e.oauth_token_secret=t.secret),e.providerId=t.providerId,t.nonce&&!t.a&&(e.nonce=t.nonce),e={postBody:Hn(e).toString(),requestUri:"http://localhost"},t.a&&(delete e.postBody,e.pendingToken=t.a),e}function ao(t){if(t&&t.providerId&&t.signInMethod){var e={idToken:t.oauthIdToken,accessToken:t.oauthTokenSecret?null:t.oauthAccessToken,oauthTokenSecret:t.oauthTokenSecret,oauthToken:t.oauthTokenSecret&&t.oauthAccessToken,nonce:t.nonce,pendingToken:t.pendingToken};try{return new ro(t.providerId,e,t.signInMethod)}catch(t){}}return null}function so(t,e){this.Qc=e||[],qi(this,{providerId:t,isOAuthProvider:!0}),this.Jb={},this.qb=(Vr(t)||{}).Ja||null,this.pb=null}function uo(t){if("string"!=typeof t||0!=t.indexOf("saml."))throw new T("argument-error",'SAML provider IDs must be prefixed with "saml."');so.call(this,t,[])}function co(t){so.call(this,t,jr),this.a=[]}function ho(){co.call(this,"facebook.com")}function lo(t){if(!t)throw new T("argument-error","credential failed: expected 1 argument (the OAuth access token).");var e=t;return m(t)&&(e=t.accessToken),(new ho).credential({accessToken:e})}function fo(){co.call(this,"github.com")}function po(t){if(!t)throw new T("argument-error","credential failed: expected 1 argument (the OAuth access token).");var e=t;return m(t)&&(e=t.accessToken),(new fo).credential({accessToken:e})}function vo(){co.call(this,"google.com"),this.Ca("profile")}function mo(t,e){var n=t;return m(t)&&(n=t.idToken,e=t.accessToken),(new vo).credential({idToken:n,accessToken:e})}function go(){so.call(this,"twitter.com",Mr)}function bo(t,e){var n=t;if(!(n=!m(n)?{oauthToken:t,oauthTokenSecret:e}:n).oauthToken||!n.oauthTokenSecret)throw new T("argument-error","credential failed: expected 2 arguments (the OAuth access token and secret).");return new ro("twitter.com",n,"twitter.com")}function yo(t,e,n){this.a=t,this.f=e,Fi(this,"providerId","password"),Fi(this,"signInMethod",n===Io.EMAIL_LINK_SIGN_IN_METHOD?Io.EMAIL_LINK_SIGN_IN_METHOD:Io.EMAIL_PASSWORD_SIGN_IN_METHOD)}function wo(t){return t&&t.email&&t.password?new yo(t.email,t.password,t.signInMethod):null}function Io(){qi(this,{providerId:"password",isOAuthProvider:!1})}function To(t,e){if(!(e=Eo(e)))throw new T("argument-error","Invalid email link!");return new yo(t,e.code,Io.EMAIL_LINK_SIGN_IN_METHOD)}function Eo(t){return(t=yr(t=Yr(t)))&&t.operation===Qi?t:null}function Ao(t){if(!(t.fb&&t.eb||t.La&&t.ea))throw new T("internal-error");this.a=t,Fi(this,"providerId","phone"),this.fa="phone",Fi(this,"signInMethod","phone")}function ko(e){if(e&&"phone"===e.providerId&&(e.verificationId&&e.verificationCode||e.temporaryProof&&e.phoneNumber)){var n={};return V(["verificationId","verificationCode","temporaryProof","phoneNumber"],function(t){e[t]&&(n[t]=e[t])}),new Ao(n)}return null}function So(t){return t.a.La&&t.a.ea?{temporaryProof:t.a.La,phoneNumber:t.a.ea}:{sessionInfo:t.a.fb,code:t.a.eb}}function No(t){try{this.a=t||Zl.default.auth()}catch(t){throw new T("argument-error","Either an instance of firebase.auth.Auth must be passed as an argument to the firebase.auth.PhoneAuthProvider constructor, or the default firebase App instance must be initialized via firebase.initializeApp().")}qi(this,{providerId:"phone",isOAuthProvider:!1})}function _o(t,e){if(!t)throw new T("missing-verification-id");if(!e)throw new T("missing-verification-code");return new Ao({fb:t,eb:e})}function Oo(t){if(t.temporaryProof&&t.phoneNumber)return new Ao({La:t.temporaryProof,ea:t.phoneNumber});var e=t&&t.providerId;if(!e||"password"===e)return null;var n=t&&t.oauthAccessToken,i=t&&t.oauthTokenSecret,r=t&&t.nonce,o=t&&t.oauthIdToken,a=t&&t.pendingToken;try{switch(e){case"google.com":return mo(o,n);case"facebook.com":return lo(n);case"github.com":return po(n);case"twitter.com":return bo(n,i);default:return n||i||o||a?a?0==e.indexOf("saml.")?new eo(e,a):new ro(e,{pendingToken:a,idToken:t.oauthIdToken,accessToken:t.oauthAccessToken},e):new co(e).credential({idToken:o,accessToken:n,rawNonce:r}):null}}catch(t){return null}}function Co(t){if(!t.isOAuthProvider)throw new T("invalid-oauth-provider")}function Ro(t,e,n,i,r,o,a){if(this.c=t,this.b=e||null,this.g=n||null,this.f=i||null,this.i=o||null,this.h=a||null,this.a=r||null,!this.g&&!this.a)throw new T("invalid-auth-event");if(this.g&&this.a)throw new T("invalid-auth-event");if(this.g&&!this.f)throw new T("invalid-auth-event")}function Do(t){return(t=t||{}).type?new Ro(t.type,t.eventId,t.urlResponse,t.sessionId,t.error&&E(t.error),t.postBody,t.tenantId):null}function Po(){this.b=null,this.a=[]}zr.prototype.Ha=function(){return this.a?ye(this.a):ye(this.b)},zr.prototype.w=function(){return this.type==$r?{multiFactorSession:{idToken:this.a}}:{multiFactorSession:{pendingCredential:this.b}}},Qr.prototype.ka=function(){},Qr.prototype.b=function(){},Qr.prototype.c=function(){},Qr.prototype.w=function(){},eo.prototype.ka=function(t){return ls(t,no(this))},eo.prototype.b=function(t,e){var n=no(this);return n.idToken=e,fs(t,n)},eo.prototype.c=function(t,e){return to(ds(t,no(this)),e)},eo.prototype.w=function(){return{providerId:this.providerId,signInMethod:this.signInMethod,pendingToken:this.a}},ro.prototype.ka=function(t){return ls(t,oo(this))},ro.prototype.b=function(t,e){var n=oo(this);return n.idToken=e,fs(t,n)},ro.prototype.c=function(t,e){return to(ds(t,oo(this)),e)},ro.prototype.w=function(){var t={providerId:this.providerId,signInMethod:this.signInMethod};return this.idToken&&(t.oauthIdToken=this.idToken),this.accessToken&&(t.oauthAccessToken=this.accessToken),this.secret&&(t.oauthTokenSecret=this.secret),this.nonce&&(t.nonce=this.nonce),this.a&&(t.pendingToken=this.a),t},so.prototype.Ka=function(t){return this.Jb=ct(t),this},w(uo,so),w(co,so),co.prototype.Ca=function(t){return K(this.a,t)||this.a.push(t),this},co.prototype.Rb=function(){return X(this.a)},co.prototype.credential=function(t,e){e=m(t)?{idToken:t.idToken||null,accessToken:t.accessToken||null,nonce:t.rawNonce||null}:{idToken:t||null,accessToken:e||null};if(!e.idToken&&!e.accessToken)throw new T("argument-error","credential failed: must provide the ID token and/or the access token.");return new ro(this.providerId,e,this.providerId)},w(ho,co),Fi(ho,"PROVIDER_ID","facebook.com"),Fi(ho,"FACEBOOK_SIGN_IN_METHOD","facebook.com"),w(fo,co),Fi(fo,"PROVIDER_ID","github.com"),Fi(fo,"GITHUB_SIGN_IN_METHOD","github.com"),w(vo,co),Fi(vo,"PROVIDER_ID","google.com"),Fi(vo,"GOOGLE_SIGN_IN_METHOD","google.com"),w(go,so),Fi(go,"PROVIDER_ID","twitter.com"),Fi(go,"TWITTER_SIGN_IN_METHOD","twitter.com"),yo.prototype.ka=function(t){return this.signInMethod==Io.EMAIL_LINK_SIGN_IN_METHOD?Js(t,Is,{email:this.a,oobCode:this.f}):Js(t,Ks,{email:this.a,password:this.f})},yo.prototype.b=function(t,e){return this.signInMethod==Io.EMAIL_LINK_SIGN_IN_METHOD?Js(t,Ts,{idToken:e,email:this.a,oobCode:this.f}):Js(t,xs,{idToken:e,email:this.a,password:this.f})},yo.prototype.c=function(t,e){return to(this.ka(t),e)},yo.prototype.w=function(){return{email:this.a,password:this.f,signInMethod:this.signInMethod}},qi(Io,{PROVIDER_ID:"password"}),qi(Io,{EMAIL_LINK_SIGN_IN_METHOD:"emailLink"}),qi(Io,{EMAIL_PASSWORD_SIGN_IN_METHOD:"password"}),Ao.prototype.ka=function(t){return t.gb(So(this))},Ao.prototype.b=function(t,e){var n=So(this);return n.idToken=e,Js(t,Bs,n)},Ao.prototype.c=function(t,e){var n=So(this);return n.operation="REAUTH",to(t=Js(t,Ws,n),e)},Ao.prototype.w=function(){var t={providerId:"phone"};return this.a.fb&&(t.verificationId=this.a.fb),this.a.eb&&(t.verificationCode=this.a.eb),this.a.La&&(t.temporaryProof=this.a.La),this.a.ea&&(t.phoneNumber=this.a.ea),t},No.prototype.gb=function(i,r){var o=this.a.a;return ye(r.verify()).then(function(e){if("string"!=typeof e)throw new T("argument-error","An implementation of firebase.auth.ApplicationVerifier.prototype.verify() must return a firebase.Promise that resolves with a string.");if("recaptcha"!==r.type)throw new T("argument-error",'Only firebase.auth.ApplicationVerifiers with type="recaptcha" are currently supported.');var t=m(i)?i.session:null,n=m(i)?i.phoneNumber:i,t=t&&t.type==$r?t.Ha().then(function(t){return Js(o,js,{idToken:t,phoneEnrollmentInfo:{phoneNumber:n,recaptchaToken:e}}).then(function(t){return t.phoneSessionInfo.sessionInfo})}):t&&t.type==Zr?t.Ha().then(function(t){return t={mfaPendingCredential:t,mfaEnrollmentId:i.multiFactorHint&&i.multiFactorHint.uid||i.multiFactorUid,phoneSignInInfo:{recaptchaToken:e}},Js(o,Us,t).then(function(t){return t.phoneResponseInfo.sessionInfo})}):Js(o,Ps,{phoneNumber:n,recaptchaToken:e});return t.then(function(t){return"function"==typeof r.reset&&r.reset(),t},function(t){throw"function"==typeof r.reset&&r.reset(),t})})},qi(No,{PROVIDER_ID:"phone"}),qi(No,{PHONE_SIGN_IN_METHOD:"phone"}),Ro.prototype.getUid=function(){var t=[];return t.push(this.c),this.b&&t.push(this.b),this.f&&t.push(this.f),this.h&&t.push(this.h),t.join("-")},Ro.prototype.T=function(){return this.h},Ro.prototype.w=function(){return{type:this.c,eventId:this.b,urlResponse:this.g,sessionId:this.f,postBody:this.i,tenantId:this.h,error:this.a&&this.a.w()}};var Lo,xo=null;function Mo(t){var e="unauthorized-domain",n=void 0,i=Cn(t);t=i.a,"chrome-extension"==(i=i.c)?n=jt("This chrome extension ID (chrome-extension://%s) is not authorized to run this operation. Add it to the OAuth redirect domains list in the Firebase console -> Auth section -> Sign in method tab.",t):"http"==i||"https"==i?n=jt("This domain (%s) is not authorized to run this operation. Add it to the OAuth redirect domains list in the Firebase console -> Auth section -> Sign in method tab.",t):e="operation-not-supported-in-this-environment",T.call(this,e,n)}function jo(t,e,n){T.call(this,t,n),(t=e||{}).Kb&&Fi(this,"email",t.Kb),t.ea&&Fi(this,"phoneNumber",t.ea),t.credential&&Fi(this,"credential",t.credential),t.$b&&Fi(this,"tenantId",t.$b)}function Uo(t){if(t.code){var e=t.code||"";0==e.indexOf(k)&&(e=e.substring(k.length));var n={credential:Oo(t),$b:t.tenantId};if(t.email)n.Kb=t.email;else if(t.phoneNumber)n.ea=t.phoneNumber;else if(!n.credential)return new T(e,t.message||void 0);return new jo(e,n,t.message)}return null}function Vo(){}function Fo(t){return t.c||(t.c=t.b())}function qo(){}function Ho(t){if(t.f||"undefined"!=typeof XMLHttpRequest||"undefined"==typeof ActiveXObject)return t.f;for(var e=["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],n=0;n=function t(e){return e.c||(e.a?t(e.a):(D("Root logger has no level set."),null))}(this).value)for(v(e)&&(e=e()),t=new Wo(t,String(e),this.f),n&&(t.a=n),n=this;n;)n=n.a};var Qo,ta={},ea=null;function na(t){var e,n,i;return ea||(ea=new Xo(""),(ta[""]=ea).c=$o),(e=ta[t])||(e=new Xo(t),i=t.lastIndexOf("."),n=t.substr(i+1),(i=na(t.substr(0,i))).b||(i.b={}),(i.b[n]=e).a=i,ta[t]=e),e}function ia(t,e){t&&t.log(Zo,e,void 0)}function ra(t){this.f=t}function oa(t){fn.call(this),this.u=t,this.h=void 0,this.readyState=aa,this.status=0,this.responseType=this.responseText=this.response=this.statusText="",this.onreadystatechange=null,this.l=new Headers,this.b=null,this.s="GET",this.f="",this.a=!1,this.i=na("goog.net.FetchXmlHttp"),this.m=this.c=this.g=null}w(ra,Vo),ra.prototype.a=function(){return new oa(this.f)},ra.prototype.b=(Qo={},function(){return Qo}),w(oa,fn);var aa=0;function sa(t){t.c.read().then(t.pc.bind(t)).catch(t.Va.bind(t))}function ua(t){t.readyState=4,t.g=null,t.c=null,t.m=null,ca(t)}function ca(t){t.onreadystatechange&&t.onreadystatechange.call(t)}function ha(t){fn.call(this),this.headers=new wn,this.D=t||null,this.c=!1,this.C=this.a=null,this.h=this.P=this.l="",this.f=this.N=this.i=this.J=!1,this.g=0,this.s=null,this.m=la,this.u=this.S=!1}(t=oa.prototype).open=function(t,e){if(this.readyState!=aa)throw this.abort(),Error("Error reopening a connection");this.s=t,this.f=e,this.readyState=1,ca(this)},t.send=function(t){if(1!=this.readyState)throw this.abort(),Error("need to call open() first. ");this.a=!0;var e={headers:this.l,method:this.s,credentials:this.h,cache:void 0};t&&(e.body=t),this.u.fetch(new Request(this.f,e)).then(this.uc.bind(this),this.Va.bind(this))},t.abort=function(){this.response=this.responseText="",this.l=new Headers,this.status=0,this.c&&this.c.cancel("Request was aborted."),1<=this.readyState&&this.a&&4!=this.readyState&&(this.a=!1,ua(this)),this.readyState=aa},t.uc=function(t){this.a&&(this.g=t,this.b||(this.status=this.g.status,this.statusText=this.g.statusText,this.b=t.headers,this.readyState=2,ca(this)),this.a&&(this.readyState=3,ca(this),this.a&&("arraybuffer"===this.responseType?t.arrayBuffer().then(this.sc.bind(this),this.Va.bind(this)):void 0!==l.ReadableStream&&"body"in t?(this.response=this.responseText="",this.c=t.body.getReader(),this.m=new TextDecoder,sa(this)):t.text().then(this.tc.bind(this),this.Va.bind(this)))))},t.pc=function(t){var e;this.a&&((e=this.m.decode(t.value||new Uint8Array(0),{stream:!t.done}))&&(this.response=this.responseText+=e),(t.done?ua:ca)(this),3==this.readyState&&sa(this))},t.tc=function(t){this.a&&(this.response=this.responseText=t,ua(this))},t.sc=function(t){this.a&&(this.response=t,ua(this))},t.Va=function(t){var e=this.i;e&&e.log(zo,"Failed to fetch url "+this.f,t instanceof Error?t:Error(t)),this.a&&ua(this)},t.setRequestHeader=function(t,e){this.l.append(t,e)},t.getResponseHeader=function(t){return this.b?this.b.get(t.toLowerCase())||"":((t=this.i)&&t.log(zo,"Attempting to get response header but no headers have been received for url: "+this.f,void 0),"")},t.getAllResponseHeaders=function(){if(!this.b){var t=this.i;return t&&t.log(zo,"Attempting to get all response headers but no headers have been received for url: "+this.f,void 0),""}for(var t=[],e=this.b.entries(),n=e.next();!n.done;)n=n.value,t.push(n[0]+": "+n[1]),n=e.next();return t.join("\r\n")},Object.defineProperty(oa.prototype,"withCredentials",{get:function(){return"include"===this.h},set:function(t){this.h=t?"include":"same-origin"}}),w(ha,fn);var la="";ha.prototype.b=na("goog.net.XhrIo");var fa=/^https?$/i,da=["POST","PUT"];function pa(e,t,n,i,r){if(e.a)throw Error("[goog.net.XhrIo] Object is active with another request="+e.l+"; newUri="+t);n=n?n.toUpperCase():"GET",e.l=t,e.h="",e.P=n,e.J=!1,e.c=!0,e.a=(e.D||Lo).a(),e.C=e.D?Fo(e.D):Fo(Lo),e.a.onreadystatechange=b(e.Wb,e);try{ia(e.b,Ea(e,"Opening Xhr")),e.N=!0,e.a.open(n,String(t),!0),e.N=!1}catch(t){return ia(e.b,Ea(e,"Error opening Xhr: "+t.message)),void ma(e,t)}t=i||"";var o,a=new wn(e.headers);r&&function(t,e){if(t.forEach&&"function"==typeof t.forEach)t.forEach(e,void 0);else if(p(t)||"string"==typeof t)V(t,e,void 0);else for(var n=yn(t),i=bn(t),r=i.length,o=0;o>>7|r<<25)^(r>>>18|r<<14)^r>>>3)|0,a=(0|n[e-7])+((i>>>17|i<<15)^(i>>>19|i<<13)^i>>>10)|0;n[e]=o+a|0}i=0|t.a[0],r=0|t.a[1];var s=0|t.a[2],u=0|t.a[3],c=0|t.a[4],h=0|t.a[5],l=0|t.a[6];for(o=0|t.a[7],e=0;e<64;e++){var f=((i>>>2|i<<30)^(i>>>13|i<<19)^(i>>>22|i<<10))+(i&r^i&s^r&s)|0;a=(o=o+((c>>>6|c<<26)^(c>>>11|c<<21)^(c>>>25|c<<7))|0)+((a=(a=c&h^~c&l)+(0|Zu[e])|0)+(0|n[e])|0)|0,o=l,l=h,h=c,c=u+a|0,u=s,s=r,r=i,i=a+f|0}t.a[0]=t.a[0]+i|0,t.a[1]=t.a[1]+r|0,t.a[2]=t.a[2]+s|0,t.a[3]=t.a[3]+u|0,t.a[4]=t.a[4]+c|0,t.a[5]=t.a[5]+h|0,t.a[6]=t.a[6]+l|0,t.a[7]=t.a[7]+o|0}function uc(t,e,n){void 0===n&&(n=e.length);var i=0,r=t.c;if("string"==typeof e)for(;i>r&255;return q(t,function(t){return 1<(t=t.toString(16)).length?t:"0"+t}).join("")}function vc(t,e){for(var n=0;nt.f&&(t.a=t.f),e)}function oh(t){this.f=t,this.b=this.a=null,this.c=Date.now()}function ah(t,e){void 0===e&&(e=t.b?(e=t.b).a-e.g:0),t.c=Date.now()+1e3*e}function sh(t,e){t.b=Lr(e[Ka]||""),t.a=e.refreshToken,ah(t,void 0!==(e=e.expiresIn)?Number(e):void 0)}function uh(e,t){return i=e.f,r=t,new fe(function(e,n){"refresh_token"==r.grant_type&&r.refresh_token||"authorization_code"==r.grant_type&&r.code?Za(i,i.l+"?key="+encodeURIComponent(i.c),function(t){t?t.error?n(zs(t)):t.access_token&&t.refresh_token?e(t):n(new T("internal-error")):n(new T("network-request-failed"))},"POST",Hn(r).toString(),i.g,i.m.get()):n(new T("internal-error"))}).then(function(t){return e.b=Lr(t.access_token),e.a=t.refresh_token,ah(e,t.expires_in),{accessToken:e.b.toString(),refreshToken:e.a}}).o(function(t){throw"auth/user-token-expired"==t.code&&(e.a=null),t});var i,r}function ch(t,e){this.a=t||null,this.b=e||null,qi(this,{lastSignInTime:Li(e||null),creationTime:Li(t||null)})}function hh(t,e,n,i,r,o){qi(this,{uid:t,displayName:i||null,photoURL:r||null,email:n||null,phoneNumber:o||null,providerId:e})}function lh(t,e,n){this.N=[],this.l=t.apiKey,this.m=t.appName,this.s=t.authDomain||null;var i,r=Zl.default.SDK_VERSION?gi(Zl.default.SDK_VERSION):null;this.a=new qa(this.l,_(A),r),(this.u=t.emulatorConfig||null)&&Ya(this.a,this.u),this.h=new oh(this.a),wh(this,e[Ka]),sh(this.h,e),Fi(this,"refreshToken",this.h.a),Eh(this,n||{}),fn.call(this),this.P=!1,this.s&&Ii()&&(this.b=xc(this.s,this.l,this.m,this.u)),this.W=[],this.i=null,this.D=(i=this,new ih(function(){return i.I(!0)},function(t){return!(!t||"auth/network-request-failed"!=t.code)},function(){var t=i.h.c-Date.now()-3e5;return 0this.c-3e4?this.a?uh(this,{grant_type:"refresh_token",refresh_token:this.a}):ye(null):ye({accessToken:this.b.toString(),refreshToken:this.a})},ch.prototype.w=function(){return{lastLoginAt:this.b,createdAt:this.a}},w(lh,fn),lh.prototype.xa=function(t){this.za=t,Ja(this.a,t)},lh.prototype.la=function(){return this.za},lh.prototype.Ga=function(){return X(this.aa)},lh.prototype.ib=function(){this.D.b&&(this.D.stop(),this.D.start())},Fi(lh.prototype,"providerId","firebase"),(t=lh.prototype).reload=function(){var t=this;return Vh(this,kh(this).then(function(){return Rh(t).then(function(){return Ih(t)}).then(Ah)}))},t.oc=function(t){return this.I(t).then(function(t){return new Bc(t)})},t.I=function(t){var e=this;return Vh(this,kh(this).then(function(){return e.h.getToken(t)}).then(function(t){if(!t)throw new T("internal-error");return t.accessToken!=e.Aa&&(wh(e,t.accessToken),e.dispatchEvent(new th("tokenChanged"))),Oh(e,"refreshToken",t.refreshToken),t.accessToken}))},t.Kc=function(t){if(!(t=t.users)||!t.length)throw new T("internal-error");Eh(this,{uid:(t=t[0]).localId,displayName:t.displayName,photoURL:t.photoUrl,email:t.email,emailVerified:!!t.emailVerified,phoneNumber:t.phoneNumber,lastLoginAt:t.lastLoginAt,createdAt:t.createdAt,tenantId:t.tenantId});for(var e,n=(e=(e=t).providerUserInfo)&&e.length?q(e,function(t){return new hh(t.rawId,t.providerId,t.email,t.displayName,t.photoUrl,t.phoneNumber)}):[],i=0;i=xl.length)throw new T("internal-error","Argument validator received an unsupported number of arguments.");n=xl[r],i=(i?"":n+" argument ")+(e.name?'"'+e.name+'" ':"")+"must be "+e.K+".";break t}i=null}}if(i)throw new T("argument-error",t+" failed: "+i)}(t=kl.prototype).Ia=function(){var e=this;return this.f||(this.f=Rl(this,ye().then(function(){if(Ti()&&!hi())return si();throw new T("operation-not-supported-in-this-environment","RecaptchaVerifier is only supported in a browser HTTP/HTTPS environment.")}).then(function(){return e.m.g(e.u())}).then(function(t){return e.g=t,Js(e.s,Rs,{})}).then(function(t){e.a[_l]=t.recaptchaSiteKey}).o(function(t){throw e.f=null,t})))},t.render=function(){Dl(this);var n=this;return Rl(this,this.Ia().then(function(){var t,e;return null===n.c&&(e=n.v,n.i||(t=te(e),e=oe("DIV"),t.appendChild(e)),n.c=n.g.render(e,n.a)),n.c}))},t.verify=function(){Dl(this);var r=this;return Rl(this,this.render().then(function(e){return new fe(function(n){var i,t=r.g.getResponse(e);t?n(t):(r.l.push(i=function(t){var e;t&&(e=i,B(r.l,function(t){return t==e}),n(t))}),r.i&&r.g.execute(r.c))})}))},t.reset=function(){Dl(this),null!==this.c&&this.g.reset(this.c)},t.clear=function(){Dl(this),this.J=!0,this.m.c();for(var t,e=0;es[0]&&e[1]>6|192:(55296==(64512&i)&&r+1>18|240,e[n++]=i>>12&63|128):e[n++]=i>>12|224,e[n++]=i>>6&63|128),e[n++]=63&i|128)}return e}function u(t){return function(t){t=i(t);return o.encodeByteArray(t,!0)}(t).replace(/\./g,"")}var o={byteToCharMap_:null,charToByteMap_:null,byteToCharMapWebSafe_:null,charToByteMapWebSafe_:null,ENCODED_VALS_BASE:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",get ENCODED_VALS(){return this.ENCODED_VALS_BASE+"+/="},get ENCODED_VALS_WEBSAFE(){return this.ENCODED_VALS_BASE+"-_."},HAS_NATIVE_SUPPORT:"function"==typeof atob,encodeByteArray:function(t,e){if(!Array.isArray(t))throw Error("encodeByteArray takes an array as a parameter");this.init_();for(var n=e?this.byteToCharMapWebSafe_:this.byteToCharMap_,r=[],i=0;i>6,c=63&c;u||(c=64,s||(h=64)),r.push(n[o>>2],n[(3&o)<<4|a>>4],n[h],n[c])}return r.join("")},encodeString:function(t,e){return this.HAS_NATIVE_SUPPORT&&!e?btoa(t):this.encodeByteArray(i(t),e)},decodeString:function(t,e){return this.HAS_NATIVE_SUPPORT&&!e?atob(t):function(t){for(var e=[],n=0,r=0;n>10)),e[r++]=String.fromCharCode(56320+(1023&i))):(o=t[n++],s=t[n++],e[r++]=String.fromCharCode((15&a)<<12|(63&o)<<6|63&s))}return e.join("")}(this.decodeStringToByteArray(t,e))},decodeStringToByteArray:function(t,e){this.init_();for(var n=e?this.charToByteMapWebSafe_:this.charToByteMap_,r=[],i=0;i>4),64!==a&&(r.push(s<<4&240|a>>2),64!==u&&r.push(a<<6&192|u))}return r},init_:function(){if(!this.byteToCharMap_){this.byteToCharMap_={},this.charToByteMap_={},this.byteToCharMapWebSafe_={},this.charToByteMapWebSafe_={};for(var t=0;t=this.ENCODED_VALS_BASE.length&&(this.charToByteMap_[this.ENCODED_VALS_WEBSAFE.charAt(t)]=t,this.charToByteMapWebSafe_[this.ENCODED_VALS.charAt(t)]=t)}}};function h(){return"undefined"!=typeof navigator&&"string"==typeof navigator.userAgent?navigator.userAgent:""}function c(){return!function(){try{return"[object process]"===Object.prototype.toString.call(global.process)}catch(t){return}}()&&navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome")}var l,f="FirebaseError",d=(n(p,l=Error),p);function p(t,e,n){e=l.call(this,e)||this;return e.code=t,e.customData=n,e.name=f,Object.setPrototypeOf(e,p.prototype),Error.captureStackTrace&&Error.captureStackTrace(e,m.prototype.create),e}var m=(v.prototype.create=function(t){for(var e=[],n=1;n"})):"Error",t=this.serviceName+": "+t+" ("+o+").";return new d(o,t,i)},v);function v(t,e,n){this.service=t,this.serviceName=e,this.errors=n}var w,b=/\{\$([^}]+)}/g;function E(t){return t&&t._delegate?t._delegate:t}(k=w=w||{})[k.DEBUG=0]="DEBUG",k[k.VERBOSE=1]="VERBOSE",k[k.INFO=2]="INFO",k[k.WARN=3]="WARN",k[k.ERROR=4]="ERROR",k[k.SILENT=5]="SILENT";function T(t,e){for(var n=[],r=2;r=t.length?void 0:t)&&t[r++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")}var k,R="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},x={},O=R||self;function L(){}function P(t){var e=typeof t;return"array"==(e="object"!=e?e:t?Array.isArray(t)?"array":e:"null")||"object"==e&&"number"==typeof t.length}function M(t){var e=typeof t;return"object"==e&&null!=t||"function"==e}var F="closure_uid_"+(1e9*Math.random()>>>0),V=0;function U(t,e,n){return t.call.apply(t.bind,arguments)}function q(e,n,t){if(!e)throw Error();if(2parseFloat(yt)){at=String(gt);break t}}at=yt}var mt={};function vt(){return t=function(){for(var t=0,e=J(String(at)).split("."),n=J("9").split("."),r=Math.max(e.length,n.length),i=0;0==t&&i>>0);function qt(e){return"function"==typeof e?e:(e[Ut]||(e[Ut]=function(t){return e.handleEvent(t)}),e[Ut])}function Bt(){G.call(this),this.i=new Nt(this),(this.P=this).I=null}function jt(t,e){var n,r=t.I;if(r)for(n=[];r;r=r.I)n.push(r);if(t=t.P,r=e.type||e,"string"==typeof e?e=new Et(e,t):e instanceof Et?e.target=e.target||t:(s=e,ot(e=new Et(r,t),s)),s=!0,n)for(var i=n.length-1;0<=i;i--)var o=e.g=n[i],s=Kt(o,r,!0,e)&&s;if(s=Kt(o=e.g=t,r,!0,e)&&s,s=Kt(o,r,!1,e)&&s,n)for(i=0;io.length?Pe:(o=o.substr(a,s),i.C=a+s,o)))==Pe){4==e&&(t.o=4,be(14),u=!1),de(t.j,t.m,null,"[Incomplete Response]");break}if(r==Le){t.o=4,be(15),de(t.j,t.m,n,"[Invalid Chunk]"),u=!1;break}de(t.j,t.m,r,null),Qe(t,r)}Ve(t)&&r!=Pe&&r!=Le&&(t.h.g="",t.C=0),4!=e||0!=n.length||t.h.h||(t.o=1,be(16),u=!1),t.i=t.i&&u,u?0>4&15).toString(16)+(15&t).toString(16)}$e.prototype.toString=function(){var t=[],e=this.j;e&&t.push(an(e,cn,!0),":");var n=this.i;return!n&&"file"!=e||(t.push("//"),(e=this.s)&&t.push(an(e,cn,!0),"@"),t.push(encodeURIComponent(String(n)).replace(/%25([0-9a-fA-F]{2})/g,"%$1")),null!=(n=this.m)&&t.push(":",String(n))),(n=this.l)&&(this.i&&"/"!=n.charAt(0)&&t.push("/"),t.push(an(n,"/"==n.charAt(0)?ln:hn,!0))),(n=this.h.toString())&&t.push("?",n),(n=this.o)&&t.push("#",an(n,dn)),t.join("")};var cn=/[#\/\?@]/g,hn=/[#\?:]/g,ln=/[#\?]/g,fn=/[#\?@]/g,dn=/#/g;function pn(t,e){this.h=this.g=null,this.i=t||null,this.j=!!e}function yn(n){n.g||(n.g=new ze,n.h=0,n.i&&function(t,e){if(t){t=t.split("&");for(var n=0;n2*t.i&&We(t)))}function mn(t,e){return yn(t),e=wn(t,e),Ye(t.g.h,e)}function vn(t,e,n){gn(t,e),0=t.j}function Sn(t){return t.h?1:t.g?t.g.size:0}function An(t,e){return t.h?t.h==e:t.g&&t.g.has(e)}function Dn(t,e){t.g?t.g.add(e):t.h=e}function Nn(t,e){t.h&&t.h==e?t.h=null:t.g&&t.g.has(e)&&t.g.delete(e)}function Cn(t){var e,n;if(null!=t.h)return t.i.concat(t.h.D);if(null==t.g||0===t.g.size)return Y(t.i);var r=t.i;try{for(var i=C(t.g.values()),o=i.next();!o.done;o=i.next())var s=o.value,r=r.concat(s.D)}catch(t){e={error:t}}finally{try{o&&!o.done&&(n=i.return)&&n.call(i)}finally{if(e)throw e.error}}return r}function kn(){}function Rn(){this.g=new kn}function xn(t,e,n,r,i){try{e.onload=null,e.onerror=null,e.onabort=null,e.ontimeout=null,i(r)}catch(t){}}function On(t){this.l=t.$b||null,this.j=t.ib||!1}function Ln(t,e){Bt.call(this),this.D=t,this.u=e,this.m=void 0,this.readyState=Pn,this.status=0,this.responseType=this.responseText=this.response=this.statusText="",this.onreadystatechange=null,this.v=new Headers,this.h=null,this.C="GET",this.B="",this.g=!1,this.A=this.j=this.l=null}En.prototype.cancel=function(){var e,t;if(this.i=Cn(this),this.h)this.h.cancel(),this.h=null;else if(this.g&&0!==this.g.size){try{for(var n=C(this.g.values()),r=n.next();!r.done;r=n.next())r.value.cancel()}catch(t){e={error:t}}finally{try{r&&!r.done&&(t=n.return)&&t.call(n)}finally{if(e)throw e.error}}this.g.clear()}},kn.prototype.stringify=function(t){return O.JSON.stringify(t,void 0)},kn.prototype.parse=function(t){return O.JSON.parse(t,void 0)},K(On,_e),On.prototype.g=function(){return new Ln(this.l,this.j)},On.prototype.i=(Tn={},function(){return Tn}),K(Ln,Bt);var Pn=0;function Mn(t){t.j.read().then(t.Sa.bind(t)).catch(t.ha.bind(t))}function Fn(t){t.readyState=4,t.l=null,t.j=null,t.A=null,Vn(t)}function Vn(t){t.onreadystatechange&&t.onreadystatechange.call(t)}(k=Ln.prototype).open=function(t,e){if(this.readyState!=Pn)throw this.abort(),Error("Error reopening a connection");this.C=t,this.B=e,this.readyState=1,Vn(this)},k.send=function(t){if(1!=this.readyState)throw this.abort(),Error("need to call open() first. ");this.g=!0;var e={headers:this.v,method:this.C,credentials:this.m,cache:void 0};t&&(e.body=t),(this.D||O).fetch(new Request(this.B,e)).then(this.Va.bind(this),this.ha.bind(this))},k.abort=function(){this.response=this.responseText="",this.v=new Headers,this.status=0,this.j&&this.j.cancel("Request was aborted."),1<=this.readyState&&this.g&&4!=this.readyState&&(this.g=!1,Fn(this)),this.readyState=Pn},k.Va=function(t){if(this.g&&(this.l=t,this.h||(this.status=this.l.status,this.statusText=this.l.statusText,this.h=t.headers,this.readyState=2,Vn(this)),this.g&&(this.readyState=3,Vn(this),this.g)))if("arraybuffer"===this.responseType)t.arrayBuffer().then(this.Ta.bind(this),this.ha.bind(this));else if(void 0!==O.ReadableStream&&"body"in t){if(this.j=t.body.getReader(),this.u){if(this.responseType)throw Error('responseType must be empty for "streamBinaryChunks" mode responses.');this.response=[]}else this.response=this.responseText="",this.A=new TextDecoder;Mn(this)}else t.text().then(this.Ua.bind(this),this.ha.bind(this))},k.Sa=function(t){var e;this.g&&(this.u&&t.value?this.response.push(t.value):this.u||(e=t.value||new Uint8Array(0),(e=this.A.decode(e,{stream:!t.done}))&&(this.response=this.responseText+=e)),(t.done?Fn:Vn)(this),3==this.readyState&&Mn(this))},k.Ua=function(t){this.g&&(this.response=this.responseText=t,Fn(this))},k.Ta=function(t){this.g&&(this.response=t,Fn(this))},k.ha=function(){this.g&&Fn(this)},k.setRequestHeader=function(t,e){this.v.append(t,e)},k.getResponseHeader=function(t){return this.h&&this.h.get(t.toLowerCase())||""},k.getAllResponseHeaders=function(){if(!this.h)return"";for(var t=[],e=this.h.entries(),n=e.next();!n.done;)n=n.value,t.push(n[0]+": "+n[1]),n=e.next();return t.join("\r\n")},Object.defineProperty(Ln.prototype,"withCredentials",{get:function(){return"include"===this.m},set:function(t){this.m=t?"include":"same-origin"}});var Un=O.JSON.parse;function qn(t){Bt.call(this),this.headers=new ze,this.u=t||null,this.h=!1,this.C=this.g=null,this.H="",this.m=0,this.j="",this.l=this.F=this.v=this.D=!1,this.B=0,this.A=null,this.J=Bn,this.K=this.L=!1}K(qn,Bt);var Bn="",jn=/^https?$/i,Kn=["POST","PUT"];function Gn(t){return"content-type"==t.toLowerCase()}function Qn(t,e){t.h=!1,t.g&&(t.l=!0,t.g.abort(),t.l=!1),t.j=e,t.m=5,Hn(t),Wn(t)}function Hn(t){t.D||(t.D=!0,jt(t,"complete"),jt(t,"error"))}function zn(t){if(t.h&&void 0!==x&&(!t.C[1]||4!=Xn(t)||2!=t.ba()))if(t.v&&4==Xn(t))ie(t.Fa,0,t);else if(jt(t,"readystatechange"),4==Xn(t)){t.h=!1;try{var e,n,r,i,o=t.ba();t:switch(o){case 200:case 201:case 202:case 204:case 206:case 304:case 1223:var s=!0;break t;default:s=!1}if((e=s)||((n=0===o)&&(!(i=String(t.H).match(Xe)[1]||null)&&O.self&&O.self.location&&(i=(r=O.self.location.protocol).substr(0,r.length-1)),n=!jn.test(i?i.toLowerCase():"")),e=n),e)jt(t,"complete"),jt(t,"success");else{t.m=6;try{var a=2=r.i.j-(r.m?1:0)||(r.m?(r.l=i.D.concat(r.l),0):1==r.G||2==r.G||r.C>=(r.Xa?0:r.Ya)||(r.m=Te(B(r.Ha,r,i),yr(r,r.C)),r.C++,0))))&&(2!=s||!hr(t)))switch(o&&0e.length?1:0},vi),ci=(n(mi,ui=R),mi.prototype.construct=function(t,e,n){return new mi(t,e,n)},mi.prototype.canonicalString=function(){return this.toArray().join("/")},mi.prototype.toString=function(){return this.canonicalString()},mi.fromString=function(){for(var t=[],e=0;et.length&&zr(),void 0===n?n=t.length-e:n>t.length-e&&zr(),this.segments=t,this.offset=e,this.len=n}di.EMPTY_BYTE_STRING=new di("");var wi=new RegExp(/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(?:\.(\d+))?Z$/);function bi(t){if(Wr(!!t),"string"!=typeof t)return{seconds:Ei(t.seconds),nanos:Ei(t.nanos)};var e=0,n=wi.exec(t);Wr(!!n),n[1]&&(n=((n=n[1])+"000000000").substr(0,9),e=Number(n));t=new Date(t);return{seconds:Math.floor(t.getTime()/1e3),nanos:e}}function Ei(t){return"number"==typeof t?t:"string"==typeof t?Number(t):0}function Ti(t){return"string"==typeof t?di.fromBase64String(t):di.fromUint8Array(t)}function Ii(t){return"server_timestamp"===(null===(t=((null===(t=null==t?void 0:t.mapValue)||void 0===t?void 0:t.fields)||{}).__type__)||void 0===t?void 0:t.stringValue)}function _i(t){t=bi(t.mapValue.fields.__local_write_time__.timestampValue);return new ti(t.seconds,t.nanos)}function Si(t){return null==t}function Ai(t){return 0===t&&1/t==-1/0}function Di(t){return"number"==typeof t&&Number.isInteger(t)&&!Ai(t)&&t<=Number.MAX_SAFE_INTEGER&&t>=Number.MIN_SAFE_INTEGER}var Ni=(Ci.fromPath=function(t){return new Ci(ci.fromString(t))},Ci.fromName=function(t){return new Ci(ci.fromString(t).popFirst(5))},Ci.prototype.hasCollectionId=function(t){return 2<=this.path.length&&this.path.get(this.path.length-2)===t},Ci.prototype.isEqual=function(t){return null!==t&&0===ci.comparator(this.path,t.path)},Ci.prototype.toString=function(){return this.path.toString()},Ci.comparator=function(t,e){return ci.comparator(t.path,e.path)},Ci.isDocumentKey=function(t){return t.length%2==0},Ci.fromSegments=function(t){return new Ci(new ci(t.slice()))},Ci);function Ci(t){this.path=t}function ki(t){return"nullValue"in t?0:"booleanValue"in t?1:"integerValue"in t||"doubleValue"in t?2:"timestampValue"in t?3:"stringValue"in t?5:"bytesValue"in t?6:"referenceValue"in t?7:"geoPointValue"in t?8:"arrayValue"in t?9:"mapValue"in t?Ii(t)?4:10:zr()}function Ri(r,i){var t,e,n=ki(r);if(n!==ki(i))return!1;switch(n){case 0:return!0;case 1:return r.booleanValue===i.booleanValue;case 4:return _i(r).isEqual(_i(i));case 3:return function(t){if("string"==typeof r.timestampValue&&"string"==typeof t.timestampValue&&r.timestampValue.length===t.timestampValue.length)return r.timestampValue===t.timestampValue;var e=bi(r.timestampValue),t=bi(t.timestampValue);return e.seconds===t.seconds&&e.nanos===t.nanos}(i);case 5:return r.stringValue===i.stringValue;case 6:return e=i,Ti(r.bytesValue).isEqual(Ti(e.bytesValue));case 7:return r.referenceValue===i.referenceValue;case 8:return t=i,Ei((e=r).geoPointValue.latitude)===Ei(t.geoPointValue.latitude)&&Ei(e.geoPointValue.longitude)===Ei(t.geoPointValue.longitude);case 2:return function(t,e){if("integerValue"in t&&"integerValue"in e)return Ei(t.integerValue)===Ei(e.integerValue);if("doubleValue"in t&&"doubleValue"in e){t=Ei(t.doubleValue),e=Ei(e.doubleValue);return t===e?Ai(t)===Ai(e):isNaN(t)&&isNaN(e)}return!1}(r,i);case 9:return Jr(r.arrayValue.values||[],i.arrayValue.values||[],Ri);case 10:return function(){var t,e=r.mapValue.fields||{},n=i.mapValue.fields||{};if(ii(e)!==ii(n))return!1;for(t in e)if(e.hasOwnProperty(t)&&(void 0===n[t]||!Ri(e[t],n[t])))return!1;return!0}();default:return zr()}}function xi(t,e){return void 0!==(t.values||[]).find(function(t){return Ri(t,e)})}function Oi(t,e){var n,r,i,o=ki(t),s=ki(e);if(o!==s)return $r(o,s);switch(o){case 0:return 0;case 1:return $r(t.booleanValue,e.booleanValue);case 2:return r=e,i=Ei(t.integerValue||t.doubleValue),r=Ei(r.integerValue||r.doubleValue),i":return 0=":return 0<=t;default:return zr()}},to.prototype.g=function(){return 0<=["<","<=",">",">=","!=","not-in"].indexOf(this.op)},to);function to(t,e,n){var r=this;return(r=Ji.call(this)||this).field=t,r.op=e,r.value=n,r}var eo,no,ro,io=(n(co,ro=Zi),co.prototype.matches=function(t){t=Ni.comparator(t.key,this.key);return this.m(t)},co),oo=(n(uo,no=Zi),uo.prototype.matches=function(e){return this.keys.some(function(t){return t.isEqual(e.key)})},uo),so=(n(ao,eo=Zi),ao.prototype.matches=function(e){return!this.keys.some(function(t){return t.isEqual(e.key)})},ao);function ao(t,e){var n=this;return(n=eo.call(this,t,"not-in",e)||this).keys=ho(0,e),n}function uo(t,e){var n=this;return(n=no.call(this,t,"in",e)||this).keys=ho(0,e),n}function co(t,e,n){var r=this;return(r=ro.call(this,t,e,n)||this).key=Ni.fromName(n.referenceValue),r}function ho(t,e){return((null===(e=e.arrayValue)||void 0===e?void 0:e.values)||[]).map(function(t){return Ni.fromName(t.referenceValue)})}var lo,fo,po,yo,go=(n(_o,yo=Zi),_o.prototype.matches=function(t){t=t.data.field(this.field);return Vi(t)&&xi(t.arrayValue,this.value)},_o),mo=(n(Io,po=Zi),Io.prototype.matches=function(t){t=t.data.field(this.field);return null!==t&&xi(this.value.arrayValue,t)},Io),vo=(n(To,fo=Zi),To.prototype.matches=function(t){if(xi(this.value.arrayValue,{nullValue:"NULL_VALUE"}))return!1;t=t.data.field(this.field);return null!==t&&!xi(this.value.arrayValue,t)},To),wo=(n(Eo,lo=Zi),Eo.prototype.matches=function(t){var e=this,t=t.data.field(this.field);return!(!Vi(t)||!t.arrayValue.values)&&t.arrayValue.values.some(function(t){return xi(e.value.arrayValue,t)})},Eo),bo=function(t,e){this.position=t,this.before=e};function Eo(t,e){return lo.call(this,t,"array-contains-any",e)||this}function To(t,e){return fo.call(this,t,"not-in",e)||this}function Io(t,e){return po.call(this,t,"in",e)||this}function _o(t,e){return yo.call(this,t,"array-contains",e)||this}function So(t){return(t.before?"b":"a")+":"+t.position.map(Pi).join(",")}var Ao=function(t,e){void 0===e&&(e="asc"),this.field=t,this.dir=e};function Do(t,e,n){for(var r=0,i=0;i":"GREATER_THAN",">=":"GREATER_THAN_OR_EQUAL","==":"EQUAL","!=":"NOT_EQUAL","array-contains":"ARRAY_CONTAINS",in:"IN","not-in":"NOT_IN","array-contains-any":"ARRAY_CONTAINS_ANY"},ga=function(t,e){this.databaseId=t,this.I=e};function ma(t,e){return t.I?new Date(1e3*e.seconds).toISOString().replace(/\.\d*/,"").replace("Z","")+"."+("000000000"+e.nanoseconds).slice(-9)+"Z":{seconds:""+e.seconds,nanos:e.nanoseconds}}function va(t,e){return t.I?e.toBase64():e.toUint8Array()}function wa(t){return Wr(!!t),ei.fromTimestamp((t=bi(t),new ti(t.seconds,t.nanos)))}function ba(t,e){return new ci(["projects",t.projectId,"databases",t.database]).child("documents").child(e).canonicalString()}function Ea(t){t=ci.fromString(t);return Wr(Ba(t)),t}function Ta(t,e){return ba(t.databaseId,e.path)}function Ia(t,e){e=Ea(e);if(e.get(1)!==t.databaseId.projectId)throw new Ur(Vr.INVALID_ARGUMENT,"Tried to deserialize key from different project: "+e.get(1)+" vs "+t.databaseId.projectId);if(e.get(3)!==t.databaseId.database)throw new Ur(Vr.INVALID_ARGUMENT,"Tried to deserialize key from different database: "+e.get(3)+" vs "+t.databaseId.database);return new Ni(Da(e))}function _a(t,e){return ba(t.databaseId,e)}function Sa(t){t=Ea(t);return 4===t.length?ci.emptyPath():Da(t)}function Aa(t){return new ci(["projects",t.databaseId.projectId,"databases",t.databaseId.database]).canonicalString()}function Da(t){return Wr(4";case"GREATER_THAN_OR_EQUAL":return">=";case"LESS_THAN":return"<";case"LESS_THAN_OR_EQUAL":return"<=";case"ARRAY_CONTAINS":return"array-contains";case"IN":return"in";case"NOT_IN":return"not-in";case"ARRAY_CONTAINS_ANY":return"array-contains-any";case"OPERATOR_UNSPECIFIED":default:return zr()}}(),t.fieldFilter.value)}function qa(t){switch(t.unaryFilter.op){case"IS_NAN":var e=Va(t.unaryFilter.field);return Zi.create(e,"==",{doubleValue:NaN});case"IS_NULL":e=Va(t.unaryFilter.field);return Zi.create(e,"==",{nullValue:"NULL_VALUE"});case"IS_NOT_NAN":var n=Va(t.unaryFilter.field);return Zi.create(n,"!=",{doubleValue:NaN});case"IS_NOT_NULL":n=Va(t.unaryFilter.field);return Zi.create(n,"!=",{nullValue:"NULL_VALUE"});case"OPERATOR_UNSPECIFIED":default:return zr()}}function Ba(t){return 4<=t.length&&"projects"===t.get(0)&&"databases"===t.get(2)}function ja(t){for(var e="",n=0;n",t),this.store.put(t));return Au(t)},Su.prototype.add=function(t){return Kr("SimpleDb","ADD",this.store.name,t,t),Au(this.store.add(t))},Su.prototype.get=function(e){var n=this;return Au(this.store.get(e)).next(function(t){return Kr("SimpleDb","GET",n.store.name,e,t=void 0===t?null:t),t})},Su.prototype.delete=function(t){return Kr("SimpleDb","DELETE",this.store.name,t),Au(this.store.delete(t))},Su.prototype.count=function(){return Kr("SimpleDb","COUNT",this.store.name),Au(this.store.count())},Su.prototype.Nt=function(t,e){var e=this.cursor(this.options(t,e)),n=[];return this.xt(e,function(t,e){n.push(e)}).next(function(){return n})},Su.prototype.kt=function(t,e){Kr("SimpleDb","DELETE ALL",this.store.name);e=this.options(t,e);e.Ft=!1;e=this.cursor(e);return this.xt(e,function(t,e,n){return n.delete()})},Su.prototype.$t=function(t,e){e?n=t:(n={},e=t);var n=this.cursor(n);return this.xt(n,e)},Su.prototype.Ot=function(r){var t=this.cursor({});return new fu(function(n,e){t.onerror=function(t){t=Nu(t.target.error);e(t)},t.onsuccess=function(t){var e=t.target.result;e?r(e.primaryKey,e.value).next(function(t){t?e.continue():n()}):n()}})},Su.prototype.xt=function(t,i){var o=[];return new fu(function(r,e){t.onerror=function(t){e(t.target.error)},t.onsuccess=function(t){var e,n=t.target.result;n?(e=new yu(n),(t=i(n.primaryKey,n.value,e))instanceof fu&&(t=t.catch(function(t){return e.done(),fu.reject(t)}),o.push(t)),e.isDone?r():null===e.Dt?n.continue():n.continue(e.Dt)):r()}}).next(function(){return fu.waitFor(o)})},Su.prototype.options=function(t,e){var n;return void 0!==t&&("string"==typeof t?n=t:e=t),{index:n,range:e}},Su.prototype.cursor=function(t){var e="next";if(t.reverse&&(e="prev"),t.index){var n=this.store.index(t.index);return t.Ft?n.openKeyCursor(t.range,e):n.openCursor(t.range,e)}return this.store.openCursor(t.range,e)},Su);function Su(t){this.store=t}function Au(t){return new fu(function(e,n){t.onsuccess=function(t){t=t.target.result;e(t)},t.onerror=function(t){t=Nu(t.target.error);n(t)}})}var Du=!1;function Nu(t){var e=pu._t(h());if(12.2<=e&&e<13){e="An internal error was encountered in the Indexed Database server";if(0<=t.message.indexOf(e)){var n=new Ur("internal","IOS_INDEXEDDB_BUG1: IndexedDb has thrown '"+e+"'. This is likely due to an unavoidable bug in iOS. See https://stackoverflow.com/q/56496296/110915 for details and a potential workaround.");return Du||(Du=!0,setTimeout(function(){throw n},0)),n}}return t}var Cu,ku=(n(Ru,Cu=R),Ru);function Ru(t,e){var n=this;return(n=Cu.call(this)||this).Mt=t,n.currentSequenceNumber=e,n}function xu(t,e){return pu.It(t.Mt,e)}var Ou=(Uu.prototype.applyToRemoteDocument=function(t,e){for(var n,r,i,o,s,a,u=e.mutationResults,c=0;c=i),o=Hu(r.R,e)),n.done()}).next(function(){return o})},dc.prototype.getHighestUnacknowledgedBatchId=function(t){var e=IDBKeyRange.upperBound([this.userId,Number.POSITIVE_INFINITY]),r=-1;return yc(t).$t({index:Wa.userMutationsIndex,range:e,reverse:!0},function(t,e,n){r=e.batchId,n.done()}).next(function(){return r})},dc.prototype.getAllMutationBatches=function(t){var e=this,n=IDBKeyRange.bound([this.userId,-1],[this.userId,Number.POSITIVE_INFINITY]);return yc(t).Nt(Wa.userMutationsIndex,n).next(function(t){return t.map(function(t){return Hu(e.R,t)})})},dc.prototype.getAllMutationBatchesAffectingDocumentKey=function(o,s){var a=this,t=Ya.prefixForPath(this.userId,s.path),t=IDBKeyRange.lowerBound(t),u=[];return gc(o).$t({range:t},function(t,e,n){var r=t[0],i=t[1],t=t[2],i=Ga(i);if(r===a.userId&&s.path.isEqual(i))return yc(o).get(t).next(function(t){if(!t)throw zr();Wr(t.userId===a.userId),u.push(Hu(a.R,t))});n.done()}).next(function(){return u})},dc.prototype.getAllMutationBatchesAffectingDocumentKeys=function(e,t){var s=this,a=new Qs($r),n=[];return t.forEach(function(o){var t=Ya.prefixForPath(s.userId,o.path),t=IDBKeyRange.lowerBound(t),t=gc(e).$t({range:t},function(t,e,n){var r=t[0],i=t[1],t=t[2],i=Ga(i);r===s.userId&&o.path.isEqual(i)?a=a.add(t):n.done()});n.push(t)}),fu.waitFor(n).next(function(){return s.Wt(e,a)})},dc.prototype.getAllMutationBatchesAffectingQuery=function(t,e){var o=this,s=e.path,a=s.length+1,e=Ya.prefixForPath(this.userId,s),e=IDBKeyRange.lowerBound(e),u=new Qs($r);return gc(t).$t({range:e},function(t,e,n){var r=t[0],i=t[1],t=t[2],i=Ga(i);r===o.userId&&s.isPrefixOf(i)?i.length===a&&(u=u.add(t)):n.done()}).next(function(){return o.Wt(t,u)})},dc.prototype.Wt=function(e,t){var n=this,r=[],i=[];return t.forEach(function(t){i.push(yc(e).get(t).next(function(t){if(null===t)throw zr();Wr(t.userId===n.userId),r.push(Hu(n.R,t))}))}),fu.waitFor(i).next(function(){return r})},dc.prototype.removeMutationBatch=function(e,n){var r=this;return hc(e.Mt,this.userId,n).next(function(t){return e.addOnCommittedListener(function(){r.Gt(n.batchId)}),fu.forEach(t,function(t){return r.referenceDelegate.markPotentiallyOrphaned(e,t)})})},dc.prototype.Gt=function(t){delete this.Kt[t]},dc.prototype.performConsistencyCheck=function(e){var i=this;return this.checkEmpty(e).next(function(t){if(!t)return fu.resolve();var t=IDBKeyRange.lowerBound(Ya.prefixForUser(i.userId)),r=[];return gc(e).$t({range:t},function(t,e,n){t[0]===i.userId?(t=Ga(t[1]),r.push(t)):n.done()}).next(function(){Wr(0===r.length)})})},dc.prototype.containsKey=function(t,e){return pc(t,this.userId,e)},dc.prototype.zt=function(t){var e=this;return mc(t).get(this.userId).next(function(t){return t||new za(e.userId,-1,"")})},dc);function dc(t,e,n,r){this.userId=t,this.R=e,this.Ut=n,this.referenceDelegate=r,this.Kt={}}function pc(t,o,e){var e=Ya.prefixForPath(o,e.path),s=e[1],e=IDBKeyRange.lowerBound(e),a=!1;return gc(t).$t({range:e,Ft:!0},function(t,e,n){var r=t[0],i=t[1];t[2],r===o&&i===s&&(a=!0),n.done()}).next(function(){return a})}function yc(t){return xu(t,Wa.store)}function gc(t){return xu(t,Ya.store)}function mc(t){return xu(t,za.store)}var vc=(Ec.prototype.next=function(){return this.Ht+=2,this.Ht},Ec.Jt=function(){return new Ec(0)},Ec.Yt=function(){return new Ec(-1)},Ec),wc=(bc.prototype.allocateTargetId=function(n){var r=this;return this.Xt(n).next(function(t){var e=new vc(t.highestTargetId);return t.highestTargetId=e.next(),r.Zt(n,t).next(function(){return t.highestTargetId})})},bc.prototype.getLastRemoteSnapshotVersion=function(t){return this.Xt(t).next(function(t){return ei.fromTimestamp(new ti(t.lastRemoteSnapshotVersion.seconds,t.lastRemoteSnapshotVersion.nanoseconds))})},bc.prototype.getHighestSequenceNumber=function(t){return this.Xt(t).next(function(t){return t.highestListenSequenceNumber})},bc.prototype.setTargetsMetadata=function(e,n,r){var i=this;return this.Xt(e).next(function(t){return t.highestListenSequenceNumber=n,r&&(t.lastRemoteSnapshotVersion=r.toTimestamp()),n>t.highestListenSequenceNumber&&(t.highestListenSequenceNumber=n),i.Zt(e,t)})},bc.prototype.addTargetData=function(e,n){var r=this;return this.te(e,n).next(function(){return r.Xt(e).next(function(t){return t.targetCount+=1,r.ee(n,t),r.Zt(e,t)})})},bc.prototype.updateTargetData=function(t,e){return this.te(t,e)},bc.prototype.removeTargetData=function(e,t){var n=this;return this.removeMatchingKeysForTargetId(e,t.targetId).next(function(){return Tc(e).delete(t.targetId)}).next(function(){return n.Xt(e)}).next(function(t){return Wr(0e.highestTargetId&&(e.highestTargetId=t.targetId,n=!0),t.sequenceNumber>e.highestListenSequenceNumber&&(e.highestListenSequenceNumber=t.sequenceNumber,n=!0),n},bc.prototype.getTargetCount=function(t){return this.Xt(t).next(function(t){return t.targetCount})},bc.prototype.getTargetData=function(t,r){var e=Yi(r),e=IDBKeyRange.bound([e,Number.NEGATIVE_INFINITY],[e,Number.POSITIVE_INFINITY]),i=null;return Tc(t).$t({range:e,index:eu.queryTargetsIndexName},function(t,e,n){e=zu(e);Xi(r,e.target)&&(i=e,n.done())}).next(function(){return i})},bc.prototype.addMatchingKeys=function(n,t,r){var i=this,o=[],s=_c(n);return t.forEach(function(t){var e=ja(t.path);o.push(s.put(new nu(r,e))),o.push(i.referenceDelegate.addReference(n,r,t))}),fu.waitFor(o)},bc.prototype.removeMatchingKeys=function(n,t,r){var i=this,o=_c(n);return fu.forEach(t,function(t){var e=ja(t.path);return fu.waitFor([o.delete([r,e]),i.referenceDelegate.removeReference(n,r,t)])})},bc.prototype.removeMatchingKeysForTargetId=function(t,e){t=_c(t),e=IDBKeyRange.bound([e],[e+1],!1,!0);return t.delete(e)},bc.prototype.getMatchingKeysForTargetId=function(t,e){var e=IDBKeyRange.bound([e],[e+1],!1,!0),t=_c(t),r=Zs();return t.$t({range:e,Ft:!0},function(t,e,n){t=Ga(t[1]),t=new Ni(t);r=r.add(t)}).next(function(){return r})},bc.prototype.containsKey=function(t,e){var e=ja(e.path),e=IDBKeyRange.bound([e],[Zr(e)],!1,!0),i=0;return _c(t).$t({index:nu.documentTargetsIndex,Ft:!0,range:e},function(t,e,n){var r=t[0];t[1],0!==r&&(i++,n.done())}).next(function(){return 0h.params.maximumSequenceNumbersToCollect?(Kr("LruGarbageCollector","Capping sequence numbers to collect down to the maximum of "+h.params.maximumSequenceNumbersToCollect+" from "+t),h.params.maximumSequenceNumbersToCollect):t,s=Date.now(),h.nthSequenceNumber(e,i)}).next(function(t){return r=t,a=Date.now(),h.removeTargets(e,r,n)}).next(function(t){return o=t,u=Date.now(),h.removeOrphanedDocuments(e,r)}).next(function(t){return c=Date.now(),jr()<=w.DEBUG&&Kr("LruGarbageCollector","LRU Garbage Collection\n\tCounted targets in "+(s-l)+"ms\n\tDetermined least recently used "+i+" in "+(a-s)+"ms\n\tRemoved "+o+" targets in "+(u-a)+"ms\n\tRemoved "+t+" documents in "+(c-u)+"ms\nTotal Duration: "+(c-l)+"ms"),fu.resolve({didRun:!0,sequenceNumbersCollected:i,targetsRemoved:o,documentsRemoved:t})})},xc),kc=(Rc.prototype.he=function(t){var n=this.de(t);return this.db.getTargetCache().getTargetCount(t).next(function(e){return n.next(function(t){return e+t})})},Rc.prototype.de=function(t){var e=0;return this.le(t,function(t){e++}).next(function(){return e})},Rc.prototype.forEachTarget=function(t,e){return this.db.getTargetCache().forEachTarget(t,e)},Rc.prototype.le=function(t,n){return this.we(t,function(t,e){return n(e)})},Rc.prototype.addReference=function(t,e,n){return Pc(t,n)},Rc.prototype.removeReference=function(t,e,n){return Pc(t,n)},Rc.prototype.removeTargets=function(t,e,n){return this.db.getTargetCache().removeTargets(t,e,n)},Rc.prototype.markPotentiallyOrphaned=Pc,Rc.prototype._e=function(t,e){return r=e,i=!1,mc(n=t).Ot(function(t){return pc(n,t,r).next(function(t){return t&&(i=!0),fu.resolve(!t)})}).next(function(){return i});var n,r,i},Rc.prototype.removeOrphanedDocuments=function(n,r){var i=this,o=this.db.getRemoteDocumentCache().newChangeBuffer(),s=[],a=0;return this.we(n,function(e,t){t<=r&&(t=i._e(n,e).next(function(t){if(!t)return a++,o.getEntry(n,e).next(function(){return o.removeEntry(e),_c(n).delete([0,ja(e.path)])})}),s.push(t))}).next(function(){return fu.waitFor(s)}).next(function(){return o.apply(n)}).next(function(){return a})},Rc.prototype.removeTarget=function(t,e){e=e.withSequenceNumber(t.currentSequenceNumber);return this.db.getTargetCache().updateTargetData(t,e)},Rc.prototype.updateLimboDocument=Pc,Rc.prototype.we=function(t,r){var i,t=_c(t),o=Pr.o;return t.$t({index:nu.documentTargetsIndex},function(t,e){var n=t[0];t[1];t=e.path,e=e.sequenceNumber;0===n?(o!==Pr.o&&r(new Ni(Ga(i)),o),o=e,i=t):o=Pr.o}).next(function(){o!==Pr.o&&r(new Ni(Ga(i)),o)})},Rc.prototype.getCacheSize=function(t){return this.db.getRemoteDocumentCache().getSize(t)},Rc);function Rc(t,e){this.db=t,this.garbageCollector=new Cc(this,e)}function xc(t,e){this.ae=t,this.params=e}function Oc(t,e){this.garbageCollector=t,this.asyncQueue=e,this.oe=!1,this.ce=null}function Lc(t){this.ne=t,this.buffer=new Qs(Ac),this.se=0}function Pc(t,e){return _c(t).put((t=t.currentSequenceNumber,new nu(0,ja(e.path),t)))}var Mc,Fc=(Kc.prototype.get=function(t){var e=this.mapKeyFn(t),e=this.inner[e];if(void 0!==e)for(var n=0,r=e;n "+n),1))},Jc.prototype.We=function(){var t=this;null!==this.document&&"function"==typeof this.document.addEventListener&&(this.Fe=function(){t.Se.enqueueAndForget(function(){return t.inForeground="visible"===t.document.visibilityState,t.je()})},this.document.addEventListener("visibilitychange",this.Fe),this.inForeground="visible"===this.document.visibilityState)},Jc.prototype.an=function(){this.Fe&&(this.document.removeEventListener("visibilitychange",this.Fe),this.Fe=null)},Jc.prototype.Ge=function(){var t,e=this;"function"==typeof(null===(t=this.window)||void 0===t?void 0:t.addEventListener)&&(this.ke=function(){e.un(),c()&&navigator.appVersion.match("Version/14")&&e.Se.enterRestrictedMode(!0),e.Se.enqueueAndForget(function(){return e.shutdown()})},this.window.addEventListener("pagehide",this.ke))},Jc.prototype.hn=function(){this.ke&&(this.window.removeEventListener("pagehide",this.ke),this.ke=null)},Jc.prototype.cn=function(t){var e;try{var n=null!==(null===(e=this.Qe)||void 0===e?void 0:e.getItem(this.on(t)));return Kr("IndexedDbPersistence","Client '"+t+"' "+(n?"is":"is not")+" zombied in LocalStorage"),n}catch(t){return Gr("IndexedDbPersistence","Failed to get zombied client id.",t),!1}},Jc.prototype.un=function(){if(this.Qe)try{this.Qe.setItem(this.on(this.clientId),String(Date.now()))}catch(t){Gr("Failed to set zombie client id.",t)}},Jc.prototype.ln=function(){if(this.Qe)try{this.Qe.removeItem(this.on(this.clientId))}catch(t){}},Jc.prototype.on=function(t){return"firestore_zombie_"+this.persistenceKey+"_"+t},Jc);function Jc(t,e,n,r,i,o,s,a,u,c){if(this.allowTabSynchronization=t,this.persistenceKey=e,this.clientId=n,this.Se=i,this.window=o,this.document=s,this.De=u,this.Ce=c,this.Ne=null,this.xe=!1,this.isPrimary=!1,this.networkEnabled=!0,this.ke=null,this.inForeground=!1,this.Fe=null,this.$e=null,this.Oe=Number.NEGATIVE_INFINITY,this.Me=function(t){return Promise.resolve()},!Jc.yt())throw new Ur(Vr.UNIMPLEMENTED,"This platform is either missing IndexedDB or is known to have an incomplete implementation. Offline persistence has been disabled.");this.referenceDelegate=new kc(this,r),this.Le=e+"main",this.R=new Mu(a),this.Be=new pu(this.Le,11,new zc(this.R)),this.qe=new wc(this.referenceDelegate,this.R),this.Ut=new nc,this.Ue=(e=this.R,a=this.Ut,new Vc(e,a)),this.Ke=new Xu,this.window&&this.window.localStorage?this.Qe=this.window.localStorage:(this.Qe=null,!1===c&&Gr("IndexedDbPersistence","LocalStorage is unavailable. As a result, persistence may not work reliably. In particular enablePersistence() could fail immediately after refreshing the page."))}function Zc(t){return xu(t,Qa.store)}function th(t){return xu(t,ou.store)}function eh(t,e){var n=t.projectId;return t.isDefaultDatabase||(n+="."+t.database),"firestore/"+e+"/"+n+"/"}function nh(t,e){this.progress=t,this.wn=e}var rh=(hh.prototype.mn=function(e,n){var r=this;return this._n.getAllMutationBatchesAffectingDocumentKey(e,n).next(function(t){return r.yn(e,n,t)})},hh.prototype.yn=function(t,e,r){return this.Ue.getEntry(t,e).next(function(t){for(var e=0,n=r;ee?this._n[e]:null)},Kh.prototype.getHighestUnacknowledgedBatchId=function(){return fu.resolve(0===this._n.length?-1:this.ss-1)},Kh.prototype.getAllMutationBatches=function(t){return fu.resolve(this._n.slice())},Kh.prototype.getAllMutationBatchesAffectingDocumentKey=function(t,e){var n=this,r=new Dh(e,0),e=new Dh(e,Number.POSITIVE_INFINITY),i=[];return this.rs.forEachInRange([r,e],function(t){t=n.os(t.ns);i.push(t)}),fu.resolve(i)},Kh.prototype.getAllMutationBatchesAffectingDocumentKeys=function(t,e){var n=this,r=new Qs($r);return e.forEach(function(t){var e=new Dh(t,0),t=new Dh(t,Number.POSITIVE_INFINITY);n.rs.forEachInRange([e,t],function(t){r=r.add(t.ns)})}),fu.resolve(this.us(r))},Kh.prototype.getAllMutationBatchesAffectingQuery=function(t,e){var n=e.path,r=n.length+1,e=n;Ni.isDocumentKey(e)||(e=e.child(""));var e=new Dh(new Ni(e),0),i=new Qs($r);return this.rs.forEachWhile(function(t){var e=t.key.path;return!!n.isPrefixOf(e)&&(e.length===r&&(i=i.add(t.ns)),!0)},e),fu.resolve(this.us(i))},Kh.prototype.us=function(t){var e=this,n=[];return t.forEach(function(t){t=e.os(t);null!==t&&n.push(t)}),n},Kh.prototype.removeMutationBatch=function(n,r){var i=this;Wr(0===this.hs(r.batchId,"removed")),this._n.shift();var o=this.rs;return fu.forEach(r.mutations,function(t){var e=new Dh(t.key,r.batchId);return o=o.delete(e),i.referenceDelegate.markPotentiallyOrphaned(n,t.key)}).next(function(){i.rs=o})},Kh.prototype.Gt=function(t){},Kh.prototype.containsKey=function(t,e){var n=new Dh(e,0),n=this.rs.firstAfterOrEqual(n);return fu.resolve(e.isEqual(n&&n.key))},Kh.prototype.performConsistencyCheck=function(t){return this._n.length,fu.resolve()},Kh.prototype.hs=function(t,e){return this.cs(t)},Kh.prototype.cs=function(t){return 0===this._n.length?0:t-this._n[0].batchId},Kh.prototype.os=function(t){t=this.cs(t);return t<0||t>=this._n.length?null:this._n[t]},Kh),Ch=(jh.prototype.addEntry=function(t,e,n){var r=e.key,i=this.docs.get(r),o=i?i.size:0,i=this.ls(e);return this.docs=this.docs.insert(r,{document:e.clone(),size:i,readTime:n}),this.size+=i-o,this.Ut.addToCollectionParentIndex(t,r.path.popLast())},jh.prototype.removeEntry=function(t){var e=this.docs.get(t);e&&(this.docs=this.docs.remove(t),this.size-=e.size)},jh.prototype.getEntry=function(t,e){var n=this.docs.get(e);return fu.resolve(n?n.document.clone():Qi.newInvalidDocument(e))},jh.prototype.getEntries=function(t,e){var n=this,r=zs;return e.forEach(function(t){var e=n.docs.get(t);r=r.insert(t,e?e.document.clone():Qi.newInvalidDocument(t))}),fu.resolve(r)},jh.prototype.getDocumentsMatchingQuery=function(t,e,n){for(var r=zs,i=new Ni(e.path.child("")),o=this.docs.getIteratorFrom(i);o.hasNext();){var s=o.getNext(),a=s.key,u=s.value,s=u.document,u=u.readTime;if(!e.path.isPrefixOf(a.path))break;u.compareTo(n)<=0||Ko(e,s)&&(r=r.insert(s.key,s.clone()))}return fu.resolve(r)},jh.prototype.fs=function(t,e){return fu.forEach(this.docs,function(t){return e(t)})},jh.prototype.newChangeBuffer=function(t){return new kh(this)},jh.prototype.getSize=function(t){return fu.resolve(this.size)},jh),kh=(n(Bh,_h=A),Bh.prototype.applyChanges=function(n){var r=this,i=[];return this.changes.forEach(function(t,e){e.document.isValidDocument()?i.push(r.Ie.addEntry(n,e.document,r.getReadTime(t))):r.Ie.removeEntry(t)}),fu.waitFor(i)},Bh.prototype.getFromCache=function(t,e){return this.Ie.getEntry(t,e)},Bh.prototype.getAllFromCache=function(t,e){return this.Ie.getEntries(t,e)},Bh),Rh=(qh.prototype.forEachTarget=function(t,n){return this.ds.forEach(function(t,e){return n(e)}),fu.resolve()},qh.prototype.getLastRemoteSnapshotVersion=function(t){return fu.resolve(this.lastRemoteSnapshotVersion)},qh.prototype.getHighestSequenceNumber=function(t){return fu.resolve(this.ws)},qh.prototype.allocateTargetId=function(t){return this.highestTargetId=this.ys.next(),fu.resolve(this.highestTargetId)},qh.prototype.setTargetsMetadata=function(t,e,n){return n&&(this.lastRemoteSnapshotVersion=n),e>this.ws&&(this.ws=e),fu.resolve()},qh.prototype.te=function(t){this.ds.set(t.target,t);var e=t.targetId;e>this.highestTargetId&&(this.ys=new vc(e),this.highestTargetId=e),t.sequenceNumber>this.ws&&(this.ws=t.sequenceNumber)},qh.prototype.addTargetData=function(t,e){return this.te(e),this.targetCount+=1,fu.resolve()},qh.prototype.updateTargetData=function(t,e){return this.te(e),fu.resolve()},qh.prototype.removeTargetData=function(t,e){return this.ds.delete(e.target),this._s.Zn(e.targetId),--this.targetCount,fu.resolve()},qh.prototype.removeTargets=function(n,r,i){var o=this,s=0,a=[];return this.ds.forEach(function(t,e){e.sequenceNumber<=r&&null===i.get(e.targetId)&&(o.ds.delete(t),a.push(o.removeMatchingKeysForTargetId(n,e.targetId)),s++)}),fu.waitFor(a).next(function(){return s})},qh.prototype.getTargetCount=function(t){return fu.resolve(this.targetCount)},qh.prototype.getTargetData=function(t,e){e=this.ds.get(e)||null;return fu.resolve(e)},qh.prototype.addMatchingKeys=function(t,e,n){return this._s.Jn(e,n),fu.resolve()},qh.prototype.removeMatchingKeys=function(e,t,n){this._s.Xn(t,n);var r=this.persistence.referenceDelegate,i=[];return r&&t.forEach(function(t){i.push(r.markPotentiallyOrphaned(e,t))}),fu.waitFor(i)},qh.prototype.removeMatchingKeysForTargetId=function(t,e){return this._s.Zn(e),fu.resolve()},qh.prototype.getMatchingKeysForTargetId=function(t,e){e=this._s.es(e);return fu.resolve(e)},qh.prototype.containsKey=function(t,e){return fu.resolve(this._s.containsKey(e))},qh),xh=(Uh.prototype.start=function(){return Promise.resolve()},Uh.prototype.shutdown=function(){return this.xe=!1,Promise.resolve()},Object.defineProperty(Uh.prototype,"started",{get:function(){return this.xe},enumerable:!1,configurable:!0}),Uh.prototype.setDatabaseDeletedListener=function(){},Uh.prototype.setNetworkEnabled=function(){},Uh.prototype.getIndexManager=function(){return this.Ut},Uh.prototype.getMutationQueue=function(t){var e=this.gs[t.toKey()];return e||(e=new Nh(this.Ut,this.referenceDelegate),this.gs[t.toKey()]=e),e},Uh.prototype.getTargetCache=function(){return this.qe},Uh.prototype.getRemoteDocumentCache=function(){return this.Ue},Uh.prototype.getBundleCache=function(){return this.Ke},Uh.prototype.runTransaction=function(t,e,n){var r=this;Kr("MemoryPersistence","Starting transaction:",t);var i=new Oh(this.Ne.next());return this.referenceDelegate.Es(),n(i).next(function(t){return r.referenceDelegate.Ts(i).next(function(){return t})}).toPromise().then(function(t){return i.raiseOnCommittedEvent(),t})},Uh.prototype.Is=function(e,n){return fu.or(Object.values(this.gs).map(function(t){return function(){return t.containsKey(e,n)}}))},Uh),Oh=(n(Vh,Ih=R),Vh),Lh=(Fh.bs=function(t){return new Fh(t)},Object.defineProperty(Fh.prototype,"vs",{get:function(){if(this.Rs)return this.Rs;throw zr()},enumerable:!1,configurable:!0}),Fh.prototype.addReference=function(t,e,n){return this.As.addReference(n,e),this.vs.delete(n.toString()),fu.resolve()},Fh.prototype.removeReference=function(t,e,n){return this.As.removeReference(n,e),this.vs.add(n.toString()),fu.resolve()},Fh.prototype.markPotentiallyOrphaned=function(t,e){return this.vs.add(e.toString()),fu.resolve()},Fh.prototype.removeTarget=function(t,e){var n=this;this.As.Zn(e.targetId).forEach(function(t){return n.vs.add(t.toString())});var r=this.persistence.getTargetCache();return r.getMatchingKeysForTargetId(t,e.targetId).next(function(t){t.forEach(function(t){return n.vs.add(t.toString())})}).next(function(){return r.removeTargetData(t,e)})},Fh.prototype.Es=function(){this.Rs=new Set},Fh.prototype.Ts=function(n){var r=this,i=this.persistence.getRemoteDocumentCache().newChangeBuffer();return fu.forEach(this.vs,function(t){var e=Ni.fromPath(t);return r.Ps(n,e).next(function(t){t||i.removeEntry(e)})}).next(function(){return r.Rs=null,i.apply(n)})},Fh.prototype.updateLimboDocument=function(t,e){var n=this;return this.Ps(t,e).next(function(t){t?n.vs.delete(e.toString()):n.vs.add(e.toString())})},Fh.prototype.ps=function(t){return 0},Fh.prototype.Ps=function(t,e){var n=this;return fu.or([function(){return fu.resolve(n.As.containsKey(e))},function(){return n.persistence.getTargetCache().containsKey(t,e)},function(){return n.persistence.Is(t,e)}])},Fh),Ph=(Mh.prototype.isAuthenticated=function(){return null!=this.uid},Mh.prototype.toKey=function(){return this.isAuthenticated()?"uid:"+this.uid:"anonymous-user"},Mh.prototype.isEqual=function(t){return t.uid===this.uid},Mh);function Mh(t){this.uid=t}function Fh(t){this.persistence=t,this.As=new Ah,this.Rs=null}function Vh(t){var e=this;return(e=Ih.call(this)||this).currentSequenceNumber=t,e}function Uh(t,e){var n=this;this.gs={},this.Ne=new Pr(0),this.xe=!1,this.xe=!0,this.referenceDelegate=t(this),this.qe=new Rh(this),this.Ut=new tc,this.Ue=(t=this.Ut,new Ch(t,function(t){return n.referenceDelegate.ps(t)})),this.R=new Mu(e),this.Ke=new Sh(this.R)}function qh(t){this.persistence=t,this.ds=new Fc(Yi,Xi),this.lastRemoteSnapshotVersion=ei.min(),this.highestTargetId=0,this.ws=0,this._s=new Ah,this.targetCount=0,this.ys=vc.Jt()}function Bh(t){var e=this;return(e=_h.call(this)||this).Ie=t,e}function jh(t,e){this.Ut=t,this.ls=e,this.docs=new Vs(Ni.comparator),this.size=0}function Kh(t,e){this.Ut=t,this.referenceDelegate=e,this._n=[],this.ss=1,this.rs=new Qs(Dh.Gn)}function Gh(t,e){this.key=t,this.ns=e}function Qh(){this.Wn=new Qs(Dh.Gn),this.zn=new Qs(Dh.Hn)}function Hh(t){this.R=t,this.Qn=new Map,this.jn=new Map}function zh(t,e){return"firestore_clients_"+t+"_"+e}function Wh(t,e,n){n="firestore_mutations_"+t+"_"+n;return e.isAuthenticated()&&(n+="_"+e.uid),n}function Yh(t,e){return"firestore_targets_"+t+"_"+e}Ph.UNAUTHENTICATED=new Ph(null),Ph.GOOGLE_CREDENTIALS=new Ph("google-credentials-uid"),Ph.FIRST_PARTY=new Ph("first-party-uid"),Ph.MOCK_USER=new Ph("mock-user");var Xh,$h=(bl.Vs=function(t,e,n){var r,i=JSON.parse(n),o="object"==typeof i&&-1!==["pending","acknowledged","rejected"].indexOf(i.state)&&(void 0===i.error||"object"==typeof i.error);return o&&i.error&&(o="string"==typeof i.error.message&&"string"==typeof i.error.code)&&(r=new Ur(i.error.code,i.error.message)),o?new bl(t,e,i.state,r):(Gr("SharedClientState","Failed to parse mutation state for ID '"+e+"': "+n),null)},bl.prototype.Ss=function(){var t={state:this.state,updateTimeMs:Date.now()};return this.error&&(t.error={code:this.error.code,message:this.error.message}),JSON.stringify(t)},bl),Jh=(wl.Vs=function(t,e){var n,r=JSON.parse(e),i="object"==typeof r&&-1!==["not-current","current","rejected"].indexOf(r.state)&&(void 0===r.error||"object"==typeof r.error);return i&&r.error&&(i="string"==typeof r.error.message&&"string"==typeof r.error.code)&&(n=new Ur(r.error.code,r.error.message)),i?new wl(t,r.state,n):(Gr("SharedClientState","Failed to parse target state for ID '"+t+"': "+e),null)},wl.prototype.Ss=function(){var t={state:this.state,updateTimeMs:Date.now()};return this.error&&(t.error={code:this.error.code,message:this.error.message}),JSON.stringify(t)},wl),Zh=(vl.Vs=function(t,e){for(var n=JSON.parse(e),r="object"==typeof n&&n.activeTargetIds instanceof Array,i=ta,o=0;r&&othis.Bi&&(this.qi=this.Bi)},Vl.prototype.Gi=function(){null!==this.Ui&&(this.Ui.skipDelay(),this.Ui=null)},Vl.prototype.cancel=function(){null!==this.Ui&&(this.Ui.cancel(),this.Ui=null)},Vl.prototype.Wi=function(){return(Math.random()-.5)*this.qi},Vl),A=(Fl.prototype.tr=function(){return 1===this.state||2===this.state||4===this.state},Fl.prototype.er=function(){return 2===this.state},Fl.prototype.start=function(){3!==this.state?this.auth():this.nr()},Fl.prototype.stop=function(){return y(this,void 0,void 0,function(){return g(this,function(t){switch(t.label){case 0:return this.tr()?[4,this.close(0)]:[3,2];case 1:t.sent(),t.label=2;case 2:return[2]}})})},Fl.prototype.sr=function(){this.state=0,this.Zi.reset()},Fl.prototype.ir=function(){var t=this;this.er()&&null===this.Xi&&(this.Xi=this.Se.enqueueAfterDelay(this.zi,6e4,function(){return t.rr()}))},Fl.prototype.cr=function(t){this.ur(),this.stream.send(t)},Fl.prototype.rr=function(){return y(this,void 0,void 0,function(){return g(this,function(t){return this.er()?[2,this.close(0)]:[2]})})},Fl.prototype.ur=function(){this.Xi&&(this.Xi.cancel(),this.Xi=null)},Fl.prototype.close=function(e,n){return y(this,void 0,void 0,function(){return g(this,function(t){switch(t.label){case 0:return this.ur(),this.Zi.cancel(),this.Yi++,3!==e?this.Zi.reset():n&&n.code===Vr.RESOURCE_EXHAUSTED?(Gr(n.toString()),Gr("Using maximum backoff delay to prevent overloading the backend."),this.Zi.Qi()):n&&n.code===Vr.UNAUTHENTICATED&&this.Ji.invalidateToken(),null!==this.stream&&(this.ar(),this.stream.close(),this.stream=null),this.state=e,[4,this.listener.Ri(n)];case 1:return t.sent(),[2]}})})},Fl.prototype.ar=function(){},Fl.prototype.auth=function(){var n=this;this.state=1;var t=this.hr(this.Yi),e=this.Yi;this.Ji.getToken().then(function(t){n.Yi===e&&n.lr(t)},function(e){t(function(){var t=new Ur(Vr.UNKNOWN,"Fetching auth token failed: "+e.message);return n.dr(t)})})},Fl.prototype.lr=function(t){var e=this,n=this.hr(this.Yi);this.stream=this.wr(t),this.stream.Ii(function(){n(function(){return e.state=2,e.listener.Ii()})}),this.stream.Ri(function(t){n(function(){return e.dr(t)})}),this.stream.onMessage(function(t){n(function(){return e.onMessage(t)})})},Fl.prototype.nr=function(){var t=this;this.state=4,this.Zi.ji(function(){return y(t,void 0,void 0,function(){return g(this,function(t){return this.state=0,this.start(),[2]})})})},Fl.prototype.dr=function(t){return Kr("PersistentStream","close with error: "+t),this.stream=null,this.close(3,t)},Fl.prototype.hr=function(e){var n=this;return function(t){n.Se.enqueueAndForget(function(){return n.Yi===e?t():(Kr("PersistentStream","stream callback skipped by getCloseGuardedDispatcher."),Promise.resolve())})}},Fl),Cl=(n(Ml,Dl=A),Ml.prototype.wr=function(t){return this.Hi.Oi("Listen",t)},Ml.prototype.onMessage=function(t){this.Zi.reset();var e=function(t,e){if("targetChange"in e){e.targetChange;var n="NO_CHANGE"===(o=e.targetChange.targetChangeType||"NO_CHANGE")?0:"ADD"===o?1:"REMOVE"===o?2:"CURRENT"===o?3:"RESET"===o?4:zr(),r=e.targetChange.targetIds||[],i=(s=e.targetChange.resumeToken,t.I?(Wr(void 0===s||"string"==typeof s),di.fromBase64String(s||"")):(Wr(void 0===s||s instanceof Uint8Array),di.fromUint8Array(s||new Uint8Array))),o=(a=e.targetChange.cause)&&(u=void 0===(c=a).code?Vr.UNKNOWN:Fs(c.code),new Ur(u,c.message||"")),s=new oa(n,r,i,o||null)}else if("documentChange"in e){e.documentChange,(n=e.documentChange).document,n.document.name,n.document.updateTime;var r=Ia(t,n.document.name),i=wa(n.document.updateTime),a=new Ki({mapValue:{fields:n.document.fields}}),u=(o=Qi.newFoundDocument(r,i,a),n.targetIds||[]),c=n.removedTargetIds||[];s=new ra(u,c,o.key,o)}else if("documentDelete"in e)e.documentDelete,(n=e.documentDelete).document,r=Ia(t,n.document),i=n.readTime?wa(n.readTime):ei.min(),a=Qi.newNoDocument(r,i),o=n.removedTargetIds||[],s=new ra([],o,a.key,a);else if("documentRemove"in e)e.documentRemove,(n=e.documentRemove).document,r=Ia(t,n.document),i=n.removedTargetIds||[],s=new ra([],i,r,null);else{if(!("filter"in e))return zr();e.filter;e=e.filter;e.targetId,n=e.count||0,r=new Ns(n),i=e.targetId,s=new ia(i,r)}return s}(this.R,t),t=function(t){if(!("targetChange"in t))return ei.min();t=t.targetChange;return(!t.targetIds||!t.targetIds.length)&&t.readTime?wa(t.readTime):ei.min()}(t);return this.listener._r(e,t)},Ml.prototype.mr=function(t){var e,n,r,i={};i.database=Aa(this.R),i.addTarget=(e=this.R,(r=$i(r=(n=t).target)?{documents:xa(e,r)}:{query:Oa(e,r)}).targetId=n.targetId,0this.query.limit;){var n=xo(this.query)?h.last():h.first(),h=h.delete(n.key),c=c.delete(n.key);a.track({type:1,doc:n})}return{fo:h,mo:a,Nn:l,mutatedKeys:c}},Pf.prototype.yo=function(t,e){return t.hasLocalMutations&&e.hasCommittedMutations&&!e.hasLocalMutations},Pf.prototype.applyChanges=function(t,e,n){var o=this,r=this.fo;this.fo=t.fo,this.mutatedKeys=t.mutatedKeys;var i=t.mo.jr();i.sort(function(t,e){return r=t.type,i=e.type,n(r)-n(i)||o.lo(t.doc,e.doc);function n(t){switch(t){case 0:return 1;case 2:case 3:return 2;case 1:return 0;default:return zr()}}var r,i}),this.po(n);var s=e?this.Eo():[],n=0===this.ho.size&&this.current?1:0,e=n!==this.ao;return this.ao=n,0!==i.length||e?{snapshot:new lf(this.query,t.fo,r,i,t.mutatedKeys,0==n,e,!1),To:s}:{To:s}},Pf.prototype.zr=function(t){return this.current&&"Offline"===t?(this.current=!1,this.applyChanges({fo:this.fo,mo:new hf,mutatedKeys:this.mutatedKeys,Nn:!1},!1)):{To:[]}},Pf.prototype.Io=function(t){return!this.uo.has(t)&&!!this.fo.has(t)&&!this.fo.get(t).hasLocalMutations},Pf.prototype.po=function(t){var e=this;t&&(t.addedDocuments.forEach(function(t){return e.uo=e.uo.add(t)}),t.modifiedDocuments.forEach(function(t){}),t.removedDocuments.forEach(function(t){return e.uo=e.uo.delete(t)}),this.current=t.current)},Pf.prototype.Eo=function(){var e=this;if(!this.current)return[];var n=this.ho;this.ho=Zs(),this.fo.forEach(function(t){e.Io(t.key)&&(e.ho=e.ho.add(t.key))});var r=[];return n.forEach(function(t){e.ho.has(t)||r.push(new Cf(t))}),this.ho.forEach(function(t){n.has(t)||r.push(new Nf(t))}),r},Pf.prototype.Ao=function(t){this.uo=t.Bn,this.ho=Zs();t=this._o(t.documents);return this.applyChanges(t,!0)},Pf.prototype.Ro=function(){return lf.fromInitialDocuments(this.query,this.fo,this.mutatedKeys,0===this.ao)},Pf),Rf=function(t,e,n){this.query=t,this.targetId=e,this.view=n},xf=function(t){this.key=t,this.bo=!1},Of=(Object.defineProperty(Lf.prototype,"isPrimaryClient",{get:function(){return!0===this.$o},enumerable:!1,configurable:!0}),Lf);function Lf(t,e,n,r,i,o){this.localStore=t,this.remoteStore=e,this.eventManager=n,this.sharedClientState=r,this.currentUser=i,this.maxConcurrentLimboResolutions=o,this.vo={},this.Po=new Fc(Bo,qo),this.Vo=new Map,this.So=new Set,this.Do=new Vs(Ni.comparator),this.Co=new Map,this.No=new Ah,this.xo={},this.ko=new Map,this.Fo=vc.Yt(),this.onlineState="Unknown",this.$o=void 0}function Pf(t,e){this.query=t,this.uo=e,this.ao=null,this.current=!1,this.ho=Zs(),this.mutatedKeys=Zs(),this.lo=Go(t),this.fo=new cf(this.lo)}function Mf(i,o,s,a){return y(this,void 0,void 0,function(){var e,n,r;return g(this,function(t){switch(t.label){case 0:return i.Oo=function(t,e,n){return function(r,i,o,s){return y(this,void 0,void 0,function(){var e,n;return g(this,function(t){switch(t.label){case 0:return(e=i.view._o(o)).Nn?[4,wh(r.localStore,i.query,!1).then(function(t){t=t.documents;return i.view._o(t,e)})]:[3,2];case 1:e=t.sent(),t.label=2;case 2:return n=s&&s.targetChanges.get(i.targetId),n=i.view.applyChanges(e,r.isPrimaryClient,n),[2,(Hf(r,i.targetId,n.To),n.snapshot)]}})})}(i,t,e,n)},[4,wh(i.localStore,o,!0)];case 1:return n=t.sent(),r=new kf(o,n.Bn),e=r._o(n.documents),n=na.createSynthesizedTargetChangeForCurrentChange(s,a&&"Offline"!==i.onlineState),n=r.applyChanges(e,i.isPrimaryClient,n),Hf(i,s,n.To),r=new Rf(o,s,r),[2,(i.Po.set(o,r),i.Vo.has(s)?i.Vo.get(s).push(o):i.Vo.set(s,[o]),n.snapshot)]}})})}function Ff(f,d,p){return y(this,void 0,void 0,function(){var s,l;return g(this,function(t){switch(t.label){case 0:l=ed(f),t.label=1;case 1:return t.trys.push([1,5,,6]),[4,(i=l.localStore,a=d,c=i,h=ti.now(),o=a.reduce(function(t,e){return t.add(e.key)},Zs()),c.persistence.runTransaction("Locally write mutations","readwrite",function(s){return c.Mn.pn(s,o).next(function(t){u=t;for(var e=[],n=0,r=a;n, or >=) must be on the same field. But you have inequality filters on '"+n.toString()+"' and '"+e.field.toString()+"'");n=Lo(t);null!==n&&ag(0,e.field,n)}t=function(t,e){for(var n=0,r=t.filters;ns.length)throw new Ur(Vr.INVALID_ARGUMENT,"Too many arguments provided to "+r+"(). The number of arguments must be less than or equal to the number of orderBy() clauses");for(var a=[],u=0;u, or >=) on field '"+e.toString()+"' and so you must also use '"+e.toString()+"' as your first argument to orderBy(), but your first orderBy() is on field '"+n.toString()+"' instead.")}ug.prototype.convertValue=function(t,e){switch(void 0===e&&(e="none"),ki(t)){case 0:return null;case 1:return t.booleanValue;case 2:return Ei(t.integerValue||t.doubleValue);case 3:return this.convertTimestamp(t.timestampValue);case 4:return this.convertServerTimestamp(t,e);case 5:return t.stringValue;case 6:return this.convertBytes(Ti(t.bytesValue));case 7:return this.convertReference(t.referenceValue);case 8:return this.convertGeoPoint(t.geoPointValue);case 9:return this.convertArray(t.arrayValue,e);case 10:return this.convertObject(t.mapValue,e);default:throw zr()}},ug.prototype.convertObject=function(t,n){var r=this,i={};return oi(t.fields,function(t,e){i[t]=r.convertValue(e,n)}),i},ug.prototype.convertGeoPoint=function(t){return new Lp(Ei(t.latitude),Ei(t.longitude))},ug.prototype.convertArray=function(t,e){var n=this;return(t.values||[]).map(function(t){return n.convertValue(t,e)})},ug.prototype.convertServerTimestamp=function(t,e){switch(e){case"previous":var n=function t(e){e=e.mapValue.fields.__previous_value__;return Ii(e)?t(e):e}(t);return null==n?null:this.convertValue(n,e);case"estimate":return this.convertTimestamp(_i(t));default:return null}},ug.prototype.convertTimestamp=function(t){t=bi(t);return new ti(t.seconds,t.nanos)},ug.prototype.convertDocumentKey=function(t,e){var n=ci.fromString(t);Wr(Ba(n));t=new Fd(n.get(1),n.get(3)),n=new Ni(n.popFirst(5));return t.isEqual(e)||Gr("Document "+n+" contains a document reference within a different database ("+t.projectId+"/"+t.database+") which is not supported. It will be treated as a reference in the current database ("+e.projectId+"/"+e.database+") instead."),n},A=ug;function ug(){}function cg(t,e,n){return t?n&&(n.merge||n.mergeFields)?t.toFirestore(e,n):t.toFirestore(e):e}var hg,lg=(n(pg,hg=A),pg.prototype.convertBytes=function(t){return new xp(t)},pg.prototype.convertReference=function(t){t=this.convertDocumentKey(t,this.firestore._databaseId);return new ap(this.firestore,null,t)},pg),fg=(dg.prototype.set=function(t,e,n){this._verifyNotCommitted();t=yg(t,this._firestore),e=cg(t.converter,e,n),n=Yp(this._dataReader,"WriteBatch.set",t._key,e,null!==t.converter,n);return this._mutations.push(n.toMutation(t._key,ds.none())),this},dg.prototype.update=function(t,e,n){for(var r=[],i=3;ia[0]&&t[1]=e.length?void 0:e)&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function f(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,i,o=n.call(e),a=[];try{for(;(void 0===t||0"})):"Error",e=this.serviceName+": "+e+" ("+o+").";return new c(o,e,i)},v);function v(e,t,n){this.service=e,this.serviceName=t,this.errors=n}var m=/\{\$([^}]+)}/g;function y(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function b(e,t){t=new g(e,t);return t.subscribe.bind(t)}var g=(I.prototype.next=function(t){this.forEachObserver(function(e){e.next(t)})},I.prototype.error=function(t){this.forEachObserver(function(e){e.error(t)}),this.close(t)},I.prototype.complete=function(){this.forEachObserver(function(e){e.complete()}),this.close()},I.prototype.subscribe=function(e,t,n){var r,i=this;if(void 0===e&&void 0===t&&void 0===n)throw new Error("Missing Observer.");void 0===(r=function(e,t){if("object"!=typeof e||null===e)return!1;for(var n=0,r=t;n=(null!=o?o:e.logLevel)&&a({level:R[t].toLowerCase(),message:i,args:n,type:e.name})}}(n[e])}var H=((H={})["no-app"]="No Firebase App '{$appName}' has been created - call Firebase App.initializeApp()",H["bad-app-name"]="Illegal App name: '{$appName}",H["duplicate-app"]="Firebase App named '{$appName}' already exists",H["app-deleted"]="Firebase App named '{$appName}' already deleted",H["invalid-app-argument"]="firebase.{$appName}() takes either no argument or a Firebase App instance.",H["invalid-log-argument"]="First argument to `onLog` must be null or a function.",H),V=new d("app","Firebase",H),B="@firebase/app",M="[DEFAULT]",U=((H={})[B]="fire-core",H["@firebase/analytics"]="fire-analytics",H["@firebase/app-check"]="fire-app-check",H["@firebase/auth"]="fire-auth",H["@firebase/database"]="fire-rtdb",H["@firebase/functions"]="fire-fn",H["@firebase/installations"]="fire-iid",H["@firebase/messaging"]="fire-fcm",H["@firebase/performance"]="fire-perf",H["@firebase/remote-config"]="fire-rc",H["@firebase/storage"]="fire-gcs",H["@firebase/firestore"]="fire-fst",H["fire-js"]="fire-js",H["firebase-wrapper"]="fire-js-all",H),W=new z("@firebase/app"),G=(Object.defineProperty($.prototype,"automaticDataCollectionEnabled",{get:function(){return this.checkDestroyed_(),this.automaticDataCollectionEnabled_},set:function(e){this.checkDestroyed_(),this.automaticDataCollectionEnabled_=e},enumerable:!1,configurable:!0}),Object.defineProperty($.prototype,"name",{get:function(){return this.checkDestroyed_(),this.name_},enumerable:!1,configurable:!0}),Object.defineProperty($.prototype,"options",{get:function(){return this.checkDestroyed_(),this.options_},enumerable:!1,configurable:!0}),$.prototype.delete=function(){var t=this;return new Promise(function(e){t.checkDestroyed_(),e()}).then(function(){return t.firebase_.INTERNAL.removeApp(t.name_),Promise.all(t.container.getProviders().map(function(e){return e.delete()}))}).then(function(){t.isDeleted_=!0})},$.prototype._getService=function(e,t){void 0===t&&(t=M),this.checkDestroyed_();var n=this.container.getProvider(e);return n.isInitialized()||"EXPLICIT"!==(null===(e=n.getComponent())||void 0===e?void 0:e.instantiationMode)||n.initialize(),n.getImmediate({identifier:t})},$.prototype._removeServiceInstance=function(e,t){void 0===t&&(t=M),this.container.getProvider(e).clearInstance(t)},$.prototype._addComponent=function(t){try{this.container.addComponent(t)}catch(e){W.debug("Component "+t.name+" failed to register with FirebaseApp "+this.name,e)}},$.prototype._addOrOverwriteComponent=function(e){this.container.addOrOverwriteComponent(e)},$.prototype.toJSON=function(){return{name:this.name,automaticDataCollectionEnabled:this.automaticDataCollectionEnabled,options:this.options}},$.prototype.checkDestroyed_=function(){if(this.isDeleted_)throw V.create("app-deleted",{appName:this.name_})},$);function $(e,t,n){var r=this;this.firebase_=n,this.isDeleted_=!1,this.name_=t.name,this.automaticDataCollectionEnabled_=t.automaticDataCollectionEnabled||!1,this.options_=h(void 0,e),this.container=new S(t.name),this._addComponent(new E("app",function(){return r},"PUBLIC")),this.firebase_.INTERNAL.components.forEach(function(e){return r._addComponent(e)})}G.prototype.name&&G.prototype.options||G.prototype.delete||console.log("dc");var K="8.9.1";function Y(a){var s={},l=new Map,c={__esModule:!0,initializeApp:function(e,t){void 0===t&&(t={});"object"==typeof t&&null!==t||(t={name:t});var n=t;void 0===n.name&&(n.name=M);t=n.name;if("string"!=typeof t||!t)throw V.create("bad-app-name",{appName:String(t)});if(y(s,t))throw V.create("duplicate-app",{appName:t});n=new a(e,n,c);return s[t]=n},app:u,registerVersion:function(e,t,n){var r=null!==(i=U[e])&&void 0!==i?i:e;n&&(r+="-"+n);var i=r.match(/\s|\//),e=t.match(/\s|\//);i||e?(n=['Unable to register library "'+r+'" with version "'+t+'":'],i&&n.push('library name "'+r+'" contains illegal characters (whitespace or "/")'),i&&e&&n.push("and"),e&&n.push('version name "'+t+'" contains illegal characters (whitespace or "/")'),W.warn(n.join(" "))):o(new E(r+"-version",function(){return{library:r,version:t}},"VERSION"))},setLogLevel:T,onLog:function(e,t){if(null!==e&&"function"!=typeof e)throw V.create("invalid-log-argument");x(e,t)},apps:null,SDK_VERSION:K,INTERNAL:{registerComponent:o,removeApp:function(e){delete s[e]},components:l,useAsService:function(e,t){return"serverAuth"!==t?t:null}}};function u(e){if(!y(s,e=e||M))throw V.create("no-app",{appName:e});return s[e]}function o(n){var e,r=n.name;if(l.has(r))return W.debug("There were multiple attempts to register component "+r+"."),"PUBLIC"===n.type?c[r]:null;l.set(r,n),"PUBLIC"===n.type&&(e=function(e){if("function"!=typeof(e=void 0===e?u():e)[r])throw V.create("invalid-app-argument",{appName:r});return e[r]()},void 0!==n.serviceProps&&h(e,n.serviceProps),c[r]=e,a.prototype[r]=function(){for(var e=[],t=0;ts[0]&&e[1]>6,c=63&c;u||(c=64,s||(h=64)),r.push(n[o>>2],n[(3&o)<<4|a>>4],n[h],n[c])}return r.join("")},encodeString:function(t,e){return this.HAS_NATIVE_SUPPORT&&!e?btoa(t):this.encodeByteArray(function(t){for(var e=[],n=0,r=0;r>6|192:(55296==(64512&i)&&r+1>18|240,e[n++]=i>>12&63|128):e[n++]=i>>12|224,e[n++]=i>>6&63|128),e[n++]=63&i|128)}return e}(t),e)},decodeString:function(t,e){return this.HAS_NATIVE_SUPPORT&&!e?atob(t):function(t){for(var e=[],n=0,r=0;n>10)),e[r++]=String.fromCharCode(56320+(1023&i))):(o=t[n++],s=t[n++],e[r++]=String.fromCharCode((15&a)<<12|(63&o)<<6|63&s))}return e.join("")}(this.decodeStringToByteArray(t,e))},decodeStringToByteArray:function(t,e){this.init_();for(var n=e?this.charToByteMapWebSafe_:this.charToByteMap_,r=[],i=0;i>4),64!==a&&(r.push(s<<4&240|a>>2),64!==u&&r.push(a<<6&192|u))}return r},init_:function(){if(!this.byteToCharMap_){this.byteToCharMap_={},this.charToByteMap_={},this.byteToCharMapWebSafe_={},this.charToByteMapWebSafe_={};for(var t=0;t=this.ENCODED_VALS_BASE.length&&(this.charToByteMap_[this.ENCODED_VALS_WEBSAFE.charAt(t)]=t,this.charToByteMapWebSafe_[this.ENCODED_VALS.charAt(t)]=t)}}};function h(){return"undefined"!=typeof navigator&&"string"==typeof navigator.userAgent?navigator.userAgent:""}function i(){return!function(){try{return"[object process]"===Object.prototype.toString.call(global.process)}catch(t){return}}()&&navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome")}var u,c="FirebaseError",l=(n(f,u=Error),f);function f(t,e,n){e=u.call(this,e)||this;return e.code=t,e.customData=n,e.name=c,Object.setPrototypeOf(e,f.prototype),Error.captureStackTrace&&Error.captureStackTrace(e,d.prototype.create),e}var d=(p.prototype.create=function(t){for(var e=[],n=1;n"})):"Error",t=this.serviceName+": "+t+" ("+o+").";return new l(o,t,i)},p);function p(t,e,n){this.service=t,this.serviceName=e,this.errors=n}var m,v=/\{\$([^}]+)}/g;function w(t){return t&&t._delegate?t._delegate:t}(N=m=m||{})[N.DEBUG=0]="DEBUG",N[N.VERBOSE=1]="VERBOSE",N[N.INFO=2]="INFO",N[N.WARN=3]="WARN",N[N.ERROR=4]="ERROR",N[N.SILENT=5]="SILENT";function b(t,e){for(var n=[],r=2;r=t.length?void 0:t)&&t[r++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")}var N,C="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},k={},R=C||self;function x(){}function O(t){var e=typeof t;return"array"==(e="object"!=e?e:t?Array.isArray(t)?"array":e:"null")||"object"==e&&"number"==typeof t.length}function L(t){var e=typeof t;return"object"==e&&null!=t||"function"==e}var P="closure_uid_"+(1e9*Math.random()>>>0),M=0;function F(t,e,n){return t.call.apply(t.bind,arguments)}function V(e,n,t){if(!e)throw Error();if(2parseFloat(dt)){ot=String(pt);break t}}ot=dt}var yt={};function gt(){return t=function(){for(var t=0,e=X(String(ot)).split("."),n=X("9").split("."),r=Math.max(e.length,n.length),i=0;0==t&&i>>0);function Vt(e){return"function"==typeof e?e:(e[Ft]||(e[Ft]=function(t){return e.handleEvent(t)}),e[Ft])}function Ut(){j.call(this),this.i=new At(this),(this.P=this).I=null}function qt(t,e){var n,r=t.I;if(r)for(n=[];r;r=r.I)n.push(r);if(t=t.P,r=e.type||e,"string"==typeof e?e=new wt(e,t):e instanceof wt?e.target=e.target||t:(s=e,rt(e=new wt(r,t),s)),s=!0,n)for(var i=n.length-1;0<=i;i--)var o=e.g=n[i],s=Bt(o,r,!0,e)&&s;if(s=Bt(o=e.g=t,r,!0,e)&&s,s=Bt(o,r,!1,e)&&s,n)for(i=0;io.length?Oe:(o=o.substr(a,s),i.C=a+s,o)))==Oe){4==e&&(t.o=4,ve(14),u=!1),le(t.j,t.m,null,"[Incomplete Response]");break}if(r==xe){t.o=4,ve(15),le(t.j,t.m,n,"[Invalid Chunk]"),u=!1;break}le(t.j,t.m,r,null),Ke(t,r)}Me(t)&&r!=Oe&&r!=xe&&(t.h.g="",t.C=0),4!=e||0!=n.length||t.h.h||(t.o=1,ve(16),u=!1),t.i=t.i&&u,u?0>4&15).toString(16)+(15&t).toString(16)}Ye.prototype.toString=function(){var t=[],e=this.j;e&&t.push(on(e,an,!0),":");var n=this.i;return!n&&"file"!=e||(t.push("//"),(e=this.s)&&t.push(on(e,an,!0),"@"),t.push(encodeURIComponent(String(n)).replace(/%25([0-9a-fA-F]{2})/g,"%$1")),null!=(n=this.m)&&t.push(":",String(n))),(n=this.l)&&(this.i&&"/"!=n.charAt(0)&&t.push("/"),t.push(on(n,"/"==n.charAt(0)?cn:un,!0))),(n=this.h.toString())&&t.push("?",n),(n=this.o)&&t.push("#",on(n,ln)),t.join("")};var an=/[#\/\?@]/g,un=/[#\?:]/g,cn=/[#\?]/g,hn=/[#\?@]/g,ln=/#/g;function fn(t,e){this.h=this.g=null,this.i=t||null,this.j=!!e}function dn(n){n.g||(n.g=new Qe,n.h=0,n.i&&function(t,e){if(t){t=t.split("&");for(var n=0;n2*t.i&&He(t)))}function yn(t,e){return dn(t),e=mn(t,e),ze(t.g.h,e)}function gn(t,e,n){pn(t,e),0=t.j}function In(t){return t.h?1:t.g?t.g.size:0}function _n(t,e){return t.h?t.h==e:t.g&&t.g.has(e)}function Sn(t,e){t.g?t.g.add(e):t.h=e}function An(t,e){t.h&&t.h==e?t.h=null:t.g&&t.g.has(e)&&t.g.delete(e)}function Dn(t){var e,n;if(null!=t.h)return t.i.concat(t.h.D);if(null==t.g||0===t.g.size)return z(t.i);var r=t.i;try{for(var i=D(t.g.values()),o=i.next();!o.done;o=i.next())var s=o.value,r=r.concat(s.D)}catch(t){e={error:t}}finally{try{o&&!o.done&&(n=i.return)&&n.call(i)}finally{if(e)throw e.error}}return r}function Nn(){}function Cn(){this.g=new Nn}function kn(t,e,n,r,i){try{e.onload=null,e.onerror=null,e.onabort=null,e.ontimeout=null,i(r)}catch(t){}}function Rn(t){this.l=t.$b||null,this.j=t.ib||!1}function xn(t,e){Ut.call(this),this.D=t,this.u=e,this.m=void 0,this.readyState=On,this.status=0,this.responseType=this.responseText=this.response=this.statusText="",this.onreadystatechange=null,this.v=new Headers,this.h=null,this.C="GET",this.B="",this.g=!1,this.A=this.j=this.l=null}wn.prototype.cancel=function(){var e,t;if(this.i=Dn(this),this.h)this.h.cancel(),this.h=null;else if(this.g&&0!==this.g.size){try{for(var n=D(this.g.values()),r=n.next();!r.done;r=n.next())r.value.cancel()}catch(t){e={error:t}}finally{try{r&&!r.done&&(t=n.return)&&t.call(n)}finally{if(e)throw e.error}}this.g.clear()}},Nn.prototype.stringify=function(t){return R.JSON.stringify(t,void 0)},Nn.prototype.parse=function(t){return R.JSON.parse(t,void 0)},B(Rn,Te),Rn.prototype.g=function(){return new xn(this.l,this.j)},Rn.prototype.i=(bn={},function(){return bn}),B(xn,Ut);var On=0;function Ln(t){t.j.read().then(t.Sa.bind(t)).catch(t.ha.bind(t))}function Pn(t){t.readyState=4,t.l=null,t.j=null,t.A=null,Mn(t)}function Mn(t){t.onreadystatechange&&t.onreadystatechange.call(t)}(N=xn.prototype).open=function(t,e){if(this.readyState!=On)throw this.abort(),Error("Error reopening a connection");this.C=t,this.B=e,this.readyState=1,Mn(this)},N.send=function(t){if(1!=this.readyState)throw this.abort(),Error("need to call open() first. ");this.g=!0;var e={headers:this.v,method:this.C,credentials:this.m,cache:void 0};t&&(e.body=t),(this.D||R).fetch(new Request(this.B,e)).then(this.Va.bind(this),this.ha.bind(this))},N.abort=function(){this.response=this.responseText="",this.v=new Headers,this.status=0,this.j&&this.j.cancel("Request was aborted."),1<=this.readyState&&this.g&&4!=this.readyState&&(this.g=!1,Pn(this)),this.readyState=On},N.Va=function(t){if(this.g&&(this.l=t,this.h||(this.status=this.l.status,this.statusText=this.l.statusText,this.h=t.headers,this.readyState=2,Mn(this)),this.g&&(this.readyState=3,Mn(this),this.g)))if("arraybuffer"===this.responseType)t.arrayBuffer().then(this.Ta.bind(this),this.ha.bind(this));else if(void 0!==R.ReadableStream&&"body"in t){if(this.j=t.body.getReader(),this.u){if(this.responseType)throw Error('responseType must be empty for "streamBinaryChunks" mode responses.');this.response=[]}else this.response=this.responseText="",this.A=new TextDecoder;Ln(this)}else t.text().then(this.Ua.bind(this),this.ha.bind(this))},N.Sa=function(t){var e;this.g&&(this.u&&t.value?this.response.push(t.value):this.u||(e=t.value||new Uint8Array(0),(e=this.A.decode(e,{stream:!t.done}))&&(this.response=this.responseText+=e)),(t.done?Pn:Mn)(this),3==this.readyState&&Ln(this))},N.Ua=function(t){this.g&&(this.response=this.responseText=t,Pn(this))},N.Ta=function(t){this.g&&(this.response=t,Pn(this))},N.ha=function(){this.g&&Pn(this)},N.setRequestHeader=function(t,e){this.v.append(t,e)},N.getResponseHeader=function(t){return this.h&&this.h.get(t.toLowerCase())||""},N.getAllResponseHeaders=function(){if(!this.h)return"";for(var t=[],e=this.h.entries(),n=e.next();!n.done;)n=n.value,t.push(n[0]+": "+n[1]),n=e.next();return t.join("\r\n")},Object.defineProperty(xn.prototype,"withCredentials",{get:function(){return"include"===this.m},set:function(t){this.m=t?"include":"same-origin"}});var Fn=R.JSON.parse;function Vn(t){Ut.call(this),this.headers=new Qe,this.u=t||null,this.h=!1,this.C=this.g=null,this.H="",this.m=0,this.j="",this.l=this.F=this.v=this.D=!1,this.B=0,this.A=null,this.J=Un,this.K=this.L=!1}B(Vn,Ut);var Un="",qn=/^https?$/i,Bn=["POST","PUT"];function jn(t){return"content-type"==t.toLowerCase()}function Kn(t,e){t.h=!1,t.g&&(t.l=!0,t.g.abort(),t.l=!1),t.j=e,t.m=5,Gn(t),Hn(t)}function Gn(t){t.D||(t.D=!0,qt(t,"complete"),qt(t,"error"))}function Qn(t){if(t.h&&void 0!==k&&(!t.C[1]||4!=Wn(t)||2!=t.ba()))if(t.v&&4==Wn(t))ne(t.Fa,0,t);else if(qt(t,"readystatechange"),4==Wn(t)){t.h=!1;try{var e,n,r,i,o=t.ba();t:switch(o){case 200:case 201:case 202:case 204:case 206:case 304:case 1223:var s=!0;break t;default:s=!1}if((e=s)||((n=0===o)&&(!(i=String(t.H).match(We)[1]||null)&&R.self&&R.self.location&&(i=(r=R.self.location.protocol).substr(0,r.length-1)),n=!qn.test(i?i.toLowerCase():"")),e=n),e)qt(t,"complete"),qt(t,"success");else{t.m=6;try{var a=2=r.i.j-(r.m?1:0)||(r.m?(r.l=i.D.concat(r.l),0):1==r.G||2==r.G||r.C>=(r.Xa?0:r.Ya)||(r.m=be(U(r.Ha,r,i),dr(r,r.C)),r.C++,0))))&&(2!=s||!ur(t)))switch(o&&0e.length?1:0},gi),ai=(n(yi,si=C),yi.prototype.construct=function(t,e,n){return new yi(t,e,n)},yi.prototype.canonicalString=function(){return this.toArray().join("/")},yi.prototype.toString=function(){return this.canonicalString()},yi.fromString=function(){for(var t=[],e=0;et.length&&Qr(),void 0===n?n=t.length-e:n>t.length-e&&Qr(),this.segments=t,this.offset=e,this.len=n}li.EMPTY_BYTE_STRING=new li("");var mi=new RegExp(/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(?:\.(\d+))?Z$/);function vi(t){if(Hr(!!t),"string"!=typeof t)return{seconds:wi(t.seconds),nanos:wi(t.nanos)};var e=0,n=mi.exec(t);Hr(!!n),n[1]&&(n=((n=n[1])+"000000000").substr(0,9),e=Number(n));t=new Date(t);return{seconds:Math.floor(t.getTime()/1e3),nanos:e}}function wi(t){return"number"==typeof t?t:"string"==typeof t?Number(t):0}function bi(t){return"string"==typeof t?li.fromBase64String(t):li.fromUint8Array(t)}function Ei(t){return"server_timestamp"===(null===(t=((null===(t=null==t?void 0:t.mapValue)||void 0===t?void 0:t.fields)||{}).__type__)||void 0===t?void 0:t.stringValue)}function Ti(t){t=vi(t.mapValue.fields.__local_write_time__.timestampValue);return new Jr(t.seconds,t.nanos)}function Ii(t){return null==t}function _i(t){return 0===t&&1/t==-1/0}function Si(t){return"number"==typeof t&&Number.isInteger(t)&&!_i(t)&&t<=Number.MAX_SAFE_INTEGER&&t>=Number.MIN_SAFE_INTEGER}var Ai=(Di.fromPath=function(t){return new Di(ai.fromString(t))},Di.fromName=function(t){return new Di(ai.fromString(t).popFirst(5))},Di.prototype.hasCollectionId=function(t){return 2<=this.path.length&&this.path.get(this.path.length-2)===t},Di.prototype.isEqual=function(t){return null!==t&&0===ai.comparator(this.path,t.path)},Di.prototype.toString=function(){return this.path.toString()},Di.comparator=function(t,e){return ai.comparator(t.path,e.path)},Di.isDocumentKey=function(t){return t.length%2==0},Di.fromSegments=function(t){return new Di(new ai(t.slice()))},Di);function Di(t){this.path=t}function Ni(t){return"nullValue"in t?0:"booleanValue"in t?1:"integerValue"in t||"doubleValue"in t?2:"timestampValue"in t?3:"stringValue"in t?5:"bytesValue"in t?6:"referenceValue"in t?7:"geoPointValue"in t?8:"arrayValue"in t?9:"mapValue"in t?Ei(t)?4:10:Qr()}function Ci(r,i){var t,e,n=Ni(r);if(n!==Ni(i))return!1;switch(n){case 0:return!0;case 1:return r.booleanValue===i.booleanValue;case 4:return Ti(r).isEqual(Ti(i));case 3:return function(t){if("string"==typeof r.timestampValue&&"string"==typeof t.timestampValue&&r.timestampValue.length===t.timestampValue.length)return r.timestampValue===t.timestampValue;var e=vi(r.timestampValue),t=vi(t.timestampValue);return e.seconds===t.seconds&&e.nanos===t.nanos}(i);case 5:return r.stringValue===i.stringValue;case 6:return e=i,bi(r.bytesValue).isEqual(bi(e.bytesValue));case 7:return r.referenceValue===i.referenceValue;case 8:return t=i,wi((e=r).geoPointValue.latitude)===wi(t.geoPointValue.latitude)&&wi(e.geoPointValue.longitude)===wi(t.geoPointValue.longitude);case 2:return function(t,e){if("integerValue"in t&&"integerValue"in e)return wi(t.integerValue)===wi(e.integerValue);if("doubleValue"in t&&"doubleValue"in e){t=wi(t.doubleValue),e=wi(e.doubleValue);return t===e?_i(t)===_i(e):isNaN(t)&&isNaN(e)}return!1}(r,i);case 9:return Xr(r.arrayValue.values||[],i.arrayValue.values||[],Ci);case 10:return function(){var t,e=r.mapValue.fields||{},n=i.mapValue.fields||{};if(ni(e)!==ni(n))return!1;for(t in e)if(e.hasOwnProperty(t)&&(void 0===n[t]||!Ci(e[t],n[t])))return!1;return!0}();default:return Qr()}}function ki(t,e){return void 0!==(t.values||[]).find(function(t){return Ci(t,e)})}function Ri(t,e){var n,r,i,o=Ni(t),s=Ni(e);if(o!==s)return Yr(o,s);switch(o){case 0:return 0;case 1:return Yr(t.booleanValue,e.booleanValue);case 2:return r=e,i=wi(t.integerValue||t.doubleValue),r=wi(r.integerValue||r.doubleValue),i":return 0=":return 0<=t;default:return Qr()}},Ji.prototype.g=function(){return 0<=["<","<=",">",">=","!=","not-in"].indexOf(this.op)},Ji);function Ji(t,e,n){var r=this;return(r=Xi.call(this)||this).field=t,r.op=e,r.value=n,r}var Zi,to,eo,no=(n(ao,eo=$i),ao.prototype.matches=function(t){t=Ai.comparator(t.key,this.key);return this.m(t)},ao),ro=(n(so,to=$i),so.prototype.matches=function(e){return this.keys.some(function(t){return t.isEqual(e.key)})},so),io=(n(oo,Zi=$i),oo.prototype.matches=function(e){return!this.keys.some(function(t){return t.isEqual(e.key)})},oo);function oo(t,e){var n=this;return(n=Zi.call(this,t,"not-in",e)||this).keys=uo(0,e),n}function so(t,e){var n=this;return(n=to.call(this,t,"in",e)||this).keys=uo(0,e),n}function ao(t,e,n){var r=this;return(r=eo.call(this,t,e,n)||this).key=Ai.fromName(n.referenceValue),r}function uo(t,e){return((null===(e=e.arrayValue)||void 0===e?void 0:e.values)||[]).map(function(t){return Ai.fromName(t.referenceValue)})}var co,ho,lo,fo,po=(n(To,fo=$i),To.prototype.matches=function(t){t=t.data.field(this.field);return Mi(t)&&ki(t.arrayValue,this.value)},To),yo=(n(Eo,lo=$i),Eo.prototype.matches=function(t){t=t.data.field(this.field);return null!==t&&ki(this.value.arrayValue,t)},Eo),go=(n(bo,ho=$i),bo.prototype.matches=function(t){if(ki(this.value.arrayValue,{nullValue:"NULL_VALUE"}))return!1;t=t.data.field(this.field);return null!==t&&!ki(this.value.arrayValue,t)},bo),mo=(n(wo,co=$i),wo.prototype.matches=function(t){var e=this,t=t.data.field(this.field);return!(!Mi(t)||!t.arrayValue.values)&&t.arrayValue.values.some(function(t){return ki(e.value.arrayValue,t)})},wo),vo=function(t,e){this.position=t,this.before=e};function wo(t,e){return co.call(this,t,"array-contains-any",e)||this}function bo(t,e){return ho.call(this,t,"not-in",e)||this}function Eo(t,e){return lo.call(this,t,"in",e)||this}function To(t,e){return fo.call(this,t,"array-contains",e)||this}function Io(t){return(t.before?"b":"a")+":"+t.position.map(Oi).join(",")}var _o=function(t,e){void 0===e&&(e="asc"),this.field=t,this.dir=e};function So(t,e,n){for(var r=0,i=0;i":"GREATER_THAN",">=":"GREATER_THAN_OR_EQUAL","==":"EQUAL","!=":"NOT_EQUAL","array-contains":"ARRAY_CONTAINS",in:"IN","not-in":"NOT_IN","array-contains-any":"ARRAY_CONTAINS_ANY"},pa=function(t,e){this.databaseId=t,this.I=e};function ya(t,e){return t.I?new Date(1e3*e.seconds).toISOString().replace(/\.\d*/,"").replace("Z","")+"."+("000000000"+e.nanoseconds).slice(-9)+"Z":{seconds:""+e.seconds,nanos:e.nanoseconds}}function ga(t,e){return t.I?e.toBase64():e.toUint8Array()}function ma(t){return Hr(!!t),Zr.fromTimestamp((t=vi(t),new Jr(t.seconds,t.nanos)))}function va(t,e){return new ai(["projects",t.projectId,"databases",t.database]).child("documents").child(e).canonicalString()}function wa(t){t=ai.fromString(t);return Hr(Ua(t)),t}function ba(t,e){return va(t.databaseId,e.path)}function Ea(t,e){e=wa(e);if(e.get(1)!==t.databaseId.projectId)throw new Fr(Mr.INVALID_ARGUMENT,"Tried to deserialize key from different project: "+e.get(1)+" vs "+t.databaseId.projectId);if(e.get(3)!==t.databaseId.database)throw new Fr(Mr.INVALID_ARGUMENT,"Tried to deserialize key from different database: "+e.get(3)+" vs "+t.databaseId.database);return new Ai(Sa(e))}function Ta(t,e){return va(t.databaseId,e)}function Ia(t){t=wa(t);return 4===t.length?ai.emptyPath():Sa(t)}function _a(t){return new ai(["projects",t.databaseId.projectId,"databases",t.databaseId.database]).canonicalString()}function Sa(t){return Hr(4";case"GREATER_THAN_OR_EQUAL":return">=";case"LESS_THAN":return"<";case"LESS_THAN_OR_EQUAL":return"<=";case"ARRAY_CONTAINS":return"array-contains";case"IN":return"in";case"NOT_IN":return"not-in";case"ARRAY_CONTAINS_ANY":return"array-contains-any";case"OPERATOR_UNSPECIFIED":default:return Qr()}}(),t.fieldFilter.value)}function Va(t){switch(t.unaryFilter.op){case"IS_NAN":var e=Ma(t.unaryFilter.field);return $i.create(e,"==",{doubleValue:NaN});case"IS_NULL":e=Ma(t.unaryFilter.field);return $i.create(e,"==",{nullValue:"NULL_VALUE"});case"IS_NOT_NAN":var n=Ma(t.unaryFilter.field);return $i.create(n,"!=",{doubleValue:NaN});case"IS_NOT_NULL":n=Ma(t.unaryFilter.field);return $i.create(n,"!=",{nullValue:"NULL_VALUE"});case"OPERATOR_UNSPECIFIED":default:return Qr()}}function Ua(t){return 4<=t.length&&"projects"===t.get(0)&&"databases"===t.get(2)}function qa(t){for(var e="",n=0;n",t),this.store.put(t));return _u(t)},Iu.prototype.add=function(t){return Br("SimpleDb","ADD",this.store.name,t,t),_u(this.store.add(t))},Iu.prototype.get=function(e){var n=this;return _u(this.store.get(e)).next(function(t){return Br("SimpleDb","GET",n.store.name,e,t=void 0===t?null:t),t})},Iu.prototype.delete=function(t){return Br("SimpleDb","DELETE",this.store.name,t),_u(this.store.delete(t))},Iu.prototype.count=function(){return Br("SimpleDb","COUNT",this.store.name),_u(this.store.count())},Iu.prototype.Nt=function(t,e){var e=this.cursor(this.options(t,e)),n=[];return this.xt(e,function(t,e){n.push(e)}).next(function(){return n})},Iu.prototype.Ft=function(t,e){Br("SimpleDb","DELETE ALL",this.store.name);e=this.options(t,e);e.kt=!1;e=this.cursor(e);return this.xt(e,function(t,e,n){return n.delete()})},Iu.prototype.$t=function(t,e){e?n=t:(n={},e=t);var n=this.cursor(n);return this.xt(n,e)},Iu.prototype.Ot=function(r){var t=this.cursor({});return new hu(function(n,e){t.onerror=function(t){t=Au(t.target.error);e(t)},t.onsuccess=function(t){var e=t.target.result;e?r(e.primaryKey,e.value).next(function(t){t?e.continue():n()}):n()}})},Iu.prototype.xt=function(t,i){var o=[];return new hu(function(r,e){t.onerror=function(t){e(t.target.error)},t.onsuccess=function(t){var e,n=t.target.result;n?(e=new du(n),(t=i(n.primaryKey,n.value,e))instanceof hu&&(t=t.catch(function(t){return e.done(),hu.reject(t)}),o.push(t)),e.isDone?r():null===e.Dt?n.continue():n.continue(e.Dt)):r()}}).next(function(){return hu.waitFor(o)})},Iu.prototype.options=function(t,e){var n;return void 0!==t&&("string"==typeof t?n=t:e=t),{index:n,range:e}},Iu.prototype.cursor=function(t){var e="next";if(t.reverse&&(e="prev"),t.index){var n=this.store.index(t.index);return t.kt?n.openKeyCursor(t.range,e):n.openCursor(t.range,e)}return this.store.openCursor(t.range,e)},Iu);function Iu(t){this.store=t}function _u(t){return new hu(function(e,n){t.onsuccess=function(t){t=t.target.result;e(t)},t.onerror=function(t){t=Au(t.target.error);n(t)}})}var Su=!1;function Au(t){var e=fu._t(h());if(12.2<=e&&e<13){e="An internal error was encountered in the Indexed Database server";if(0<=t.message.indexOf(e)){var n=new Fr("internal","IOS_INDEXEDDB_BUG1: IndexedDb has thrown '"+e+"'. This is likely due to an unavoidable bug in iOS. See https://stackoverflow.com/q/56496296/110915 for details and a potential workaround.");return Su||(Su=!0,setTimeout(function(){throw n},0)),n}}return t}var Du,Nu=(n(Cu,Du=C),Cu);function Cu(t,e){var n=this;return(n=Du.call(this)||this).Mt=t,n.currentSequenceNumber=e,n}function ku(t,e){return fu.It(t.Mt,e)}var Ru=(Fu.prototype.applyToRemoteDocument=function(t,e){for(var n,r,i,o,s,a,u=e.mutationResults,c=0;c=i),o=Gu(r.R,e)),n.done()}).next(function(){return o})},lc.prototype.getHighestUnacknowledgedBatchId=function(t){var e=IDBKeyRange.upperBound([this.userId,Number.POSITIVE_INFINITY]),r=-1;return dc(t).$t({index:Ha.userMutationsIndex,range:e,reverse:!0},function(t,e,n){r=e.batchId,n.done()}).next(function(){return r})},lc.prototype.getAllMutationBatches=function(t){var e=this,n=IDBKeyRange.bound([this.userId,-1],[this.userId,Number.POSITIVE_INFINITY]);return dc(t).Nt(Ha.userMutationsIndex,n).next(function(t){return t.map(function(t){return Gu(e.R,t)})})},lc.prototype.getAllMutationBatchesAffectingDocumentKey=function(o,s){var a=this,t=za.prefixForPath(this.userId,s.path),t=IDBKeyRange.lowerBound(t),u=[];return pc(o).$t({range:t},function(t,e,n){var r=t[0],i=t[1],t=t[2],i=ja(i);if(r===a.userId&&s.path.isEqual(i))return dc(o).get(t).next(function(t){if(!t)throw Qr();Hr(t.userId===a.userId),u.push(Gu(a.R,t))});n.done()}).next(function(){return u})},lc.prototype.getAllMutationBatchesAffectingDocumentKeys=function(e,t){var s=this,a=new Ks(Yr),n=[];return t.forEach(function(o){var t=za.prefixForPath(s.userId,o.path),t=IDBKeyRange.lowerBound(t),t=pc(e).$t({range:t},function(t,e,n){var r=t[0],i=t[1],t=t[2],i=ja(i);r===s.userId&&o.path.isEqual(i)?a=a.add(t):n.done()});n.push(t)}),hu.waitFor(n).next(function(){return s.Wt(e,a)})},lc.prototype.getAllMutationBatchesAffectingQuery=function(t,e){var o=this,s=e.path,a=s.length+1,e=za.prefixForPath(this.userId,s),e=IDBKeyRange.lowerBound(e),u=new Ks(Yr);return pc(t).$t({range:e},function(t,e,n){var r=t[0],i=t[1],t=t[2],i=ja(i);r===o.userId&&s.isPrefixOf(i)?i.length===a&&(u=u.add(t)):n.done()}).next(function(){return o.Wt(t,u)})},lc.prototype.Wt=function(e,t){var n=this,r=[],i=[];return t.forEach(function(t){i.push(dc(e).get(t).next(function(t){if(null===t)throw Qr();Hr(t.userId===n.userId),r.push(Gu(n.R,t))}))}),hu.waitFor(i).next(function(){return r})},lc.prototype.removeMutationBatch=function(e,n){var r=this;return uc(e.Mt,this.userId,n).next(function(t){return e.addOnCommittedListener(function(){r.Gt(n.batchId)}),hu.forEach(t,function(t){return r.referenceDelegate.markPotentiallyOrphaned(e,t)})})},lc.prototype.Gt=function(t){delete this.Kt[t]},lc.prototype.performConsistencyCheck=function(e){var i=this;return this.checkEmpty(e).next(function(t){if(!t)return hu.resolve();var t=IDBKeyRange.lowerBound(za.prefixForUser(i.userId)),r=[];return pc(e).$t({range:t},function(t,e,n){t[0]===i.userId?(t=ja(t[1]),r.push(t)):n.done()}).next(function(){Hr(0===r.length)})})},lc.prototype.containsKey=function(t,e){return fc(t,this.userId,e)},lc.prototype.zt=function(t){var e=this;return yc(t).get(this.userId).next(function(t){return t||new Qa(e.userId,-1,"")})},lc);function lc(t,e,n,r){this.userId=t,this.R=e,this.Ut=n,this.referenceDelegate=r,this.Kt={}}function fc(t,o,e){var e=za.prefixForPath(o,e.path),s=e[1],e=IDBKeyRange.lowerBound(e),a=!1;return pc(t).$t({range:e,kt:!0},function(t,e,n){var r=t[0],i=t[1];t[2],r===o&&i===s&&(a=!0),n.done()}).next(function(){return a})}function dc(t){return ku(t,Ha.store)}function pc(t){return ku(t,za.store)}function yc(t){return ku(t,Qa.store)}var gc=(wc.prototype.next=function(){return this.Ht+=2,this.Ht},wc.Jt=function(){return new wc(0)},wc.Yt=function(){return new wc(-1)},wc),mc=(vc.prototype.allocateTargetId=function(n){var r=this;return this.Xt(n).next(function(t){var e=new gc(t.highestTargetId);return t.highestTargetId=e.next(),r.Zt(n,t).next(function(){return t.highestTargetId})})},vc.prototype.getLastRemoteSnapshotVersion=function(t){return this.Xt(t).next(function(t){return Zr.fromTimestamp(new Jr(t.lastRemoteSnapshotVersion.seconds,t.lastRemoteSnapshotVersion.nanoseconds))})},vc.prototype.getHighestSequenceNumber=function(t){return this.Xt(t).next(function(t){return t.highestListenSequenceNumber})},vc.prototype.setTargetsMetadata=function(e,n,r){var i=this;return this.Xt(e).next(function(t){return t.highestListenSequenceNumber=n,r&&(t.lastRemoteSnapshotVersion=r.toTimestamp()),n>t.highestListenSequenceNumber&&(t.highestListenSequenceNumber=n),i.Zt(e,t)})},vc.prototype.addTargetData=function(e,n){var r=this;return this.te(e,n).next(function(){return r.Xt(e).next(function(t){return t.targetCount+=1,r.ee(n,t),r.Zt(e,t)})})},vc.prototype.updateTargetData=function(t,e){return this.te(t,e)},vc.prototype.removeTargetData=function(e,t){var n=this;return this.removeMatchingKeysForTargetId(e,t.targetId).next(function(){return bc(e).delete(t.targetId)}).next(function(){return n.Xt(e)}).next(function(t){return Hr(0e.highestTargetId&&(e.highestTargetId=t.targetId,n=!0),t.sequenceNumber>e.highestListenSequenceNumber&&(e.highestListenSequenceNumber=t.sequenceNumber,n=!0),n},vc.prototype.getTargetCount=function(t){return this.Xt(t).next(function(t){return t.targetCount})},vc.prototype.getTargetData=function(t,r){var e=zi(r),e=IDBKeyRange.bound([e,Number.NEGATIVE_INFINITY],[e,Number.POSITIVE_INFINITY]),i=null;return bc(t).$t({range:e,index:Za.queryTargetsIndexName},function(t,e,n){e=Qu(e);Wi(r,e.target)&&(i=e,n.done())}).next(function(){return i})},vc.prototype.addMatchingKeys=function(n,t,r){var i=this,o=[],s=Tc(n);return t.forEach(function(t){var e=qa(t.path);o.push(s.put(new tu(r,e))),o.push(i.referenceDelegate.addReference(n,r,t))}),hu.waitFor(o)},vc.prototype.removeMatchingKeys=function(n,t,r){var i=this,o=Tc(n);return hu.forEach(t,function(t){var e=qa(t.path);return hu.waitFor([o.delete([r,e]),i.referenceDelegate.removeReference(n,r,t)])})},vc.prototype.removeMatchingKeysForTargetId=function(t,e){t=Tc(t),e=IDBKeyRange.bound([e],[e+1],!1,!0);return t.delete(e)},vc.prototype.getMatchingKeysForTargetId=function(t,e){var e=IDBKeyRange.bound([e],[e+1],!1,!0),t=Tc(t),r=$s();return t.$t({range:e,kt:!0},function(t,e,n){t=ja(t[1]),t=new Ai(t);r=r.add(t)}).next(function(){return r})},vc.prototype.containsKey=function(t,e){var e=qa(e.path),e=IDBKeyRange.bound([e],[$r(e)],!1,!0),i=0;return Tc(t).$t({index:tu.documentTargetsIndex,kt:!0,range:e},function(t,e,n){var r=t[0];t[1],0!==r&&(i++,n.done())}).next(function(){return 0h.params.maximumSequenceNumbersToCollect?(Br("LruGarbageCollector","Capping sequence numbers to collect down to the maximum of "+h.params.maximumSequenceNumbersToCollect+" from "+t),h.params.maximumSequenceNumbersToCollect):t,s=Date.now(),h.nthSequenceNumber(e,i)}).next(function(t){return r=t,a=Date.now(),h.removeTargets(e,r,n)}).next(function(t){return o=t,u=Date.now(),h.removeOrphanedDocuments(e,r)}).next(function(t){return c=Date.now(),qr()<=m.DEBUG&&Br("LruGarbageCollector","LRU Garbage Collection\n\tCounted targets in "+(s-l)+"ms\n\tDetermined least recently used "+i+" in "+(a-s)+"ms\n\tRemoved "+o+" targets in "+(u-a)+"ms\n\tRemoved "+t+" documents in "+(c-u)+"ms\nTotal Duration: "+(c-l)+"ms"),hu.resolve({didRun:!0,sequenceNumbersCollected:i,targetsRemoved:o,documentsRemoved:t})})},kc),Nc=(Cc.prototype.he=function(t){var n=this.de(t);return this.db.getTargetCache().getTargetCount(t).next(function(e){return n.next(function(t){return e+t})})},Cc.prototype.de=function(t){var e=0;return this.le(t,function(t){e++}).next(function(){return e})},Cc.prototype.forEachTarget=function(t,e){return this.db.getTargetCache().forEachTarget(t,e)},Cc.prototype.le=function(t,n){return this.we(t,function(t,e){return n(e)})},Cc.prototype.addReference=function(t,e,n){return Oc(t,n)},Cc.prototype.removeReference=function(t,e,n){return Oc(t,n)},Cc.prototype.removeTargets=function(t,e,n){return this.db.getTargetCache().removeTargets(t,e,n)},Cc.prototype.markPotentiallyOrphaned=Oc,Cc.prototype._e=function(t,e){return r=e,i=!1,yc(n=t).Ot(function(t){return fc(n,t,r).next(function(t){return t&&(i=!0),hu.resolve(!t)})}).next(function(){return i});var n,r,i},Cc.prototype.removeOrphanedDocuments=function(n,r){var i=this,o=this.db.getRemoteDocumentCache().newChangeBuffer(),s=[],a=0;return this.we(n,function(e,t){t<=r&&(t=i._e(n,e).next(function(t){if(!t)return a++,o.getEntry(n,e).next(function(){return o.removeEntry(e),Tc(n).delete([0,qa(e.path)])})}),s.push(t))}).next(function(){return hu.waitFor(s)}).next(function(){return o.apply(n)}).next(function(){return a})},Cc.prototype.removeTarget=function(t,e){e=e.withSequenceNumber(t.currentSequenceNumber);return this.db.getTargetCache().updateTargetData(t,e)},Cc.prototype.updateLimboDocument=Oc,Cc.prototype.we=function(t,r){var i,t=Tc(t),o=Or.o;return t.$t({index:tu.documentTargetsIndex},function(t,e){var n=t[0];t[1];t=e.path,e=e.sequenceNumber;0===n?(o!==Or.o&&r(new Ai(ja(i)),o),o=e,i=t):o=Or.o}).next(function(){o!==Or.o&&r(new Ai(ja(i)),o)})},Cc.prototype.getCacheSize=function(t){return this.db.getRemoteDocumentCache().getSize(t)},Cc);function Cc(t,e){this.db=t,this.garbageCollector=new Dc(this,e)}function kc(t,e){this.ae=t,this.params=e}function Rc(t,e){this.garbageCollector=t,this.asyncQueue=e,this.oe=!1,this.ce=null}function xc(t){this.ne=t,this.buffer=new Ks(_c),this.se=0}function Oc(t,e){return Tc(t).put((t=t.currentSequenceNumber,new tu(0,qa(e.path),t)))}var Lc,Pc=(Bc.prototype.get=function(t){var e=this.mapKeyFn(t),e=this.inner[e];if(void 0!==e)for(var n=0,r=e;n "+n),1))},Xc.prototype.We=function(){var t=this;null!==this.document&&"function"==typeof this.document.addEventListener&&(this.ke=function(){t.Se.enqueueAndForget(function(){return t.inForeground="visible"===t.document.visibilityState,t.je()})},this.document.addEventListener("visibilitychange",this.ke),this.inForeground="visible"===this.document.visibilityState)},Xc.prototype.an=function(){this.ke&&(this.document.removeEventListener("visibilitychange",this.ke),this.ke=null)},Xc.prototype.Ge=function(){var t,e=this;"function"==typeof(null===(t=this.window)||void 0===t?void 0:t.addEventListener)&&(this.Fe=function(){e.un(),i()&&navigator.appVersion.match("Version/14")&&e.Se.enterRestrictedMode(!0),e.Se.enqueueAndForget(function(){return e.shutdown()})},this.window.addEventListener("pagehide",this.Fe))},Xc.prototype.hn=function(){this.Fe&&(this.window.removeEventListener("pagehide",this.Fe),this.Fe=null)},Xc.prototype.cn=function(t){var e;try{var n=null!==(null===(e=this.Qe)||void 0===e?void 0:e.getItem(this.on(t)));return Br("IndexedDbPersistence","Client '"+t+"' "+(n?"is":"is not")+" zombied in LocalStorage"),n}catch(t){return jr("IndexedDbPersistence","Failed to get zombied client id.",t),!1}},Xc.prototype.un=function(){if(this.Qe)try{this.Qe.setItem(this.on(this.clientId),String(Date.now()))}catch(t){jr("Failed to set zombie client id.",t)}},Xc.prototype.ln=function(){if(this.Qe)try{this.Qe.removeItem(this.on(this.clientId))}catch(t){}},Xc.prototype.on=function(t){return"firestore_zombie_"+this.persistenceKey+"_"+t},Xc);function Xc(t,e,n,r,i,o,s,a,u,c){if(this.allowTabSynchronization=t,this.persistenceKey=e,this.clientId=n,this.Se=i,this.window=o,this.document=s,this.De=u,this.Ce=c,this.Ne=null,this.xe=!1,this.isPrimary=!1,this.networkEnabled=!0,this.Fe=null,this.inForeground=!1,this.ke=null,this.$e=null,this.Oe=Number.NEGATIVE_INFINITY,this.Me=function(t){return Promise.resolve()},!Xc.yt())throw new Fr(Mr.UNIMPLEMENTED,"This platform is either missing IndexedDB or is known to have an incomplete implementation. Offline persistence has been disabled.");this.referenceDelegate=new Nc(this,r),this.Le=e+"main",this.R=new Lu(a),this.Be=new fu(this.Le,11,new Qc(this.R)),this.qe=new mc(this.referenceDelegate,this.R),this.Ut=new tc,this.Ue=(e=this.R,a=this.Ut,new Mc(e,a)),this.Ke=new Wu,this.window&&this.window.localStorage?this.Qe=this.window.localStorage:(this.Qe=null,!1===c&&jr("IndexedDbPersistence","LocalStorage is unavailable. As a result, persistence may not work reliably. In particular enablePersistence() could fail immediately after refreshing the page."))}function $c(t){return ku(t,Ka.store)}function Jc(t){return ku(t,ru.store)}function Zc(t,e){var n=t.projectId;return t.isDefaultDatabase||(n+="."+t.database),"firestore/"+e+"/"+n+"/"}function th(t,e){this.progress=t,this.wn=e}var eh=(uh.prototype.mn=function(e,n){var r=this;return this._n.getAllMutationBatchesAffectingDocumentKey(e,n).next(function(t){return r.yn(e,n,t)})},uh.prototype.yn=function(t,e,r){return this.Ue.getEntry(t,e).next(function(t){for(var e=0,n=r;ee?this._n[e]:null)},Bh.prototype.getHighestUnacknowledgedBatchId=function(){return hu.resolve(0===this._n.length?-1:this.ss-1)},Bh.prototype.getAllMutationBatches=function(t){return hu.resolve(this._n.slice())},Bh.prototype.getAllMutationBatchesAffectingDocumentKey=function(t,e){var n=this,r=new Sh(e,0),e=new Sh(e,Number.POSITIVE_INFINITY),i=[];return this.rs.forEachInRange([r,e],function(t){t=n.os(t.ns);i.push(t)}),hu.resolve(i)},Bh.prototype.getAllMutationBatchesAffectingDocumentKeys=function(t,e){var n=this,r=new Ks(Yr);return e.forEach(function(t){var e=new Sh(t,0),t=new Sh(t,Number.POSITIVE_INFINITY);n.rs.forEachInRange([e,t],function(t){r=r.add(t.ns)})}),hu.resolve(this.us(r))},Bh.prototype.getAllMutationBatchesAffectingQuery=function(t,e){var n=e.path,r=n.length+1,e=n;Ai.isDocumentKey(e)||(e=e.child(""));var e=new Sh(new Ai(e),0),i=new Ks(Yr);return this.rs.forEachWhile(function(t){var e=t.key.path;return!!n.isPrefixOf(e)&&(e.length===r&&(i=i.add(t.ns)),!0)},e),hu.resolve(this.us(i))},Bh.prototype.us=function(t){var e=this,n=[];return t.forEach(function(t){t=e.os(t);null!==t&&n.push(t)}),n},Bh.prototype.removeMutationBatch=function(n,r){var i=this;Hr(0===this.hs(r.batchId,"removed")),this._n.shift();var o=this.rs;return hu.forEach(r.mutations,function(t){var e=new Sh(t.key,r.batchId);return o=o.delete(e),i.referenceDelegate.markPotentiallyOrphaned(n,t.key)}).next(function(){i.rs=o})},Bh.prototype.Gt=function(t){},Bh.prototype.containsKey=function(t,e){var n=new Sh(e,0),n=this.rs.firstAfterOrEqual(n);return hu.resolve(e.isEqual(n&&n.key))},Bh.prototype.performConsistencyCheck=function(t){return this._n.length,hu.resolve()},Bh.prototype.hs=function(t,e){return this.cs(t)},Bh.prototype.cs=function(t){return 0===this._n.length?0:t-this._n[0].batchId},Bh.prototype.os=function(t){t=this.cs(t);return t<0||t>=this._n.length?null:this._n[t]},Bh),Dh=(qh.prototype.addEntry=function(t,e,n){var r=e.key,i=this.docs.get(r),o=i?i.size:0,i=this.ls(e);return this.docs=this.docs.insert(r,{document:e.clone(),size:i,readTime:n}),this.size+=i-o,this.Ut.addToCollectionParentIndex(t,r.path.popLast())},qh.prototype.removeEntry=function(t){var e=this.docs.get(t);e&&(this.docs=this.docs.remove(t),this.size-=e.size)},qh.prototype.getEntry=function(t,e){var n=this.docs.get(e);return hu.resolve(n?n.document.clone():Ki.newInvalidDocument(e))},qh.prototype.getEntries=function(t,e){var n=this,r=Qs;return e.forEach(function(t){var e=n.docs.get(t);r=r.insert(t,e?e.document.clone():Ki.newInvalidDocument(t))}),hu.resolve(r)},qh.prototype.getDocumentsMatchingQuery=function(t,e,n){for(var r=Qs,i=new Ai(e.path.child("")),o=this.docs.getIteratorFrom(i);o.hasNext();){var s=o.getNext(),a=s.key,u=s.value,s=u.document,u=u.readTime;if(!e.path.isPrefixOf(a.path))break;u.compareTo(n)<=0||Bo(e,s)&&(r=r.insert(s.key,s.clone()))}return hu.resolve(r)},qh.prototype.fs=function(t,e){return hu.forEach(this.docs,function(t){return e(t)})},qh.prototype.newChangeBuffer=function(t){return new Nh(this)},qh.prototype.getSize=function(t){return hu.resolve(this.size)},qh),Nh=(n(Uh,Th=_),Uh.prototype.applyChanges=function(n){var r=this,i=[];return this.changes.forEach(function(t,e){e.document.isValidDocument()?i.push(r.Ie.addEntry(n,e.document,r.getReadTime(t))):r.Ie.removeEntry(t)}),hu.waitFor(i)},Uh.prototype.getFromCache=function(t,e){return this.Ie.getEntry(t,e)},Uh.prototype.getAllFromCache=function(t,e){return this.Ie.getEntries(t,e)},Uh),Ch=(Vh.prototype.forEachTarget=function(t,n){return this.ds.forEach(function(t,e){return n(e)}),hu.resolve()},Vh.prototype.getLastRemoteSnapshotVersion=function(t){return hu.resolve(this.lastRemoteSnapshotVersion)},Vh.prototype.getHighestSequenceNumber=function(t){return hu.resolve(this.ws)},Vh.prototype.allocateTargetId=function(t){return this.highestTargetId=this.ys.next(),hu.resolve(this.highestTargetId)},Vh.prototype.setTargetsMetadata=function(t,e,n){return n&&(this.lastRemoteSnapshotVersion=n),e>this.ws&&(this.ws=e),hu.resolve()},Vh.prototype.te=function(t){this.ds.set(t.target,t);var e=t.targetId;e>this.highestTargetId&&(this.ys=new gc(e),this.highestTargetId=e),t.sequenceNumber>this.ws&&(this.ws=t.sequenceNumber)},Vh.prototype.addTargetData=function(t,e){return this.te(e),this.targetCount+=1,hu.resolve()},Vh.prototype.updateTargetData=function(t,e){return this.te(e),hu.resolve()},Vh.prototype.removeTargetData=function(t,e){return this.ds.delete(e.target),this._s.Zn(e.targetId),--this.targetCount,hu.resolve()},Vh.prototype.removeTargets=function(n,r,i){var o=this,s=0,a=[];return this.ds.forEach(function(t,e){e.sequenceNumber<=r&&null===i.get(e.targetId)&&(o.ds.delete(t),a.push(o.removeMatchingKeysForTargetId(n,e.targetId)),s++)}),hu.waitFor(a).next(function(){return s})},Vh.prototype.getTargetCount=function(t){return hu.resolve(this.targetCount)},Vh.prototype.getTargetData=function(t,e){e=this.ds.get(e)||null;return hu.resolve(e)},Vh.prototype.addMatchingKeys=function(t,e,n){return this._s.Jn(e,n),hu.resolve()},Vh.prototype.removeMatchingKeys=function(e,t,n){this._s.Xn(t,n);var r=this.persistence.referenceDelegate,i=[];return r&&t.forEach(function(t){i.push(r.markPotentiallyOrphaned(e,t))}),hu.waitFor(i)},Vh.prototype.removeMatchingKeysForTargetId=function(t,e){return this._s.Zn(e),hu.resolve()},Vh.prototype.getMatchingKeysForTargetId=function(t,e){e=this._s.es(e);return hu.resolve(e)},Vh.prototype.containsKey=function(t,e){return hu.resolve(this._s.containsKey(e))},Vh),kh=(Fh.prototype.start=function(){return Promise.resolve()},Fh.prototype.shutdown=function(){return this.xe=!1,Promise.resolve()},Object.defineProperty(Fh.prototype,"started",{get:function(){return this.xe},enumerable:!1,configurable:!0}),Fh.prototype.setDatabaseDeletedListener=function(){},Fh.prototype.setNetworkEnabled=function(){},Fh.prototype.getIndexManager=function(){return this.Ut},Fh.prototype.getMutationQueue=function(t){var e=this.gs[t.toKey()];return e||(e=new Ah(this.Ut,this.referenceDelegate),this.gs[t.toKey()]=e),e},Fh.prototype.getTargetCache=function(){return this.qe},Fh.prototype.getRemoteDocumentCache=function(){return this.Ue},Fh.prototype.getBundleCache=function(){return this.Ke},Fh.prototype.runTransaction=function(t,e,n){var r=this;Br("MemoryPersistence","Starting transaction:",t);var i=new Rh(this.Ne.next());return this.referenceDelegate.Es(),n(i).next(function(t){return r.referenceDelegate.Ts(i).next(function(){return t})}).toPromise().then(function(t){return i.raiseOnCommittedEvent(),t})},Fh.prototype.Is=function(e,n){return hu.or(Object.values(this.gs).map(function(t){return function(){return t.containsKey(e,n)}}))},Fh),Rh=(n(Mh,Eh=C),Mh),xh=(Ph.bs=function(t){return new Ph(t)},Object.defineProperty(Ph.prototype,"vs",{get:function(){if(this.Rs)return this.Rs;throw Qr()},enumerable:!1,configurable:!0}),Ph.prototype.addReference=function(t,e,n){return this.As.addReference(n,e),this.vs.delete(n.toString()),hu.resolve()},Ph.prototype.removeReference=function(t,e,n){return this.As.removeReference(n,e),this.vs.add(n.toString()),hu.resolve()},Ph.prototype.markPotentiallyOrphaned=function(t,e){return this.vs.add(e.toString()),hu.resolve()},Ph.prototype.removeTarget=function(t,e){var n=this;this.As.Zn(e.targetId).forEach(function(t){return n.vs.add(t.toString())});var r=this.persistence.getTargetCache();return r.getMatchingKeysForTargetId(t,e.targetId).next(function(t){t.forEach(function(t){return n.vs.add(t.toString())})}).next(function(){return r.removeTargetData(t,e)})},Ph.prototype.Es=function(){this.Rs=new Set},Ph.prototype.Ts=function(n){var r=this,i=this.persistence.getRemoteDocumentCache().newChangeBuffer();return hu.forEach(this.vs,function(t){var e=Ai.fromPath(t);return r.Ps(n,e).next(function(t){t||i.removeEntry(e)})}).next(function(){return r.Rs=null,i.apply(n)})},Ph.prototype.updateLimboDocument=function(t,e){var n=this;return this.Ps(t,e).next(function(t){t?n.vs.delete(e.toString()):n.vs.add(e.toString())})},Ph.prototype.ps=function(t){return 0},Ph.prototype.Ps=function(t,e){var n=this;return hu.or([function(){return hu.resolve(n.As.containsKey(e))},function(){return n.persistence.getTargetCache().containsKey(t,e)},function(){return n.persistence.Is(t,e)}])},Ph),Oh=(Lh.prototype.isAuthenticated=function(){return null!=this.uid},Lh.prototype.toKey=function(){return this.isAuthenticated()?"uid:"+this.uid:"anonymous-user"},Lh.prototype.isEqual=function(t){return t.uid===this.uid},Lh);function Lh(t){this.uid=t}function Ph(t){this.persistence=t,this.As=new _h,this.Rs=null}function Mh(t){var e=this;return(e=Eh.call(this)||this).currentSequenceNumber=t,e}function Fh(t,e){var n=this;this.gs={},this.Ne=new Or(0),this.xe=!1,this.xe=!0,this.referenceDelegate=t(this),this.qe=new Ch(this),this.Ut=new Ju,this.Ue=(t=this.Ut,new Dh(t,function(t){return n.referenceDelegate.ps(t)})),this.R=new Lu(e),this.Ke=new Ih(this.R)}function Vh(t){this.persistence=t,this.ds=new Pc(zi,Wi),this.lastRemoteSnapshotVersion=Zr.min(),this.highestTargetId=0,this.ws=0,this._s=new _h,this.targetCount=0,this.ys=gc.Jt()}function Uh(t){var e=this;return(e=Th.call(this)||this).Ie=t,e}function qh(t,e){this.Ut=t,this.ls=e,this.docs=new Ms(Ai.comparator),this.size=0}function Bh(t,e){this.Ut=t,this.referenceDelegate=e,this._n=[],this.ss=1,this.rs=new Ks(Sh.Gn)}function jh(t,e){this.key=t,this.ns=e}function Kh(){this.Wn=new Ks(Sh.Gn),this.zn=new Ks(Sh.Hn)}function Gh(t){this.R=t,this.Qn=new Map,this.jn=new Map}function Qh(t,e){return"firestore_clients_"+t+"_"+e}function Hh(t,e,n){n="firestore_mutations_"+t+"_"+n;return e.isAuthenticated()&&(n+="_"+e.uid),n}function zh(t,e){return"firestore_targets_"+t+"_"+e}Oh.UNAUTHENTICATED=new Oh(null),Oh.GOOGLE_CREDENTIALS=new Oh("google-credentials-uid"),Oh.FIRST_PARTY=new Oh("first-party-uid");var Wh,Yh=(vl.Vs=function(t,e,n){var r,i=JSON.parse(n),o="object"==typeof i&&-1!==["pending","acknowledged","rejected"].indexOf(i.state)&&(void 0===i.error||"object"==typeof i.error);return o&&i.error&&(o="string"==typeof i.error.message&&"string"==typeof i.error.code)&&(r=new Fr(i.error.code,i.error.message)),o?new vl(t,e,i.state,r):(jr("SharedClientState","Failed to parse mutation state for ID '"+e+"': "+n),null)},vl.prototype.Ss=function(){var t={state:this.state,updateTimeMs:Date.now()};return this.error&&(t.error={code:this.error.code,message:this.error.message}),JSON.stringify(t)},vl),Xh=(ml.Vs=function(t,e){var n,r=JSON.parse(e),i="object"==typeof r&&-1!==["not-current","current","rejected"].indexOf(r.state)&&(void 0===r.error||"object"==typeof r.error);return i&&r.error&&(i="string"==typeof r.error.message&&"string"==typeof r.error.code)&&(n=new Fr(r.error.code,r.error.message)),i?new ml(t,r.state,n):(jr("SharedClientState","Failed to parse target state for ID '"+t+"': "+e),null)},ml.prototype.Ss=function(){var t={state:this.state,updateTimeMs:Date.now()};return this.error&&(t.error={code:this.error.code,message:this.error.message}),JSON.stringify(t)},ml),$h=(gl.Vs=function(t,e){for(var n=JSON.parse(e),r="object"==typeof n&&n.activeTargetIds instanceof Array,i=Js,o=0;r&&othis.Bi&&(this.qi=this.Bi)},Ml.prototype.Gi=function(){null!==this.Ui&&(this.Ui.skipDelay(),this.Ui=null)},Ml.prototype.cancel=function(){null!==this.Ui&&(this.Ui.cancel(),this.Ui=null)},Ml.prototype.Wi=function(){return(Math.random()-.5)*this.qi},Ml),_=(Pl.prototype.tr=function(){return 1===this.state||2===this.state||4===this.state},Pl.prototype.er=function(){return 2===this.state},Pl.prototype.start=function(){3!==this.state?this.auth():this.nr()},Pl.prototype.stop=function(){return y(this,void 0,void 0,function(){return g(this,function(t){switch(t.label){case 0:return this.tr()?[4,this.close(0)]:[3,2];case 1:t.sent(),t.label=2;case 2:return[2]}})})},Pl.prototype.sr=function(){this.state=0,this.Zi.reset()},Pl.prototype.ir=function(){var t=this;this.er()&&null===this.Xi&&(this.Xi=this.Se.enqueueAfterDelay(this.zi,6e4,function(){return t.rr()}))},Pl.prototype.cr=function(t){this.ur(),this.stream.send(t)},Pl.prototype.rr=function(){return y(this,void 0,void 0,function(){return g(this,function(t){return this.er()?[2,this.close(0)]:[2]})})},Pl.prototype.ur=function(){this.Xi&&(this.Xi.cancel(),this.Xi=null)},Pl.prototype.close=function(e,n){return y(this,void 0,void 0,function(){return g(this,function(t){switch(t.label){case 0:return this.ur(),this.Zi.cancel(),this.Yi++,3!==e?this.Zi.reset():n&&n.code===Mr.RESOURCE_EXHAUSTED?(jr(n.toString()),jr("Using maximum backoff delay to prevent overloading the backend."),this.Zi.Qi()):n&&n.code===Mr.UNAUTHENTICATED&&this.Ji.invalidateToken(),null!==this.stream&&(this.ar(),this.stream.close(),this.stream=null),this.state=e,[4,this.listener.Ri(n)];case 1:return t.sent(),[2]}})})},Pl.prototype.ar=function(){},Pl.prototype.auth=function(){var n=this;this.state=1;var t=this.hr(this.Yi),e=this.Yi;this.Ji.getToken().then(function(t){n.Yi===e&&n.lr(t)},function(e){t(function(){var t=new Fr(Mr.UNKNOWN,"Fetching auth token failed: "+e.message);return n.dr(t)})})},Pl.prototype.lr=function(t){var e=this,n=this.hr(this.Yi);this.stream=this.wr(t),this.stream.Ii(function(){n(function(){return e.state=2,e.listener.Ii()})}),this.stream.Ri(function(t){n(function(){return e.dr(t)})}),this.stream.onMessage(function(t){n(function(){return e.onMessage(t)})})},Pl.prototype.nr=function(){var t=this;this.state=4,this.Zi.ji(function(){return y(t,void 0,void 0,function(){return g(this,function(t){return this.state=0,this.start(),[2]})})})},Pl.prototype.dr=function(t){return Br("PersistentStream","close with error: "+t),this.stream=null,this.close(3,t)},Pl.prototype.hr=function(e){var n=this;return function(t){n.Se.enqueueAndForget(function(){return n.Yi===e?t():(Br("PersistentStream","stream callback skipped by getCloseGuardedDispatcher."),Promise.resolve())})}},Pl),Dl=(n(Ll,Sl=_),Ll.prototype.wr=function(t){return this.Hi.Oi("Listen",t)},Ll.prototype.onMessage=function(t){this.Zi.reset();var e=function(t,e){if("targetChange"in e){e.targetChange;var n="NO_CHANGE"===(o=e.targetChange.targetChangeType||"NO_CHANGE")?0:"ADD"===o?1:"REMOVE"===o?2:"CURRENT"===o?3:"RESET"===o?4:Qr(),r=e.targetChange.targetIds||[],i=(s=e.targetChange.resumeToken,t.I?(Hr(void 0===s||"string"==typeof s),li.fromBase64String(s||"")):(Hr(void 0===s||s instanceof Uint8Array),li.fromUint8Array(s||new Uint8Array))),o=(a=e.targetChange.cause)&&(u=void 0===(c=a).code?Mr.UNKNOWN:Ps(c.code),new Fr(u,c.message||"")),s=new ra(n,r,i,o||null)}else if("documentChange"in e){e.documentChange,(n=e.documentChange).document,n.document.name,n.document.updateTime;var r=Ea(t,n.document.name),i=ma(n.document.updateTime),a=new Bi({mapValue:{fields:n.document.fields}}),u=(o=Ki.newFoundDocument(r,i,a),n.targetIds||[]),c=n.removedTargetIds||[];s=new ea(u,c,o.key,o)}else if("documentDelete"in e)e.documentDelete,(n=e.documentDelete).document,r=Ea(t,n.document),i=n.readTime?ma(n.readTime):Zr.min(),a=Ki.newNoDocument(r,i),o=n.removedTargetIds||[],s=new ea([],o,a.key,a);else if("documentRemove"in e)e.documentRemove,(n=e.documentRemove).document,r=Ea(t,n.document),i=n.removedTargetIds||[],s=new ea([],i,r,null);else{if(!("filter"in e))return Qr();e.filter;e=e.filter;e.targetId,n=e.count||0,r=new As(n),i=e.targetId,s=new na(i,r)}return s}(this.R,t),t=function(t){if(!("targetChange"in t))return Zr.min();t=t.targetChange;return(!t.targetIds||!t.targetIds.length)&&t.readTime?ma(t.readTime):Zr.min()}(t);return this.listener._r(e,t)},Ll.prototype.mr=function(t){var e,n,r,i={};i.database=_a(this.R),i.addTarget=(e=this.R,(r=Yi(r=(n=t).target)?{documents:ka(e,r)}:{query:Ra(e,r)}).targetId=n.targetId,0this.query.limit;){var n=ko(this.query)?h.last():h.first(),h=h.delete(n.key),c=c.delete(n.key);a.track({type:1,doc:n})}return{fo:h,mo:a,Nn:l,mutatedKeys:c}},Of.prototype.yo=function(t,e){return t.hasLocalMutations&&e.hasCommittedMutations&&!e.hasLocalMutations},Of.prototype.applyChanges=function(t,e,n){var o=this,r=this.fo;this.fo=t.fo,this.mutatedKeys=t.mutatedKeys;var i=t.mo.jr();i.sort(function(t,e){return r=t.type,i=e.type,n(r)-n(i)||o.lo(t.doc,e.doc);function n(t){switch(t){case 0:return 1;case 2:case 3:return 2;case 1:return 0;default:return Qr()}}var r,i}),this.po(n);var s=e?this.Eo():[],n=0===this.ho.size&&this.current?1:0,e=n!==this.ao;return this.ao=n,0!==i.length||e?{snapshot:new cf(this.query,t.fo,r,i,t.mutatedKeys,0==n,e,!1),To:s}:{To:s}},Of.prototype.zr=function(t){return this.current&&"Offline"===t?(this.current=!1,this.applyChanges({fo:this.fo,mo:new uf,mutatedKeys:this.mutatedKeys,Nn:!1},!1)):{To:[]}},Of.prototype.Io=function(t){return!this.uo.has(t)&&!!this.fo.has(t)&&!this.fo.get(t).hasLocalMutations},Of.prototype.po=function(t){var e=this;t&&(t.addedDocuments.forEach(function(t){return e.uo=e.uo.add(t)}),t.modifiedDocuments.forEach(function(t){}),t.removedDocuments.forEach(function(t){return e.uo=e.uo.delete(t)}),this.current=t.current)},Of.prototype.Eo=function(){var e=this;if(!this.current)return[];var n=this.ho;this.ho=$s(),this.fo.forEach(function(t){e.Io(t.key)&&(e.ho=e.ho.add(t.key))});var r=[];return n.forEach(function(t){e.ho.has(t)||r.push(new Df(t))}),this.ho.forEach(function(t){n.has(t)||r.push(new Af(t))}),r},Of.prototype.Ao=function(t){this.uo=t.Bn,this.ho=$s();t=this._o(t.documents);return this.applyChanges(t,!0)},Of.prototype.Ro=function(){return cf.fromInitialDocuments(this.query,this.fo,this.mutatedKeys,0===this.ao)},Of),Cf=function(t,e,n){this.query=t,this.targetId=e,this.view=n},kf=function(t){this.key=t,this.bo=!1},Rf=(Object.defineProperty(xf.prototype,"isPrimaryClient",{get:function(){return!0===this.$o},enumerable:!1,configurable:!0}),xf);function xf(t,e,n,r,i,o){this.localStore=t,this.remoteStore=e,this.eventManager=n,this.sharedClientState=r,this.currentUser=i,this.maxConcurrentLimboResolutions=o,this.vo={},this.Po=new Pc(Uo,Vo),this.Vo=new Map,this.So=new Set,this.Do=new Ms(Ai.comparator),this.Co=new Map,this.No=new _h,this.xo={},this.Fo=new Map,this.ko=gc.Yt(),this.onlineState="Unknown",this.$o=void 0}function Of(t,e){this.query=t,this.uo=e,this.ao=null,this.current=!1,this.ho=$s(),this.mutatedKeys=$s(),this.lo=jo(t),this.fo=new af(this.lo)}function Lf(i,o,s,a){return y(this,void 0,void 0,function(){var e,n,r;return g(this,function(t){switch(t.label){case 0:return i.Oo=function(t,e,n){return function(r,i,o,s){return y(this,void 0,void 0,function(){var e,n;return g(this,function(t){switch(t.label){case 0:return(e=i.view._o(o)).Nn?[4,mh(r.localStore,i.query,!1).then(function(t){t=t.documents;return i.view._o(t,e)})]:[3,2];case 1:e=t.sent(),t.label=2;case 2:return n=s&&s.targetChanges.get(i.targetId),n=i.view.applyChanges(e,r.isPrimaryClient,n),[2,(Gf(r,i.targetId,n.To),n.snapshot)]}})})}(i,t,e,n)},[4,mh(i.localStore,o,!0)];case 1:return n=t.sent(),r=new Nf(o,n.Bn),e=r._o(n.documents),n=ta.createSynthesizedTargetChangeForCurrentChange(s,a&&"Offline"!==i.onlineState),n=r.applyChanges(e,i.isPrimaryClient,n),Gf(i,s,n.To),r=new Cf(o,s,r),[2,(i.Po.set(o,r),i.Vo.has(s)?i.Vo.get(s).push(o):i.Vo.set(s,[o]),n.snapshot)]}})})}function Pf(f,d,p){return y(this,void 0,void 0,function(){var s,l;return g(this,function(t){switch(t.label){case 0:l=Zf(f),t.label=1;case 1:return t.trys.push([1,5,,6]),[4,(i=l.localStore,a=d,c=i,h=Jr.now(),o=a.reduce(function(t,e){return t.add(e.key)},$s()),c.persistence.runTransaction("Locally write mutations","readwrite",function(s){return c.Mn.pn(s,o).next(function(t){u=t;for(var e=[],n=0,r=a;n, or >=) must be on the same field. But you have inequality filters on '"+n.toString()+"' and '"+e.field.toString()+"'");n=xo(t);null!==n&&og(0,e.field,n)}t=function(t,e){for(var n=0,r=t.filters;ns.length)throw new Fr(Mr.INVALID_ARGUMENT,"Too many arguments provided to "+r+"(). The number of arguments must be less than or equal to the number of orderBy() clauses");for(var a=[],u=0;u, or >=) on field '"+e.toString()+"' and so you must also use '"+e.toString()+"' as your first argument to orderBy(), but your first orderBy() is on field '"+n.toString()+"' instead.")}sg.prototype.convertValue=function(t,e){switch(void 0===e&&(e="none"),Ni(t)){case 0:return null;case 1:return t.booleanValue;case 2:return wi(t.integerValue||t.doubleValue);case 3:return this.convertTimestamp(t.timestampValue);case 4:return this.convertServerTimestamp(t,e);case 5:return t.stringValue;case 6:return this.convertBytes(bi(t.bytesValue));case 7:return this.convertReference(t.referenceValue);case 8:return this.convertGeoPoint(t.geoPointValue);case 9:return this.convertArray(t.arrayValue,e);case 10:return this.convertObject(t.mapValue,e);default:throw Qr()}},sg.prototype.convertObject=function(t,n){var r=this,i={};return ri(t.fields,function(t,e){i[t]=r.convertValue(e,n)}),i},sg.prototype.convertGeoPoint=function(t){return new xp(wi(t.latitude),wi(t.longitude))},sg.prototype.convertArray=function(t,e){var n=this;return(t.values||[]).map(function(t){return n.convertValue(t,e)})},sg.prototype.convertServerTimestamp=function(t,e){switch(e){case"previous":var n=function t(e){e=e.mapValue.fields.__previous_value__;return Ei(e)?t(e):e}(t);return null==n?null:this.convertValue(n,e);case"estimate":return this.convertTimestamp(Ti(t));default:return null}},sg.prototype.convertTimestamp=function(t){t=vi(t);return new Jr(t.seconds,t.nanos)},sg.prototype.convertDocumentKey=function(t,e){var n=ai.fromString(t);Hr(Ua(n));t=new Pd(n.get(1),n.get(3)),n=new Ai(n.popFirst(5));return t.isEqual(e)||jr("Document "+n+" contains a document reference within a different database ("+t.projectId+"/"+t.database+") which is not supported. It will be treated as a reference in the current database ("+e.projectId+"/"+e.database+") instead."),n},_=sg;function sg(){}function ag(t,e,n){return t?n&&(n.merge||n.mergeFields)?t.toFirestore(e,n):t.toFirestore(e):e}var ug,cg=(n(fg,ug=_),fg.prototype.convertBytes=function(t){return new kp(t)},fg.prototype.convertReference=function(t){t=this.convertDocumentKey(t,this.firestore._databaseId);return new op(this.firestore,null,t)},fg),hg=(lg.prototype.set=function(t,e,n){this._verifyNotCommitted();t=dg(t,this._firestore),e=ag(t.converter,e,n),n=zp(this._dataReader,"WriteBatch.set",t._key,e,null!==t.converter,n);return this._mutations.push(n.toMutation(t._key,ls.none())),this},lg.prototype.update=function(t,e,n){for(var r=[],i=3;iI/O Pinball Machine - Flutter - - - + + + +