Skip to content
This repository has been archived by the owner on Mar 6, 2024. It is now read-only.

Commit

Permalink
feat: don't allow mobile web browser (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsgalarraga authored Nov 2, 2023
1 parent 2525550 commit ca3c523
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 61 deletions.
1 change: 1 addition & 0 deletions lib/game_intro/game_intro.dart
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export 'view/view.dart';
export 'widgets/widgets.dart';
216 changes: 155 additions & 61 deletions lib/game_intro/view/game_intro_page.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import 'package:app_ui/app_ui.dart';
import 'package:dash_run/assets/assets.dart';
import 'package:dash_run/game/game.dart';
import 'package:dash_run/game_intro/game_intro.dart';
import 'package:dash_run/l10n/l10n.dart';
import 'package:dash_run/settings/settings.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:url_launcher/url_launcher_string.dart';

class GameIntroPage extends StatelessWidget {
const GameIntroPage({super.key});

@override
Widget build(BuildContext context) {
final l10n = context.l10n;
final theme = Theme.of(context);
return Scaffold(
body: Container(
decoration: BoxDecoration(
Expand All @@ -23,76 +23,170 @@ class GameIntroPage extends StatelessWidget {
fit: BoxFit.cover,
),
),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 390),
child: Column(
children: [
const Spacer(),
Image.asset(
Assets.logo,
width: context.isSmall ? 282 : 380,
),
const Spacer(flex: 4),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Text(
l10n.gameIntroPageHeadline,
textAlign: TextAlign.center,
style: theme.textTheme.titleMedium?.copyWith(
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
),
const SizedBox(height: 32),
GameElevatedButton(
label: l10n.gameIntroPagePlayButtonText,
onPressed: () => Navigator.of(context).push(GameView.route()),
child: isMobileWeb
? const _MobileWebNotAvailableIntroPage()
: const _IntroPage(),
),
);
}

bool get isMobileWeb =>
kIsWeb &&
(defaultTargetPlatform == TargetPlatform.android ||
defaultTargetPlatform == TargetPlatform.iOS);
}

class _IntroPage extends StatelessWidget {
const _IntroPage();

@override
Widget build(BuildContext context) {
final l10n = context.l10n;
final theme = Theme.of(context);
return Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 390),
child: Column(
children: [
const Spacer(),
Image.asset(
Assets.logo,
width: context.isSmall ? 282 : 380,
),
const Spacer(flex: 4),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Text(
l10n.gameIntroPageHeadline,
textAlign: TextAlign.center,
style: theme.textTheme.titleMedium?.copyWith(
color: Colors.white,
fontWeight: FontWeight.w500,
),
const Spacer(),
const _Actions(),
const SizedBox(height: 32),
),
),
const SizedBox(height: 32),
GameElevatedButton(
label: l10n.gameIntroPagePlayButtonText,
onPressed: () => Navigator.of(context).push(GameView.route()),
),
const Spacer(),
const Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
AudioButton(),
LeaderboardButton(),
InfoButton(),
HowToPlayButton(),
],
),
),
const SizedBox(height: 32),
],
),
),
);
}
}

class _Actions extends StatelessWidget {
const _Actions();
class _MobileWebNotAvailableIntroPage extends StatelessWidget {
const _MobileWebNotAvailableIntroPage();

@override
Widget build(BuildContext context) {
final settingsController = context.watch<SettingsController>();
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ValueListenableBuilder<bool>(
valueListenable: settingsController.soundsOn,
builder: (context, soundsOn, child) => GameIconButton(
icon: soundsOn ? Icons.volume_up : Icons.volume_off,
onPressed: soundsOn
? settingsController.toggleMuted
: settingsController.toggleMusicOn,
),
),
GameIconButton(
icon: Icons.leaderboard,
onPressed: () {},
),
GameIconButton(
onPressed: () {},
icon: Icons.info,
),
GameIconButton(
onPressed: () {},
icon: Icons.help,
final l10n = context.l10n;
final theme = Theme.of(context);
return Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 390),
child: Column(
children: [
const Spacer(),
Image.asset(Assets.logo, width: 282),
const Spacer(flex: 4),
Container(
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Color(0xFF0046ab),
),
padding: const EdgeInsets.all(12),
child: const Icon(
Icons.mobile_off,
size: 24,
color: Colors.white,
),
),
const SizedBox(height: 24),
Text(
l10n.mobileModeUnavailable,
textAlign: TextAlign.center,
style: theme.textTheme.headlineSmall?.copyWith(
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 24),
Text(
l10n.mobileModeUnavailableDescription,
textAlign: TextAlign.center,
style: theme.textTheme.titleMedium?.copyWith(
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
const Spacer(),
const _BottomBar(),
const SizedBox(height: 32),
],
),
],
),
);
}
}

class _BottomBar extends StatelessWidget {
const _BottomBar();

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final l10n = context.l10n;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const AudioButton(),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
l10n.superDash,
style: theme.textTheme.titleMedium?.copyWith(
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 4),
RichText(
text: TextSpan(
text: l10n.howItsMade,
style: theme.textTheme.titleMedium?.copyWith(
color: Colors.white,
fontWeight: FontWeight.w400,
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () {
// TODO(all): confirm url once is in google's org
launchUrlString('https://github.com/flutter/superdash');
},
),
),
],
),
const InfoButton(),
],
),
);
}
}
58 changes: 58 additions & 0 deletions lib/game_intro/widgets/game_intro_buttons.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import 'package:app_ui/app_ui.dart';
import 'package:dash_run/settings/settings_controller.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class AudioButton extends StatelessWidget {
const AudioButton({super.key});

@override
Widget build(BuildContext context) {
final settingsController = context.watch<SettingsController>();
return ValueListenableBuilder<bool>(
valueListenable: settingsController.soundsOn,
builder: (context, soundsOn, child) => GameIconButton(
icon: soundsOn ? Icons.volume_up : Icons.volume_off,
onPressed: soundsOn
? settingsController.toggleMuted
: settingsController.toggleMusicOn,
),
);
}
}

class LeaderboardButton extends StatelessWidget {
const LeaderboardButton({super.key});

@override
Widget build(BuildContext context) {
return GameIconButton(
icon: Icons.leaderboard,
onPressed: () {},
);
}
}

class InfoButton extends StatelessWidget {
const InfoButton({super.key});

@override
Widget build(BuildContext context) {
return GameIconButton(
icon: Icons.info,
onPressed: () {},
);
}
}

class HowToPlayButton extends StatelessWidget {
const HowToPlayButton({super.key});

@override
Widget build(BuildContext context) {
return GameIconButton(
icon: Icons.help,
onPressed: () {},
);
}
}
1 change: 1 addition & 0 deletions lib/game_intro/widgets/widgets.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'game_intro_buttons.dart';
16 changes: 16 additions & 0 deletions lib/l10n/arb/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,21 @@
"gameIntroPagePlayButtonText": "Play",
"@gameIntroPagePlayButtonText": {
"description": "Text shown in the Play button of the Game Info Page"
},
"mobileModeUnavailable": "Mobile mode unavailable",
"@mobileModeUnavailable": {
"description": "Title shown in the Game Info Page for mobile devices joining from a browser"
},
"mobileModeUnavailableDescription": "Super Dash mobile is coming soon.\nOpen this link on a desktop web browser\nto play today.",
"@mobileModeUnavailableDescription": {
"description": "Description shown in the Game Info Page for mobile devices joining from a browser"
},
"superDash": "Super Dash",
"@superDash": {
"description": "Game name"
},
"howItsMade": "How it's made",
"@howItsMade": {
"description": "Text shown in the game info page"
}
}
2 changes: 2 additions & 0 deletions macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import audioplayers_darwin
import file_selector_macos
import path_provider_foundation
import shared_preferences_foundation
import url_launcher_macos

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
}
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ dependencies:
pathxp: ^0.4.0
provider: ^6.0.5
shared_preferences: ^2.2.2
url_launcher: ^6.2.1

dev_dependencies:
bloc_test: ^9.1.2
Expand Down

0 comments on commit ca3c523

Please sign in to comment.