Skip to content

Commit 02aa77e

Browse files
committed
add dev banner in debug mode for development
1 parent 6abcc0c commit 02aa77e

File tree

13 files changed

+228
-13
lines changed

13 files changed

+228
-13
lines changed

app/lib/main/app.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1+
import 'package:app/presentation/resources/resources.dart';
2+
import 'package:app/presentation/ui/custom/app_theme_switch.dart';
13
import 'package:flutter/material.dart';
24
import 'package:domain/bloc/app/app_cubit.dart';
35
import 'package:domain/bloc/app/app_state.dart';
46
import 'package:domain/bloc/auth/auth_cubit.dart';
7+
import 'package:domain/models/app_lang.dart';
58
import 'package:app/presentation/navigation/routers.dart';
69
import 'package:app/presentation/resources/locale/generated/l10n.dart';
710
import 'package:app/presentation/themes/app_themes.dart';
811
import 'package:app/presentation/utils/lang_extensions.dart';
912
import 'package:flutter_bloc/flutter_bloc.dart';
1013
import 'package:flutter_localizations/flutter_localizations.dart';
11-
import 'package:flutter/foundation.dart' show kIsWeb;
14+
import 'package:flutter/foundation.dart' show kDebugMode, kIsWeb;
1215
import 'package:app_links/app_links.dart';
16+
import 'package:gap/gap.dart';
1317
import 'package:go_router/go_router.dart';
1418
import 'init.dart';
1519

@@ -74,6 +78,7 @@ class _AppState extends State<App> {
7478
: BlocBuilder<AppCubit, AppState>(
7579
builder: (context, state) {
7680
return MaterialApp.router(
81+
debugShowCheckedModeBanner: false,
7782
theme: AppThemes.getAppTheme(state.themeType).data,
7883
locale: LangExtensions.langLocale[state.appLang],
7984
supportedLocales: LangExtensions.supportedLang,

app/lib/presentation/navigation/routers.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import 'package:app/main/init.dart';
2+
import 'package:app/presentation/ui/pages/debug_banner.dart';
23
import 'package:app/presentation/ui/pages/main/home/home_page.dart';
34
import 'package:app/presentation/ui/pages/auth/login/login_page.dart';
45
import 'package:app/presentation/ui/pages/auth/sign_up/sign_up_page.dart';
56
import 'package:app/presentation/ui/pages/splash/splash_page.dart';
67
import 'package:common/core/resource.dart';
78
import 'package:domain/bloc/auth/auth_cubit.dart';
89
import 'package:domain/bloc/auth/auth_state.dart';
10+
import 'package:flutter/foundation.dart';
911
import 'package:flutter/widgets.dart';
1012
import 'package:flutter_bloc/flutter_bloc.dart';
1113
import 'package:go_router/go_router.dart';
@@ -36,12 +38,15 @@ extension ContextOnRouter on BuildContext {
3638
GoRouter get router => GoRouter.of(this);
3739
}
3840

41+
final rootNavigatorKey = GlobalKey<NavigatorState>();
42+
3943
class Routers {
4044
static GoRouter appRouter(
4145
BuildContext context, {
4246
String? initialLocation,
4347
}) =>
4448
GoRouter(
49+
navigatorKey: rootNavigatorKey,
4550
initialLocation: initialLocation ??
4651
(getIt<AuthCubit>().isLoggedIn()
4752
? Routes.app.path
@@ -85,7 +90,8 @@ class Routers {
8590
},
8691
routes: [
8792
ShellRoute(
88-
builder: (context, state, child) => child,
93+
builder: (context, state, child) =>
94+
kDebugMode ? DebugBanner(child: child) : child,
8995
routes: [
9096
GoRoute(
9197
name: Routes.auth.name,
@@ -108,7 +114,8 @@ class Routers {
108114
],
109115
),
110116
ShellRoute(
111-
builder: (context, state, child) => child,
117+
builder: (context, state, child) =>
118+
kDebugMode ? DebugBanner(child: child) : child,
112119
routes: [
113120
GoRoute(
114121
name: Routes.app.name,

app/lib/presentation/resources/locale/generated/intl/messages_en.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ class MessageLookup extends MessageLookupByLibrary {
3232
),
3333
"ctaLogin": MessageLookupByLibrary.simpleMessage("Login"),
3434
"ctaSignUp": MessageLookupByLibrary.simpleMessage("Sign Up"),
35+
"debugModeCancel": MessageLookupByLibrary.simpleMessage("Cancel"),
36+
"debugModeConfirm": MessageLookupByLibrary.simpleMessage("Confirm"),
37+
"debugModeLabel": MessageLookupByLibrary.simpleMessage("DEV MODE"),
38+
"debugModeResetApp": MessageLookupByLibrary.simpleMessage("RESET APP"),
39+
"debugModeResetAppMessage": MessageLookupByLibrary.simpleMessage(
40+
"Are you sure you want to reset the app?",
41+
),
42+
"debugModeResetAppTitle": MessageLookupByLibrary.simpleMessage("Reset App"),
3543
"errorEmailInvalid": MessageLookupByLibrary.simpleMessage(
3644
"Please enter a valid email address.",
3745
),

app/lib/presentation/resources/locale/generated/l10n.dart

Lines changed: 50 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/lib/presentation/resources/locale/intl_en.arb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,11 @@
2424
"errorEmailInvalid": "Please enter a valid email address.",
2525
"errorPasswordWeak": "Password is too weak.",
2626
"loginErrorInvalidCredentials": "Invalid email or password.",
27-
"hintTermsAndConditions": "This should open the terms and conditions URL."
27+
"hintTermsAndConditions": "This should open the terms and conditions URL.",
28+
"debugModeLabel": "DEV MODE",
29+
"debugModeResetApp": "RESET APP",
30+
"debugModeResetAppTitle": "Reset App",
31+
"debugModeResetAppMessage": "Are you sure you want to reset the app?",
32+
"debugModeCancel": "Cancel",
33+
"debugModeConfirm": "Confirm"
2834
}

app/lib/presentation/resources/locale/intl_es.arb

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,33 @@
22
"appName": "Flutter Target",
33
"cookiesTitle": "Este sitio web utiliza cookies",
44
"cookiesAcceptCTA": "Aceptar",
5-
"cookiesBody": "Usamos cookies para personalizar el contenido y los anuncios, ofrecer funciones de redes sociales y analizar nuestro tráfico. También compartimos información sobre el uso de nuestro sitio con nuestros socios de redes sociales, publicidad y análisis, quienes pueden combinarla con otra información que les hayas proporcionado o que hayan recopilado a partir del uso de sus servicios.",
5+
"cookiesBody": "Usamos cookies para personalizar el contenido y los anuncios, proporcionar funciones de redes sociales y analizar nuestro tráfico. También compartimos información sobre el uso que haces de nuestro sitio con nuestros socios de redes sociales, publicidad y análisis, quienes pueden combinarla con otra información que les hayas proporcionado o que hayan recopilado a partir del uso que haces de sus servicios.",
66
"noConnection": "Sin conexión",
77
"retry": "Reintentar",
8-
"pleaseTryAgainLaterWeArenworkingToFixTheIssue": "Por favor, inténtalo más tarde,\nestamos trabajando para resolver el problema.",
9-
"sorryWeDidntFindAnyProduct": "Lo sentimos, no hemos encontrado ningún producto",
8+
"pleaseTryAgainLaterWeArenworkingToFixTheIssue": "Por favor intenta nuevamente más tarde,\nestamos trabajando para solucionar el problema.",
9+
"sorryWeDidntFindAnyProduct": "Lo sentimos, no encontramos ningún producto",
1010
"ctaLogin": "Iniciar sesión",
11+
"ctaSignUp": "Registrarse",
1112
"labelEmail": "Correo electrónico",
1213
"labelPassword": "Contraseña",
14+
"labelConfirmPassword": "Confirmar contraseña",
15+
"errorPasswordsDoNotMatch": "Las contraseñas no coinciden.",
1316
"passwordInstructions": "Mínimo 8 caracteres: 1 mayúscula, 1 minúscula, 1 número y 1 carácter especial.",
1417
"labelAgreeToTerms": "Acepto los Términos y Condiciones",
1518
"errorEmailRequired": "El correo electrónico es obligatorio.",
1619
"errorPasswordRequired": "La contraseña es obligatoria.",
1720
"titleLogin": "Iniciar sesión",
18-
"titleLoginSubtitle": "Usa tu correo y contraseña para iniciar sesión en tu cuenta.",
19-
"errorEmailInvalid": "Por favor ingresa una dirección de correo válida.",
21+
"titleSignUp": "Registrarse",
22+
"titleLoginSubtitle": "Usa tu correo electrónico y contraseña para iniciar sesión en tu cuenta.",
23+
"titleSignUpSubtitle": "Crea una cuenta usando tu correo electrónico y contraseña.",
24+
"errorEmailInvalid": "Por favor ingresa un correo electrónico válido.",
2025
"errorPasswordWeak": "La contraseña es demasiado débil.",
21-
"loginErrorInvalidCredentials": "Correo o contraseña inválidos."
26+
"loginErrorInvalidCredentials": "Correo electrónico o contraseña incorrectos.",
27+
"hintTermsAndConditions": "Esto debería abrir la URL de términos y condiciones.",
28+
"debugModeLabel": "MODO DEV",
29+
"debugModeResetApp": "RESETEAR APP",
30+
"debugModeResetAppTitle": "Resetear App",
31+
"debugModeResetAppMessage": "¿Estás seguro de que deseas resetear la aplicación?",
32+
"debugModeCancel": "Cancelar",
33+
"debugModeConfirm": "Confirmar"
2234
}

app/lib/presentation/themes/local_theme.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ abstract class LocalTheme {
8585
),
8686
elevation: 10,
8787
),
88+
dialogTheme: DialogThemeData(
89+
shape: RoundedRectangleBorder(
90+
borderRadius: BorderRadius.all(
91+
Radius.circular(themeData.borderRadius),
92+
),
93+
),
94+
titleTextStyle: titleM.copyWith(color: colors.onSurface),
95+
contentTextStyle: subtitleM.copyWith(color: colors.onSurface),
96+
),
8897
);
8998

9099
final primaryFont = 'Roboto Regular';

app/lib/presentation/ui/custom/app_theme_switch.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ class AppThemeSwitch extends StatelessWidget {
1414

1515
return Switch(
1616
value: theme == ThemeType.dark,
17-
activeTrackColor: Colors.grey,
17+
thumbIcon: const WidgetStatePropertyAll(Icon(Icons.brightness_6)),
1818
onChanged: (value) {
19-
context.read<AppCubit>().updateTheme(value ? ThemeType.dark : ThemeType.light);
19+
context
20+
.read<AppCubit>()
21+
.updateTheme(value ? ThemeType.dark : ThemeType.light);
2022
},
2123
);
2224
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import 'package:app/presentation/resources/locale/generated/l10n.dart';
2+
import 'package:app/presentation/resources/resources.dart';
3+
import 'package:app/presentation/ui/custom/app_theme_switch.dart';
4+
import 'package:domain/bloc/app/app_cubit.dart';
5+
import 'package:domain/bloc/app/app_state.dart';
6+
import 'package:domain/bloc/auth/auth_cubit.dart';
7+
import 'package:domain/models/app_lang.dart';
8+
import 'package:flutter/material.dart';
9+
import 'package:flutter_bloc/flutter_bloc.dart';
10+
import 'package:gap/gap.dart';
11+
12+
class DebugBanner extends StatelessWidget {
13+
final Widget child;
14+
const DebugBanner({
15+
super.key,
16+
required this.child,
17+
});
18+
19+
@override
20+
Widget build(BuildContext context) {
21+
final colorScheme = Theme.of(context).colorScheme;
22+
final textTheme = Theme.of(context).textTheme;
23+
24+
return Material(
25+
child: Column(
26+
children: [
27+
Container(
28+
color: colorScheme.error.withAlpha(120),
29+
child: Row(
30+
children: [
31+
Icon(Icons.bug_report, color: colorScheme.onError),
32+
const Gap(Dimen.spacingS),
33+
Text(
34+
S.of(context).debugModeLabel,
35+
style:
36+
textTheme.bodyLarge?.copyWith(color: colorScheme.onError),
37+
),
38+
const Spacer(),
39+
BlocBuilder<AppCubit, AppState>(
40+
builder: (context, state) {
41+
return DropdownButton<AppLang>(
42+
value: state.appLang,
43+
padding: const EdgeInsets.symmetric(
44+
horizontal: Dimen.spacingS,
45+
),
46+
underline: Container(),
47+
icon: Icon(Icons.language, color: colorScheme.onError),
48+
onChanged: (AppLang? newLang) {
49+
if (newLang != null) {
50+
context.read<AppCubit>().updateAppLang(newLang);
51+
}
52+
},
53+
items: AppLang.values.map((AppLang lang) {
54+
return DropdownMenuItem<AppLang>(
55+
value: lang,
56+
child: Text(lang.name.toUpperCase()),
57+
);
58+
}).toList(),
59+
);
60+
},
61+
),
62+
const Gap(Dimen.spacingS),
63+
const AppThemeSwitch(),
64+
const Gap(Dimen.spacingS),
65+
TextButton(
66+
onPressed: () => resetApp(context),
67+
child: Text(S.of(context).debugModeResetApp),
68+
),
69+
],
70+
),
71+
),
72+
Expanded(child: child),
73+
],
74+
),
75+
);
76+
}
77+
78+
void resetApp(BuildContext context) async {
79+
showDialog(
80+
context: context,
81+
barrierDismissible: true,
82+
builder: (dialogContext) {
83+
return AlertDialog(
84+
title: Text(S.of(context).debugModeResetAppTitle),
85+
content: Text(S.of(context).debugModeResetAppMessage),
86+
actions: [
87+
TextButton(
88+
onPressed: () => Navigator.of(dialogContext).pop(),
89+
child: Text(S.of(context).debugModeCancel),
90+
),
91+
TextButton(
92+
onPressed: () async {
93+
Navigator.of(dialogContext).pop();
94+
await context.read<AppCubit>().resetApp();
95+
await context.read<AuthCubit>().logOut();
96+
},
97+
child: Text(S.of(context).debugModeConfirm),
98+
),
99+
],
100+
);
101+
},
102+
);
103+
}
104+
}

app/lib/presentation/ui/pages/main/home/home_view.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ class HomeView extends StatelessWidget {
2121
onPressed: () => _authCubit.logOut(),
2222
icon: const Icon(Icons.logout),
2323
),
24-
const AppThemeSwitch(),
2524
],
2625
),
2726
body: const Text('Home Page'),

0 commit comments

Comments
 (0)