diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000000..f7258f4601
--- /dev/null
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000000..f7258f4601
--- /dev/null
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/assets/images/automatic.svg b/assets/images/automatic.svg
new file mode 100644
index 0000000000..ee487024f6
--- /dev/null
+++ b/assets/images/automatic.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/images/dark_mode.svg b/assets/images/dark_mode.svg
new file mode 100644
index 0000000000..425ef43d1f
--- /dev/null
+++ b/assets/images/dark_mode.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/light_mode.svg b/assets/images/light_mode.svg
new file mode 100644
index 0000000000..695071f8fb
--- /dev/null
+++ b/assets/images/light_mode.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/locales/en.po b/assets/locales/en.po
index cb8c8b02e7..2c38dd9cfc 100644
--- a/assets/locales/en.po
+++ b/assets/locales/en.po
@@ -1466,10 +1466,22 @@ msgstr "Your Pro plan was purchased through Google Play. Please manage your subs
msgid "manage_subscription_apple_app_store"
msgstr "Your Pro plan was purchased through the Apple App Store. Please manage your subscription from your Apple ID account settings."
-
msgid "create_account_error"
msgstr "Create Account Error"
+msgid "appearance"
+msgstr "Appearance"
+
+msgid "light"
+msgstr "Light"
+
+msgid "dark"
+msgstr "Dark"
+
+msgid "system"
+msgstr "System"
+
+
diff --git a/lib/core/common/app_asset.dart b/lib/core/common/app_asset.dart
index 526228a213..a37f5e787c 100644
--- a/lib/core/common/app_asset.dart
+++ b/lib/core/common/app_asset.dart
@@ -17,6 +17,9 @@ class AppImage extends StatelessWidget {
final AssetType type;
final OnPressed? onPressed;
final BoxFit? fit;
+ // Set to false for decorative/multicolor assets (illustrations, logos)
+ // that should not be recolored by the theme.
+ final bool useThemeColor;
const AppImage({
required this.path,
@@ -26,6 +29,7 @@ class AppImage extends StatelessWidget {
this.type = AssetType.svg,
this.onPressed,
this.fit,
+ this.useThemeColor = true,
super.key,
});
@@ -33,6 +37,9 @@ class AppImage extends StatelessWidget {
Widget build(BuildContext context) {
switch (type) {
case AssetType.svg:
+ // Use explicit color > theme icon color > no filter (when opted out)
+ final effectiveColor =
+ color ?? (useThemeColor ? Theme.of(context).iconTheme.color : null);
return GestureDetector(
onTap: onPressed,
child: SvgPicture.asset(
@@ -40,8 +47,8 @@ class AppImage extends StatelessWidget {
height: height,
width: width,
fit: fit ?? BoxFit.contain,
- colorFilter: color != null
- ? ColorFilter.mode(color!, BlendMode.srcIn)
+ colorFilter: effectiveColor != null
+ ? ColorFilter.mode(effectiveColor, BlendMode.srcIn)
: null,
),
);
diff --git a/lib/core/common/app_buttons.dart b/lib/core/common/app_buttons.dart
index 492dc199a5..98a4f04332 100644
--- a/lib/core/common/app_buttons.dart
+++ b/lib/core/common/app_buttons.dart
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:lantern/core/common/app_asset.dart';
import 'package:lantern/core/common/app_colors.dart';
import 'package:lantern/core/common/app_dimens.dart';
+import 'package:lantern/core/common/app_semantic_colors.dart';
import 'package:lantern/core/common/app_text_styles.dart';
import 'package:lantern/core/common/cap_scaling.dart';
@@ -21,6 +22,7 @@ class PrimaryButton extends StatelessWidget {
final Color? bgColor;
final Color? textColor;
final bool? isTaller;
+ final bool? useThemeColor;
// Default constructor for button without an icon
const PrimaryButton({
@@ -33,6 +35,7 @@ class PrimaryButton extends StatelessWidget {
this.expanded = true,
this.isTaller = false,
this.showBorder = false,
+ this.useThemeColor,
this.icon,
super.key,
});
@@ -56,6 +59,7 @@ class PrimaryButton extends StatelessWidget {
path: icon!,
height: iconHeight,
color: iconColor,
+ useThemeColor: useThemeColor ?? true,
),
label: Text(label),
style: _buildButtonStyle(context, button!, iconSz),
@@ -69,6 +73,7 @@ class PrimaryButton extends StatelessWidget {
) {
final verticalPad = hCap(context, 12);
final fontSz = spCap(context, 16);
+ final isDark = Theme.of(context).brightness == Brightness.dark;
// Heights
final minHeight = isTaller == true ? hCap(context, 56) : hCap(context, 48);
@@ -78,36 +83,42 @@ class PrimaryButton extends StatelessWidget {
backgroundColor: WidgetStateProperty.resolveWith(
(Set states) {
if (states.contains(WidgetState.disabled)) {
- return AppColors.gray2; // Disabled background color
+ // primary-disabled-bg: Gray.200 light / Gray.700 dark
+ return isDark ? AppColors.gray7 : AppColors.gray2;
}
if (states.contains(WidgetState.hovered) &&
bgColor == AppColors.blue1) {
- return AppColors.blue2; // Pressed background color
+ return AppColors.blue2;
}
if (states.contains(WidgetState.hovered)) {
- return AppColors.blue8; // Hovered background color
+ // primary-bg-hover: Blue.800 light / Blue.500 dark
+ return isDark ? AppColors.blue5 : AppColors.blue8;
}
- return bgColor ?? AppColors.blue10; // Default background color
+ // primary-bg: Blue.1000 light / Blue.600 dark
+ return bgColor ?? (isDark ? AppColors.blue6 : AppColors.blue10);
},
),
side: WidgetStateProperty.resolveWith(
(Set states) {
if (states.contains(WidgetState.disabled)) {
- return BorderSide(color: AppColors.gray4, width: 1);
+ // primary-disabled-border: Gray.400 light / Gray.500 dark
+ return BorderSide(
+ color: isDark ? AppColors.gray5 : AppColors.gray4,
+ width: 1,
+ );
}
if (showBorder) {
- return BorderSide(color: AppColors.gray2, width: 1);
+ return BorderSide(
+ color: isDark ? AppColors.gray7 : AppColors.gray2,
+ width: 1,
+ );
}
return BorderSide.none;
},
),
- // backgroundColor: WidgetStatePropertyAll(bgColor ?? AppColors.blue7),
iconSize: WidgetStatePropertyAll(iconSz),
padding: WidgetStatePropertyAll(
- EdgeInsets.symmetric(
- vertical: verticalPad,
- horizontal: 40.0,
- ),
+ EdgeInsets.symmetric(vertical: verticalPad, horizontal: 40.0),
),
textStyle: WidgetStatePropertyAll(
AppTextStyles.primaryButtonTextStyle.copyWith(
@@ -115,6 +126,7 @@ class PrimaryButton extends StatelessWidget {
fontWeight: FontWeight.w500,
),
),
+ // primary-text: Gray.100 both / primary-disabled-text: Gray.500 both
foregroundColor: WidgetStatePropertyAll(
enabled == false ? AppColors.gray5 : textColor ?? AppColors.gray1,
),
@@ -138,6 +150,8 @@ class SecondaryButton extends StatelessWidget {
final Color? bgColor;
final bool? isTaller;
+ final bool? useThemeColor;
+ final Color? iconColor;
const SecondaryButton({
super.key,
@@ -148,6 +162,8 @@ class SecondaryButton extends StatelessWidget {
required this.onPressed,
this.icon,
this.bgColor,
+ this.useThemeColor,
+ this.iconColor,
});
@override
@@ -168,6 +184,8 @@ class SecondaryButton extends StatelessWidget {
icon: AppImage(
path: icon!,
height: iconHeight,
+ color: iconColor,
+ useThemeColor: useThemeColor ?? false,
),
label: Text(label),
style: _buildButtonStyle(context, button!, iconSz),
@@ -181,40 +199,58 @@ class SecondaryButton extends StatelessWidget {
) {
final verticalPad = hCap(context, 12);
final fontSz = spCap(context, 16);
+ final isDark = Theme.of(context).brightness == Brightness.dark;
// Heights
final height = isTaller == true ? hCap(context, 56) : hCap(context, 50);
+ // secondary-text: Gray.900 light / Gray.100 dark
+ final textColor = isDark ? AppColors.gray1 : AppColors.gray9;
+
return style.copyWith(
backgroundColor: WidgetStateProperty.resolveWith(
(Set states) {
if (states.contains(WidgetState.disabled)) {
- return AppColors.gray2; // Disabled background color
+ // secondary-disabled-bg: Gray.200 light / Gray.900 dark
+ return isDark ? AppColors.gray9 : AppColors.gray2;
}
- return bgColor ?? AppColors.gray1; // Default background color
+ if (states.contains(WidgetState.hovered)) {
+ // secondary-bg-hover: Gray.200 light / Gray.800 dark
+ return isDark ? AppColors.gray8 : AppColors.gray2;
+ }
+ // secondary-bg: Gray.100 light / Gray.900 dark
+ return bgColor ?? (isDark ? AppColors.gray9 : AppColors.gray1);
},
),
side: WidgetStateProperty.resolveWith(
(Set states) {
if (states.contains(WidgetState.disabled)) {
- return BorderSide(color: AppColors.gray4, width: 1);
+ // secondary-disabled-border: Gray.400 light / Gray.700 dark
+ return BorderSide(
+ color: isDark ? AppColors.gray7 : AppColors.gray4,
+ width: 1,
+ );
}
- return BorderSide(color: AppColors.gray4, width: 1);
+ // secondary-border: Gray.500 light / Gray.600 dark
+ return BorderSide(
+ color: isDark ? AppColors.gray6 : AppColors.gray5,
+ width: 1,
+ );
},
),
- overlayColor: WidgetStatePropertyAll(AppColors.gray2),
- foregroundColor: WidgetStatePropertyAll(AppColors.gray9),
+ // secondary-bg-hover used as overlay
+ overlayColor: WidgetStatePropertyAll(
+ isDark ? AppColors.gray8 : AppColors.gray2,
+ ),
+ foregroundColor: WidgetStatePropertyAll(textColor),
iconSize: WidgetStatePropertyAll(iconSz),
padding: WidgetStatePropertyAll(
- EdgeInsets.symmetric(
- vertical: verticalPad,
- horizontal: 40.0,
- ),
+ EdgeInsets.symmetric(vertical: verticalPad, horizontal: 40.0),
),
textStyle: WidgetStatePropertyAll(
AppTextStyles.primaryButtonTextStyle.copyWith(
fontSize: expanded ? fontSz : 16.0,
- color: AppColors.gray9,
+ color: textColor,
fontWeight: FontWeight.w600,
),
),
@@ -259,7 +295,8 @@ class AppTextButton extends StatelessWidget {
underLine ? TextDecoration.underline : TextDecoration.none,
fontSize: cappedFontSize,
),
- foregroundColor: textColor ?? AppColors.blue7,
+ // text.link from semantic token
+ foregroundColor: textColor ?? context.textLink,
),
child: Text(label),
);
@@ -306,7 +343,6 @@ class AppRadioButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final sz = hCap(context, 24);
-
return SizedBox(
width: sz,
height: sz,
@@ -314,6 +350,7 @@ class AppRadioButton extends StatelessWidget {
value: value,
groupValue: groupValue,
onChanged: onChanged,
+ activeColor: context.textLink,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity.compact,
),
diff --git a/lib/core/common/app_colors.dart b/lib/core/common/app_colors.dart
index 3737411824..b6d6df04f1 100644
--- a/lib/core/common/app_colors.dart
+++ b/lib/core/common/app_colors.dart
@@ -1,133 +1,136 @@
import 'package:flutter/material.dart';
class AppColors {
- static Color get black => const Color(0xFF000000);
+ static const Color black = Color(0xFF000000);
- static Color get black1 => const Color(0xFF1A1B1C);
+ static const Color black1 = Color(0xFF1A1B1C);
- static Color get white => Colors.white;
+ static const Color white = Color(0xFFFFFFFF);
- static Color get whiteBlur => const Color(0xCCF8FAFB);
+ static const Color whiteBlur = Color(0xCCF8FAFB);
- static Color get blue1 => const Color(0xFFF0FDFF);
+ static const Color blue1 = Color(0xFFF0FDFF);
- static Color get blue2 => const Color(0xFFD6F6FA);
+ static const Color blue2 = Color(0xFFD6F6FA);
- static Color get blue3 => const Color(0xFF6AD8E7);
+ static const Color blue3 = Color(0xFF6AD8E7);
- static Color get blue4 => const Color(0xFF00BDD6);
+ static const Color blue4 = Color(0xFF00BDD6);
- static Color get blue5 => const Color(0xFF009EB2);
+ static const Color blue5 = Color(0xFF009EB2);
- static Color get blue6 => const Color(0xFF008394);
+ static const Color blue6 = Color(0xFF008394);
- static Color get blue7 => const Color(0xFF005F61);
+ static const Color blue7 = Color(0xFF005F61);
- static Color get blue8 => const Color(0xFF004D57);
+ static const Color blue8 = Color(0xFF004D57);
- static Color get blue9 => const Color(0xFF00353D);
+ static const Color blue9 = Color(0xFF00353D);
- static Color get blue10 => const Color(0xFF012D2D);
+ static const Color blue10 = Color(0xFF012D2D);
- static Color get gray0 => Colors.white;
+ static const Color gray0 = Color(0xFFFFFFFF);
- static Color get gray1 => const Color(0xFFF8FAFB);
+ static const Color gray1 = Color(0xFFF8FAFB);
- static Color get gray2 => const Color(0xFFEDEFEF);
+ static const Color gray2 = Color(0xFFEDEFEF);
- static Color get gray3 => const Color(0xFFDEDFDF);
+ static const Color gray3 = Color(0xFFDEDFDF);
- static Color get gray4 => const Color(0xFFBFBFBF);
+ static const Color gray4 = Color(0xFFBFBFBF);
- static Color get gray5 => const Color(0xFFA2A2A2);
+ static const Color gray5 = Color(0xFFA2A2A2);
- static Color get gray6 => const Color(0xFF848484);
+ static const Color gray6 = Color(0xFF848484);
- static Color get gray7 => const Color(0xFF616569);
+ static const Color gray7 = Color(0xFF616569);
- static Color get gray8 => const Color(0xFF3E464E);
+ static const Color gray8 = Color(0xFF3E464E);
- static Color get gray9 => const Color(0xFF1B1C1D);
+ // Gray 850 – dark mode elevated/input surface (#2d3136)
+ static const Color gray850 = Color(0xFF2D3136);
- static Color get gray10 => Colors.black;
+ static const Color gray9 = Color(0xFF1B1C1D);
- static Color get gray11 => const Color(0xFF040404);
+ static const Color gray10 = Color(0xFF000000);
- static Color get gray12 => const Color(0xFFBDBDBD);
- static Color get lightGray => const Color(0xFF838383);
+ static const Color gray11 = Color(0xFF040404);
- static Color get yellow0 => const Color(0xFFFEFDF6);
+ static const Color gray12 = Color(0xFFBDBDBD);
+ static const Color lightGray = Color(0xFF838383);
- static Color get yellow1 => const Color(0xFFFCF8E8);
+ static const Color yellow0 = Color(0xFFFEFDF6);
- static Color get yellow2 => const Color(0xFFFAF1D6);
+ static const Color yellow1 = Color(0xFFFCF8E8);
- static Color get yellow3 => const Color(0xFFFFC105);
+ static const Color yellow2 = Color(0xFFFAF1D6);
- static Color get yellow4 => const Color(0xFFD6A100);
+ static const Color yellow3 = Color(0xFFFFC105);
- static Color get yellow5 => const Color(0xFFB88A00);
+ static const Color yellow4 = Color(0xFFD6A100);
- static Color get yellow6 => const Color(0xFF946F00);
+ static const Color yellow5 = Color(0xFFB88A00);
- static Color get yellow7 => const Color(0xFF7A5C00);
+ static const Color yellow6 = Color(0xFF946F00);
- static Color get yellow8 => const Color(0xFF503C02);
+ static const Color yellow7 = Color(0xFF7A5C00);
- static Color get yellow9 => const Color(0xFF3D2D00);
+ static const Color yellow8 = Color(0xFF503C02);
- static Color get yellow10 => const Color(0xFF241800);
+ static const Color yellow9 = Color(0xFF3D2D00);
- static Color get green0 => const Color(0xFFFBFFFA);
+ static const Color yellow10 = Color(0xFF241800);
- static Color get green1 => const Color(0xFFF0FFF4);
+ static const Color green0 = Color(0xFFFBFFFA);
- static Color get green2 => const Color(0xFFD4FAD6);
+ static const Color green1 = Color(0xFFF0FFF4);
- static Color get green3 => const Color(0xFFA2DDAF);
+ static const Color green2 = Color(0xFFD4FAD6);
- static Color get green4 => const Color(0xFF6FC087);
+ static const Color green3 = Color(0xFFA2DDAF);
- static Color get green5 => const Color(0xFF3DA360);
+ static const Color green4 = Color(0xFF6FC087);
- static Color get green6 => const Color(0xFF0A8638);
+ static const Color green5 = Color(0xFF3DA360);
- static Color get green7 => const Color(0xFF006E2B);
+ static const Color green6 = Color(0xFF0A8638);
- static Color get green8 => const Color(0xFF00531F);
+ static const Color green7 = Color(0xFF006E2B);
- static Color get green9 => const Color(0xFF003913);
+ static const Color green8 = Color(0xFF00531F);
- static Color get green10 => const Color(0xFF002108);
+ static const Color green9 = Color(0xFF003913);
- static Color get green11 => const Color(0xFF005F61);
+ static const Color green10 = Color(0xFF002108);
- static Color get green12 => const Color(0xFF1FBF63);
+ static const Color green11 = Color(0xFF005F61);
- static Color get red0 => const Color(0xFFFFF8F7);
+ static const Color green12 = Color(0xFF1FBF63);
- static Color get red1 => const Color(0xFFFFEDEA);
+ static const Color red0 = Color(0xFFFFF8F7);
- static Color get red2 => const Color(0xFFFFDAD5);
+ static const Color red1 = Color(0xFFFFEDEA);
- static Color get red3 => const Color(0xFFFFB4AA);
+ static const Color red2 = Color(0xFFFFDAD5);
- static Color get red4 => const Color(0xFFFF8A7C);
+ static const Color red3 = Color(0xFFFFB4AA);
- static Color get red5 => const Color(0xFFFF5447);
+ static const Color red4 = Color(0xFFFF8A7C);
- static Color get red6 => const Color(0xFFDB1C1C);
+ static const Color red5 = Color(0xFFFF5447);
- static Color get red7 => const Color(0xFFC0000E);
+ static const Color red6 = Color(0xFFDB1C1C);
- static Color get red8 => const Color(0xFF930008);
+ static const Color red7 = Color(0xFFC0000E);
- static Color get red9 => const Color(0xFF690004);
+ static const Color red8 = Color(0xFF930008);
- static Color get red10 => const Color(0xFF410001);
+ static const Color red9 = Color(0xFF690004);
- static Color get shadowColor => const Color(0x19006162);
+ static const Color red10 = Color(0xFF410001);
- static Color get logTextColor => const Color(0xFF3D454D);
- static Color get linkColor => const Color(0xFF005F60);
+ static const Color shadowColor = Color(0x19006162);
+
+ static const Color logTextColor = Color(0xFF3D454D);
+ static const Color linkColor = Color(0xFF005F60);
}
diff --git a/lib/core/common/app_dialog.dart b/lib/core/common/app_dialog.dart
index c779559d52..a32ced004d 100644
--- a/lib/core/common/app_dialog.dart
+++ b/lib/core/common/app_dialog.dart
@@ -15,13 +15,9 @@ class AppDialog {
barrierDismissible: false,
builder: (context) {
return AlertDialog(
- backgroundColor: AppColors.gray1,
+ // backgroundColor and shape come from dialogTheme in app_theme.dart
contentPadding: EdgeInsets.symmetric(horizontal: defaultSize),
actionsPadding: EdgeInsets.all(24),
- // contentPadding: EdgeInsets.zero,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(16),
- ),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
@@ -83,7 +79,7 @@ class AppDialog {
return AlertDialog(
actionsAlignment: MainAxisAlignment.end,
actionsOverflowAlignment: OverflowBarAlignment.end,
- backgroundColor: AppColors.gray1,
+ // backgroundColor and shape come from dialogTheme in app_theme.dart
contentPadding: EdgeInsets.symmetric(horizontal: size24),
actionsPadding: actionPadding ??
EdgeInsets.only(
@@ -91,10 +87,6 @@ class AppDialog {
bottom: defaultSize,
left: defaultSize,
right: defaultSize),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(16),
- side: BorderSide(color: AppColors.gray3, width: 1),
- ),
content: content,
actions: action,
);
@@ -113,17 +105,13 @@ class AppDialog {
barrierDismissible: false,
builder: (context) {
return AlertDialog(
- backgroundColor: AppColors.gray3,
+ // backgroundColor and shape come from dialogTheme in app_theme.dart
contentPadding: EdgeInsets.symmetric(horizontal: defaultSize),
actionsPadding: EdgeInsets.only(
top: defaultSize,
bottom: defaultSize,
left: defaultSize,
right: defaultSize),
- // contentPadding: EdgeInsets.zero,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(16),
- ),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
@@ -161,17 +149,13 @@ class AppDialog {
barrierDismissible: false,
builder: (context) {
return AlertDialog(
- backgroundColor: AppColors.gray3,
+ // backgroundColor and shape come from dialogTheme in app_theme.dart
contentPadding: EdgeInsets.symmetric(horizontal: defaultSize),
actionsPadding: EdgeInsets.only(
top: defaultSize,
bottom: defaultSize,
left: defaultSize,
right: defaultSize),
- // contentPadding: EdgeInsets.zero,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(16),
- ),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
diff --git a/lib/core/common/app_dropdown.dart b/lib/core/common/app_dropdown.dart
index f3e965fa09..84db83bee9 100644
--- a/lib/core/common/app_dropdown.dart
+++ b/lib/core/common/app_dropdown.dart
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:lantern/core/common/app_asset.dart';
+import 'package:lantern/core/common/app_semantic_colors.dart';
import 'app_colors.dart' show AppColors;
@@ -28,7 +29,7 @@ class AppDropdown extends StatelessWidget {
height: 56,
decoration: BoxDecoration(
border: Border.all(
- color: AppColors.gray3,
+ color: context.borderInput,
width: 1,
),
borderRadius: BorderRadius.circular(16),
@@ -41,7 +42,7 @@ class AppDropdown extends StatelessWidget {
isExpanded: true,
padding: EdgeInsets.only(left: prefixIconPath != null ? 8 : 0),
style: textTheme.bodyMedium!.copyWith(
- color: AppColors.gray9,
+ color: context.textPrimary,
),
value: value,
borderRadius: BorderRadius.circular(16),
@@ -63,7 +64,7 @@ class AppDropdown extends StatelessWidget {
child: Text(
label!,
style: textTheme.labelLarge?.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
fontSize: 14.sp,
),
),
diff --git a/lib/core/common/app_image_paths.dart b/lib/core/common/app_image_paths.dart
index a7a3d7cab6..84250edfd6 100644
--- a/lib/core/common/app_image_paths.dart
+++ b/lib/core/common/app_image_paths.dart
@@ -108,6 +108,9 @@ class AppImagePaths {
static const nonProfit = 'assets/images/non_profit.svg';
static const privateServerIntro = 'assets/images/private_server_intro.svg';
static const smartRouteMode = 'assets/images/smart_route_mode.svg';
+ static const automatic = 'assets/images/automatic.svg';
+ static const lightMode = 'assets/images/light_mode.svg';
+ static const darkMode = 'assets/images/dark_mode.svg';
/// Validates and returns a safe flag path for the given country code.
/// Returns null if the country code is invalid or the flag asset doesn't exist.
diff --git a/lib/core/common/app_semantic_colors.dart b/lib/core/common/app_semantic_colors.dart
new file mode 100644
index 0000000000..74b15e2d5a
--- /dev/null
+++ b/lib/core/common/app_semantic_colors.dart
@@ -0,0 +1,272 @@
+import 'package:flutter/material.dart';
+import 'app_colors.dart';
+
+/// BuildContext extension that maps Figma Color/Semantic tokens to AppColors.
+/// Every property has a light and dark value derived directly from the JSON export.
+///
+/// Usage: context.textPrimary, context.bgElevated, context.borderInput …
+extension AppSemanticColors on BuildContext {
+ bool get _isDark => Theme.of(this).brightness == Brightness.dark;
+
+ // ── Text ────────────────────────────────────────────────────────────────────
+
+ /// text.primary Gray.900 light / Gray.200 dark
+ Color get textPrimary => _isDark ? AppColors.gray2 : AppColors.gray9;
+
+ /// text.secondary Gray.800 light / Gray.300 dark
+ Color get textSecondary => _isDark ? AppColors.gray3 : AppColors.gray8;
+
+ /// text.tertiary Gray.700 light / Gray.400 dark
+ Color get textTertiary => _isDark ? AppColors.gray4 : AppColors.gray7;
+
+ /// text.link Blue.700 light / Blue.200 dark
+ Color get textLink => _isDark ? AppColors.blue2 : AppColors.blue7;
+
+ /// text.disabled Gray.600 light / Gray.500 dark
+ Color get textDisabled => _isDark ? AppColors.gray5 : AppColors.gray6;
+
+ /// text.inverse Gray.100 light / Gray.900 dark
+ Color get textInverse => _isDark ? AppColors.gray9 : AppColors.gray1;
+
+ /// text.inverse-color Blue.400 light / Blue.600 dark
+ Color get textInverseColor => _isDark ? AppColors.blue6 : AppColors.blue4;
+
+ /// text.promo-icon Yellow.300 both modes
+ Color get textPromoIcon => AppColors.yellow3;
+
+ // ── Background ──────────────────────────────────────────────────────────────
+
+ /// bg.surface Gray.100 light / Gray.900 dark
+ Color get bgSurface => _isDark ? AppColors.gray9 : AppColors.gray1;
+
+ /// bg.elevated White light / Gray.850 dark
+ Color get bgElevated => _isDark ? AppColors.gray850 : AppColors.white;
+
+ /// bg.input White light / Gray.850 dark
+ Color get bgInput => _isDark ? AppColors.gray850 : AppColors.white;
+
+ /// bg.hover Blue.100 light / Blue.900 dark
+ Color get bgHover => _isDark ? AppColors.blue9 : AppColors.blue1;
+
+ /// bg.overlay Gray.100 light / Gray.900 dark
+ Color get bgOverlay => _isDark ? AppColors.gray9 : AppColors.gray1;
+
+ /// bg.callout Gray.200 light / Gray.800 dark
+ Color get bgCallout => _isDark ? AppColors.gray8 : AppColors.gray2;
+
+ /// bg.snackbar Blue.900 light / Blue.200 dark
+ Color get bgSnackbar => _isDark ? AppColors.blue2 : AppColors.blue9;
+
+ /// bg.snackbar-error Red.700 light / Red.500 dark
+ Color get bgSnackbarError => _isDark ? AppColors.red5 : AppColors.red7;
+
+ /// bg.promo Yellow.100 light / Gray.900 dark
+ Color get bgPromo => _isDark ? AppColors.gray9 : AppColors.yellow1;
+
+ // ── Border ──────────────────────────────────────────────────────────────────
+
+ /// border.default Gray.200 light / Gray.800 dark
+ Color get borderDefault => _isDark ? AppColors.gray8 : AppColors.gray2;
+
+ /// border.input Gray.300 light / Gray.700 dark
+ Color get borderInput => _isDark ? AppColors.gray7 : AppColors.gray3;
+
+ /// border.input-focus Blue.800 light / Blue.200 dark
+ Color get borderInputFocus => _isDark ? AppColors.blue2 : AppColors.blue8;
+
+ /// border.input-filled Gray.900 light / Gray.400 dark
+ Color get borderInputFilled => _isDark ? AppColors.gray4 : AppColors.gray9;
+
+ /// border.error Red.600 light / Red.500 dark
+ Color get borderError => _isDark ? AppColors.red5 : AppColors.red6;
+
+ /// border.promo Yellow.500 both modes
+ Color get borderPromo => AppColors.yellow5;
+
+ // ── Status ──────────────────────────────────────────────────────────────────
+
+ /// status.error-text Red.800 light / Red.200 dark
+ Color get statusErrorText => _isDark ? AppColors.red2 : AppColors.red8;
+
+ /// status.error-bg Red.200 light / Red.800 dark
+ Color get statusErrorBg => _isDark ? AppColors.red8 : AppColors.red2;
+
+ /// status.error-border Red.400 light / Red.600 dark
+ Color get statusErrorBorder => _isDark ? AppColors.red6 : AppColors.red4;
+
+ /// status.success-text Green.800 light / Green.300 dark
+ Color get statusSuccessText => _isDark ? AppColors.green3 : AppColors.green8;
+
+ /// status.success-bg Green.200 light / Green.700 dark
+ Color get statusSuccessBg => _isDark ? AppColors.green7 : AppColors.green2;
+
+ /// status.success-border Green.400 light / Green.600 dark
+ Color get statusSuccessBorder =>
+ _isDark ? AppColors.green6 : AppColors.green4;
+
+ /// status.warning-text Yellow.500 light / Yellow.200 dark
+ Color get statusWarningText => _isDark ? AppColors.yellow2 : AppColors.yellow5;
+
+ /// status.warning-bg-dot Yellow.300 light / Yellow.500 dark
+ Color get statusWarningBgDot =>
+ _isDark ? AppColors.yellow5 : AppColors.yellow3;
+
+ /// status.neutral-text Gray.600 light / Gray.200 dark
+ Color get statusNeutralText => _isDark ? AppColors.gray2 : AppColors.gray6;
+
+ /// status.informational-text Blue.800 light / Blue.200 dark
+ Color get statusInfoText => _isDark ? AppColors.blue2 : AppColors.blue8;
+
+ /// status.Informational-bg Blue.200 light / Blue.700 dark
+ Color get statusInfoBg => _isDark ? AppColors.blue7 : AppColors.blue2;
+
+ /// status.Informational-border Blue.400 light / Blue.600 dark
+ Color get statusInfoBorder => _isDark ? AppColors.blue6 : AppColors.blue4;
+
+ /// status.error-bg-dot Red.600 light / Red.800 dark
+ Color get statusErrorBgDot => _isDark ? AppColors.red8 : AppColors.red6;
+
+ /// status.error-border-dot Red.300 light / Red.500 dark
+ Color get statusErrorBorderDot => _isDark ? AppColors.red5 : AppColors.red3;
+
+ /// status.warning-border-dot Yellow.200 light / Yellow.400 dark
+ Color get statusWarningBorderDot =>
+ _isDark ? AppColors.yellow4 : AppColors.yellow2;
+
+ /// status.success-bg-dot Green.600 light / Green.700 dark
+ Color get statusSuccessBgDot =>
+ _isDark ? AppColors.green7 : AppColors.green6;
+
+ /// status.success-border-dot Green.300 light / Green.500 dark
+ Color get statusSuccessBorderDot =>
+ _isDark ? AppColors.green5 : AppColors.green3;
+
+ /// status.neutral-bg-dot Gray.500 light / Gray.700 dark
+ Color get statusNeutralBgDot => _isDark ? AppColors.gray7 : AppColors.gray5;
+
+ /// status.neutral-border-dot Gray.300 light / Gray.500 dark
+ Color get statusNeutralBorderDot =>
+ _isDark ? AppColors.gray5 : AppColors.gray3;
+
+ // ── Action / Primary ────────────────────────────────────────────────────────
+
+ /// action.primary.primary-bg Blue.1000 light / Blue.600 dark
+ Color get actionPrimaryBg => _isDark ? AppColors.blue6 : AppColors.blue10;
+
+ /// action.primary.primary-bg-hover Blue.800 light / Blue.500 dark
+ Color get actionPrimaryBgHover => _isDark ? AppColors.blue5 : AppColors.blue8;
+
+ /// action.primary.primary-text Gray.100 both modes
+ Color get actionPrimaryText => AppColors.gray1;
+
+ /// action.primary.primary-disabled-bg Gray.200 light / Gray.700 dark
+ Color get actionPrimaryDisabledBg =>
+ _isDark ? AppColors.gray7 : AppColors.gray2;
+
+ /// action.primary.primary-disabled-text Gray.500 both modes
+ Color get actionPrimaryDisabledText => AppColors.gray5;
+
+ /// action.primary.primary-disabled-border Gray.400 light / Gray.500 dark
+ Color get actionPrimaryDisabledBorder =>
+ _isDark ? AppColors.gray5 : AppColors.gray4;
+
+ // ── Action / Secondary ──────────────────────────────────────────────────────
+
+ /// action.secondary.secondary-bg Gray.100 light / Gray.900 dark
+ Color get actionSecondaryBg => _isDark ? AppColors.gray9 : AppColors.gray1;
+
+ /// action.secondary.secondary-bg-hover Gray.200 light / Gray.800 dark
+ Color get actionSecondaryBgHover =>
+ _isDark ? AppColors.gray8 : AppColors.gray2;
+
+ /// action.secondary.secondary-text Gray.900 light / Gray.100 dark
+ Color get actionSecondaryText => _isDark ? AppColors.gray1 : AppColors.gray9;
+
+ /// action.secondary.secondary-border Gray.500 light / Gray.600 dark
+ Color get actionSecondaryBorder =>
+ _isDark ? AppColors.gray6 : AppColors.gray5;
+
+ /// action.secondary.secondary-disabled-bg Gray.200 light / Gray.900 dark
+ Color get actionSecondaryDisabledBg =>
+ _isDark ? AppColors.gray9 : AppColors.gray2;
+
+ /// action.secondary.secondary-disabled-text Gray.500 both modes
+ Color get actionSecondaryDisabledText => AppColors.gray5;
+
+ /// action.secondary.secondary-disabled-border Gray.300 light / Gray.700 dark
+ Color get actionSecondaryDisabledBorder =>
+ _isDark ? AppColors.gray7 : AppColors.gray3;
+
+ // ── Action / Tertiary ───────────────────────────────────────────────────────
+
+ /// action.tertiary.tertiary-text Gray.900 light / Gray.100 dark
+ Color get actionTertiaryText => _isDark ? AppColors.gray1 : AppColors.gray9;
+
+ /// action.tertiary.tertiary-hover-bg Gray.200 light / Gray.800 dark
+ Color get actionTertiaryHoverBg =>
+ _isDark ? AppColors.gray8 : AppColors.gray2;
+
+ /// action.tertiary.tertiary-disabled-text Gray.500 both modes
+ Color get actionTertiaryDisabledText => AppColors.gray5;
+
+ // ── Action / Tonal ──────────────────────────────────────────────────────────
+
+ /// action.tonal.tonal-bg Blue.100 light / Blue.700 dark
+ Color get actionTonalBg => _isDark ? AppColors.blue7 : AppColors.blue1;
+
+ /// action.tonal.tonal-border Gray.200 light / Gray.800 dark
+ Color get actionTonalBorder => _isDark ? AppColors.gray8 : AppColors.gray2;
+
+ /// action.tonal.tonal-bg-hover Blue.200 light / Blue.600 dark
+ Color get actionTonalBgHover => _isDark ? AppColors.blue6 : AppColors.blue2;
+
+ /// action.tonal.tonal-text Gray.900 light / Gray.100 dark
+ Color get actionTonalText => _isDark ? AppColors.gray1 : AppColors.gray9;
+
+ /// action.tonal.tonal-disabled-bg Gray.100 light / Gray.800 dark
+ Color get actionTonalDisabledBg =>
+ _isDark ? AppColors.gray8 : AppColors.gray1;
+
+ /// action.tonal.tonal-disabled-border Gray.200 light / Gray.800 dark
+ Color get actionTonalDisabledBorder =>
+ _isDark ? AppColors.gray8 : AppColors.gray2;
+
+ /// action.tonal.tonal-disabled-text Gray.400 light / Gray.500 dark
+ Color get actionTonalDisabledText =>
+ _isDark ? AppColors.gray5 : AppColors.gray4;
+
+ // ── Action / Toggle ─────────────────────────────────────────────────────────
+
+ /// action.toggle.toggle-active-bg Green.500 light / Green.700 dark
+ Color get actionToggleActiveBg =>
+ _isDark ? AppColors.green7 : AppColors.green5;
+
+ /// action.toggle.toggle-brand-active-bg Blue.400 light / Blue.600 dark
+ Color get actionToggleBrandActiveBg =>
+ _isDark ? AppColors.blue6 : AppColors.blue4;
+
+ /// action.toggle.toggle-disabled-bg Gray.700 both modes
+ Color get actionToggleDisabledBg => AppColors.gray7;
+
+ /// action.toggle.toggle-knob-bg Gray.000 light / Gray.100 dark
+ Color get actionToggleKnobBg => _isDark ? AppColors.gray1 : AppColors.gray0;
+
+ /// action.toggle.toggle-border Gray.200 light / Gray.700 dark
+ Color get actionToggleBorder => _isDark ? AppColors.gray7 : AppColors.gray2;
+
+ // ── Action / Tabbar ─────────────────────────────────────────────────────────
+
+ /// action.tabbar.tabbar-bg Blue.200 light / Blue.800 dark
+ Color get actionTabbarBg => _isDark ? AppColors.blue8 : AppColors.blue2;
+
+ /// action.tabbar.tabbar-border Blue.300 light / Blue.700 dark
+ Color get actionTabbarBorder => _isDark ? AppColors.blue7 : AppColors.blue3;
+
+ /// action.tabbar.tabbar-selected-text Blue.1000 light / Blue.100 dark
+ Color get actionTabbarSelectedText =>
+ _isDark ? AppColors.blue1 : AppColors.blue10;
+
+ /// action.tabbar.tabbar-disabled-text Gray.600 light / Gray.200 dark
+ Color get actionTabbarDisabledText =>
+ _isDark ? AppColors.gray2 : AppColors.gray6;
+}
diff --git a/lib/core/common/app_text_field.dart b/lib/core/common/app_text_field.dart
index a94eee284a..7fa8a7683d 100644
--- a/lib/core/common/app_text_field.dart
+++ b/lib/core/common/app_text_field.dart
@@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:lantern/core/common/app_asset.dart';
-import 'package:lantern/core/common/app_colors.dart';
import 'package:lantern/core/common/app_dimens.dart';
+import 'package:lantern/core/common/app_semantic_colors.dart';
import 'package:lantern/core/common/cap_scaling.dart';
class AppTextField extends StatelessWidget {
@@ -82,14 +82,14 @@ class AppTextField extends StatelessWidget {
onEditingComplete: onEditingComplete,
readOnly: onTap != null,
onTap: onTap,
- cursorColor: AppColors.blue10,
+ // cursorColor from textSelectionTheme
autovalidateMode: autovalidateMode,
validator: validator,
cursorRadius: Radius.circular(16),
cursorHeight: defaultSize,
cursorOpacityAnimates: true,
style: textTheme.bodyMedium!.copyWith(
- color: AppColors.gray9,
+ // text color from colorScheme.onSurface via theme
fontSize: spCap(context, 14),
),
textInputAction: textInputAction,
@@ -100,50 +100,18 @@ class AppTextField extends StatelessWidget {
required maxLength}) =>
counter,
decoration: InputDecoration(
- contentPadding: EdgeInsets.symmetric(vertical: 20, horizontal: 16),
+ // borders, hintStyle, contentPadding come from inputDecorationTheme
filled: true,
- fillColor: enable ? AppColors.white : AppColors.gray3,
+ fillColor: enable
+ ? context.bgElevated // bg.input = bg.elevated
+ : context.bgCallout, // bg.callout for disabled
hintText: hintText,
- hintStyle: textTheme.bodyMedium!.copyWith(
- color: AppColors.gray4,
- ),
- prefixIcon: prefixIcon != null ? _buildFix(prefixIcon!) : null,
- suffixIcon: suffixIcon != null ? _buildFix(suffixIcon!) : null,
- border: OutlineInputBorder(
- borderRadius: defaultBorderRadius,
- borderSide: BorderSide(
- color: AppColors.gray3,
- width: 1,
- ),
- ),
- enabledBorder: OutlineInputBorder(
- borderRadius: defaultBorderRadius,
- borderSide: BorderSide(
- color: AppColors.gray3,
- width: 1,
- ),
- ),
- focusedBorder: OutlineInputBorder(
- borderRadius: defaultBorderRadius,
- borderSide: BorderSide(
- color: AppColors.blue8,
- width: 2,
- ),
- ),
- errorBorder: OutlineInputBorder(
- borderRadius: defaultBorderRadius,
- borderSide: BorderSide(
- color: Colors.grey,
- width: 1,
- ),
- ),
- disabledBorder: OutlineInputBorder(
- borderRadius: defaultBorderRadius,
- borderSide: BorderSide(
- color: AppColors.gray3,
- width: 1,
- ),
- ),
+ prefixIcon: prefixIcon != null
+ ? _buildFix(prefixIcon!, iconColor: context.textPrimary)
+ : null,
+ suffixIcon: suffixIcon != null
+ ? _buildFix(suffixIcon!, iconColor: context.textPrimary)
+ : null,
));
// If a label is provided, wrap the input field in a Column with a Text widget above.
@@ -157,7 +125,7 @@ class AppTextField extends StatelessWidget {
child: Text(
label!,
style: textTheme.labelLarge?.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary, // text.secondary
fontSize: spCap(context, 14),
),
),
@@ -171,14 +139,14 @@ class AppTextField extends StatelessWidget {
return inputField;
}
- Widget _buildFix(Object iconPath) {
+ Widget _buildFix(Object iconPath, {Color? iconColor}) {
Widget? appAsset;
if (iconPath is IconData) {
- appAsset = Icon(iconPath, color: AppColors.yellow9);
+ appAsset = Icon(iconPath, color: iconColor);
} else if (iconPath is String) {
appAsset = AppImage(
path: iconPath,
- color: AppColors.yellow9,
+ color: iconColor,
);
} else if (iconPath is Widget) {
appAsset = iconPath;
diff --git a/lib/core/common/app_text_styles.dart b/lib/core/common/app_text_styles.dart
index 6c94e33224..ed02f41c36 100644
--- a/lib/core/common/app_text_styles.dart
+++ b/lib/core/common/app_text_styles.dart
@@ -9,37 +9,37 @@ class AppTextStyles {
static TextStyle get displayLarge => GoogleFonts.urbanist(
fontSize: 56,
fontWeight: FontWeight.w700,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get displayMedium => GoogleFonts.urbanist(
fontSize: 44,
fontWeight: FontWeight.w700,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get displaySmall => GoogleFonts.urbanist(
fontSize: 36,
fontWeight: FontWeight.w700,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get headingLarge => GoogleFonts.urbanist(
fontSize: 32,
fontWeight: FontWeight.w600,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get headingMedium => GoogleFonts.urbanist(
fontSize: 28,
fontWeight: FontWeight.w600,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get headingSmall => GoogleFonts.urbanist(
fontSize: 24,
fontWeight: FontWeight.w600,
- color: AppColors.black,
+ // color: AppColors.black,
letterSpacing: 0,
);
@@ -47,75 +47,75 @@ class AppTextStyles {
fontSize: 14,
fontWeight: FontWeight.w400,
letterSpacing: 0,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get labelLargeBold => GoogleFonts.urbanist(
fontSize: 14,
fontWeight: FontWeight.bold,
letterSpacing: 0,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get labelMedium => GoogleFonts.urbanist(
fontSize: 12,
fontWeight: FontWeight.w500,
- color: AppColors.black,
+ // color: AppColors.black,
letterSpacing: 0.0,
);
static TextStyle get labelSmall => GoogleFonts.urbanist(
fontSize: 10,
fontWeight: FontWeight.w500,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get titleLarge => GoogleFonts.urbanist(
fontSize: 22,
fontWeight: FontWeight.w600,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get titleMedium => GoogleFonts.urbanist(
fontSize: 16,
fontWeight: FontWeight.w600,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get titleSmall => GoogleFonts.urbanist(
fontSize: 14,
fontWeight: FontWeight.w600,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get bodyLarge => GoogleFonts.urbanist(
fontSize: 16,
fontWeight: FontWeight.w400,
- color: AppColors.black,
+ // color: AppColors.black,
letterSpacing: 0);
static TextStyle get bodyLargeBold => GoogleFonts.urbanist(
fontSize: 16,
fontWeight: FontWeight.bold,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get bodyMedium => GoogleFonts.urbanist(
fontSize: 14,
fontWeight: FontWeight.w400,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get bodyMediumBold => GoogleFonts.urbanist(
fontSize: 14,
fontWeight: FontWeight.bold,
- color: AppColors.black,
+ // color: AppColors.black,
);
static TextStyle get bodySmall => GoogleFonts.urbanist(
fontSize: 12,
fontWeight: FontWeight.w400,
- color: AppColors.black,
+ // color: AppColors.black,
);
//Text style for button
diff --git a/lib/core/common/app_theme.dart b/lib/core/common/app_theme.dart
index 34e32d7ecd..68c3bf94b5 100644
--- a/lib/core/common/app_theme.dart
+++ b/lib/core/common/app_theme.dart
@@ -5,16 +5,76 @@ import 'package:lantern/core/common/app_text_styles.dart';
import 'app_colors.dart';
+// ─────────────────────────────────────────────────────────────────────────────
+// Figma token → ColorScheme slot reference
+//
+// token light dark
+// ─────────────────────────────────────────────────────────────────────────────
+// bg.elevated white gray850 → surface
+// bg.surface gray1 gray9 → surfaceContainer
+// bg.callout gray2 gray8 → surfaceContainerHighest
+// bg.hover blue1 blue9 → primaryContainer
+// text.primary gray9 gray2 → onSurface
+// text.secondary gray8 gray3 → onSurfaceVariant
+// text.link blue8(≈blue7) blue2 → primary (textButtonTheme)
+// border.default gray2 gray8 → outline
+// border.input gray3 gray7 → outlineVariant
+// border.input-focus blue8 blue2 → primary (focused border)
+// border.error red6 red5 → error
+// status.error-bg red2 red8 → errorContainer
+// status.error-text red8 red2 → onErrorContainer
+// action.primary.bg blue10 blue6 → primary (elevatedButton)
+// ─────────────────────────────────────────────────────────────────────────────
+
class AppTheme {
+ // ── Light ──────────────────────────────────────────────────────────────────
+
static ThemeData appTheme() {
+ const cs = ColorScheme.light(
+ // Primary action / brand
+ primary: AppColors.blue10, // Blue.1000 – action.primary.bg
+ onPrimary: AppColors.gray1, // Gray.100 – action.primary.text
+ primaryContainer: AppColors.blue1, // Blue.100 – bg.hover
+ onPrimaryContainer: AppColors.gray9,
+ // Secondary
+ secondary: AppColors.blue7, // Blue.700
+ onSecondary: AppColors.gray1,
+ secondaryContainer: AppColors.blue2, // Blue.200
+ onSecondaryContainer: AppColors.gray9,
+ // Success (tertiary)
+ tertiary: AppColors.green5, // Green.500 – toggle-active-bg
+ onTertiary: AppColors.gray1,
+ tertiaryContainer: AppColors.green2, // Green.200 – status.success-bg
+ onTertiaryContainer: AppColors.green8, // Green.800 – status.success-text
+ // Error
+ error: AppColors.red6, // Red.600 – border.error
+ onError: AppColors.gray1,
+ errorContainer: AppColors.red2, // Red.200 – status.error-bg
+ onErrorContainer: AppColors.red8, // Red.800 – status.error-text
+ // Surfaces
+ surface: AppColors.white, // White – bg.elevated (Card, Dialog, Sheet)
+ onSurface: AppColors.gray9, // Gray.900 – text.primary
+ onSurfaceVariant: AppColors.gray8, // Gray.800 – text.secondary
+ surfaceContainer: AppColors.gray1, // Gray.100 – bg.surface
+ surfaceContainerHighest: AppColors.gray2, // Gray.200 – bg.callout
+ // Borders
+ outline: AppColors.gray2, // Gray.200 – border.default
+ outlineVariant: AppColors.gray3, // Gray.300 – border.input
+ );
+
return ThemeData(
useMaterial3: true,
+ colorScheme: cs,
hoverColor: AppColors.blue1,
+ scaffoldBackgroundColor: AppColors.gray1, // bg.surface
+ primaryColor: AppColors.blue10,
pageTransitionsTheme: const PageTransitionsTheme(
builders: {
TargetPlatform.android: FadeForwardsPageTransitionsBuilder(),
},
),
+
+ // ── Text ────────────────────────────────────────────────────────────────
textSelectionTheme: TextSelectionThemeData(
cursorColor: AppColors.blue10,
selectionColor: AppColors.blue6,
@@ -37,6 +97,8 @@ class AppTheme {
titleMedium: AppTextStyles.titleMedium,
titleSmall: AppTextStyles.titleSmall,
),
+
+ // ── AppBar ──────────────────────────────────────────────────────────────
appBarTheme: AppBarTheme(
centerTitle: true,
surfaceTintColor: AppColors.white,
@@ -45,7 +107,7 @@ class AppTheme {
),
titleSpacing: 0,
elevation: 0,
- backgroundColor: AppColors.gray1,
+ backgroundColor: AppColors.gray1, // bg.surface
systemOverlayStyle: SystemUiOverlayStyle(
statusBarColor: AppColors.white,
statusBarBrightness: Brightness.light,
@@ -53,38 +115,113 @@ class AppTheme {
systemNavigationBarColor: AppColors.gray1,
systemNavigationBarIconBrightness: Brightness.dark,
),
- iconTheme: IconThemeData(
- color: AppColors.blue10,
- ),
+ iconTheme: IconThemeData(color: AppColors.blue10),
),
- primaryColor: AppColors.blue10,
- scaffoldBackgroundColor: AppColors.gray1,
+
+ // ── Card ────────────────────────────────────────────────────────────────
cardTheme: CardThemeData(
elevation: 0,
margin: EdgeInsets.zero,
- color: AppColors.white,
+ color: cs.surface, // bg.elevated
clipBehavior: Clip.hardEdge,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.0),
- side: BorderSide(
- color: AppColors.gray2,
- width: 1,
- ),
+ side: BorderSide(color: cs.outline, width: 1), // border.default
+ ),
+ ),
+
+ // ── Divider ─────────────────────────────────────────────────────────────
+ dividerTheme: DividerThemeData(
+ color: cs.outline, // border.default
+ thickness: 1,
+ ),
+
+ // ── Input / TextField ────────────────────────────────────────────────────
+ // Widgets using TextFormField / TextField inherit these automatically.
+ inputDecorationTheme: InputDecorationTheme(
+ filled: true,
+ fillColor: cs.surface, // bg.input = bg.elevated
+ contentPadding: const EdgeInsets.symmetric(vertical: 20, horizontal: 16),
+ hintStyle: TextStyle(color: AppColors.gray4),
+ labelStyle: TextStyle(color: cs.onSurfaceVariant), // text.secondary
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(16),
+ borderSide: BorderSide(color: cs.outlineVariant), // border.input
+ ),
+ enabledBorder: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(16),
+ borderSide: BorderSide(color: cs.outlineVariant),
+ ),
+ focusedBorder: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(16),
+ borderSide: BorderSide(color: AppColors.blue8, width: 2), // border.input-focus
+ ),
+ errorBorder: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(16),
+ borderSide: BorderSide(color: cs.error), // border.error
+ ),
+ focusedErrorBorder: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(16),
+ borderSide: BorderSide(color: cs.error, width: 2),
+ ),
+ disabledBorder: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(16),
+ borderSide: BorderSide(color: cs.outlineVariant),
+ ),
+ ),
+
+ // ── Dialog ──────────────────────────────────────────────────────────────
+ dialogTheme: DialogThemeData(
+ backgroundColor: cs.surface, // bg.elevated
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(16),
+ side: BorderSide(color: cs.outlineVariant, width: 1),
+ ),
+ titleTextStyle: AppTextStyles.headingSmall,
+ contentTextStyle: AppTextStyles.bodyMedium,
+ ),
+
+ // ── Bottom Sheet ─────────────────────────────────────────────────────────
+ bottomSheetTheme: BottomSheetThemeData(
+ backgroundColor: cs.surface, // bg.elevated
+ modalBackgroundColor: cs.surface,
+ dragHandleColor: AppColors.gray4,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
),
+
+ // ── ListTile (used by AppTile) ───────────────────────────────────────────
+ listTileTheme: ListTileThemeData(
+ textColor: cs.onSurface, // text.primary
+ iconColor: cs.onSurface,
+ selectedColor: cs.primary,
+ selectedTileColor: cs.primaryContainer, // bg.hover
+ ),
+
+ // ── TextButton (used by AppTextButton) ───────────────────────────────────
+ textButtonTheme: TextButtonThemeData(
+ style: TextButton.styleFrom(
+ foregroundColor: AppColors.blue7, // text.link light
+ ),
+ ),
+
+ // ── Radio ───────────────────────────────────────────────────────────────
radioTheme: RadioThemeData(
- fillColor: WidgetStatePropertyAll(AppColors.gray9),
+ fillColor: WidgetStatePropertyAll(cs.onSurface),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
splashRadius: 10.0,
),
+
+ // ── ElevatedButton (PrimaryButton) ───────────────────────────────────────
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
elevation: 0,
- backgroundColor: AppColors.blue10,
+ backgroundColor: cs.primary, // action.primary.primary-bg
enableFeedback: true,
- foregroundColor: AppColors.gray1,
+ foregroundColor: cs.onPrimary, // action.primary.primary-text
textStyle: AppTextStyles.primaryButtonTextStyle
- .copyWith(fontSize: 18.0, color: AppColors.gray1),
+ .copyWith(fontSize: 18.0, color: cs.onPrimary),
overlayColor: AppColors.blue6,
minimumSize: const Size(double.infinity, 52),
tapTargetSize: MaterialTapTargetSize.padded,
@@ -97,7 +234,212 @@ class AppTheme {
);
}
+ // ── Dark ───────────────────────────────────────────────────────────────────
+
static ThemeData darkTheme() {
- return ThemeData();
+ const cs = ColorScheme.dark(
+ // Primary action / brand
+ primary: AppColors.blue6, // Blue.600 – action.primary.bg
+ onPrimary: AppColors.gray1, // Gray.100 – action.primary.text
+ primaryContainer: AppColors.blue9, // Blue.900 – bg.hover
+ onPrimaryContainer: AppColors.gray2,
+ // Secondary
+ secondary: AppColors.blue5, // Blue.500
+ onSecondary: AppColors.gray1,
+ secondaryContainer: AppColors.blue7, // Blue.700
+ onSecondaryContainer: AppColors.gray2,
+ // Success (tertiary)
+ tertiary: AppColors.green7, // Green.700 – toggle-active-bg dark
+ onTertiary: AppColors.gray1,
+ tertiaryContainer: AppColors.green7,
+ onTertiaryContainer: AppColors.green3, // Green.300 – status.success-text dark
+ // Error
+ error: AppColors.red5, // Red.500 – border.error dark
+ onError: AppColors.gray1,
+ errorContainer: AppColors.red8, // Red.800 – status.error-bg dark
+ onErrorContainer: AppColors.red2, // Red.200 – status.error-text dark
+ // Surfaces
+ surface: AppColors.gray850, // Gray.850 – bg.elevated (Card, Dialog, Sheet)
+ onSurface: AppColors.gray2, // Gray.200 – text.primary dark
+ onSurfaceVariant: AppColors.gray3, // Gray.300 – text.secondary dark
+ surfaceContainer: AppColors.gray9, // Gray.900 – bg.surface dark
+ surfaceContainerHighest: AppColors.gray8, // Gray.800 – bg.callout dark
+ // Borders
+ outline: AppColors.gray8, // Gray.800 – border.default dark
+ outlineVariant: AppColors.gray7, // Gray.700 – border.input dark
+ );
+
+ return ThemeData(
+ useMaterial3: true,
+ brightness: Brightness.dark,
+ colorScheme: cs,
+ hoverColor: AppColors.blue9,
+ scaffoldBackgroundColor: AppColors.gray9, // bg.surface dark
+ primaryColor: AppColors.blue6,
+ pageTransitionsTheme: const PageTransitionsTheme(
+ builders: {
+ TargetPlatform.android: FadeForwardsPageTransitionsBuilder(),
+ },
+ ),
+
+ // ── Text ────────────────────────────────────────────────────────────────
+ textSelectionTheme: TextSelectionThemeData(
+ cursorColor: AppColors.blue6,
+ selectionColor: AppColors.blue7,
+ selectionHandleColor: AppColors.blue5,
+ ),
+ textTheme: GoogleFonts.urbanistTextTheme(
+ ThemeData(brightness: Brightness.dark).textTheme,
+ ).copyWith(
+ bodyLarge: AppTextStyles.bodyLarge,
+ bodyMedium: AppTextStyles.bodyMedium,
+ bodySmall: AppTextStyles.bodySmall,
+ displayLarge: AppTextStyles.displayLarge,
+ displayMedium: AppTextStyles.displayMedium,
+ displaySmall: AppTextStyles.displaySmall,
+ headlineLarge: AppTextStyles.headingLarge,
+ headlineMedium: AppTextStyles.headingMedium,
+ headlineSmall: AppTextStyles.headingSmall,
+ labelLarge: AppTextStyles.labelLarge,
+ labelMedium: AppTextStyles.labelMedium,
+ labelSmall: AppTextStyles.labelSmall,
+ titleLarge: AppTextStyles.titleLarge,
+ titleMedium: AppTextStyles.titleMedium,
+ titleSmall: AppTextStyles.titleSmall,
+ ),
+
+ // ── AppBar ──────────────────────────────────────────────────────────────
+ appBarTheme: AppBarTheme(
+ centerTitle: true,
+ surfaceTintColor: AppColors.gray850,
+ titleTextStyle: AppTextStyles.headingSmall.copyWith(
+ color: cs.onSurface, // text.primary dark
+ ),
+ titleSpacing: 0,
+ elevation: 0,
+ backgroundColor: AppColors.gray9, // bg.surface dark
+ systemOverlayStyle: SystemUiOverlayStyle(
+ statusBarColor: AppColors.gray9,
+ statusBarBrightness: Brightness.dark,
+ statusBarIconBrightness: Brightness.light,
+ systemNavigationBarColor: AppColors.gray9,
+ systemNavigationBarIconBrightness: Brightness.light,
+ ),
+ iconTheme: IconThemeData(color: cs.onSurface),
+ ),
+
+ // ── Card ────────────────────────────────────────────────────────────────
+ cardTheme: CardThemeData(
+ elevation: 0,
+ margin: EdgeInsets.zero,
+ color: cs.surface, // bg.elevated dark
+ clipBehavior: Clip.hardEdge,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(16.0),
+ side: BorderSide(color: cs.outline, width: 1), // border.default dark
+ ),
+ ),
+
+ // ── Divider ─────────────────────────────────────────────────────────────
+ dividerTheme: DividerThemeData(
+ color: cs.outline, // border.default dark
+ thickness: 1,
+ ),
+
+ // ── Input / TextField ────────────────────────────────────────────────────
+ inputDecorationTheme: InputDecorationTheme(
+ filled: true,
+ fillColor: cs.surface, // bg.input dark (gray850)
+ contentPadding: const EdgeInsets.symmetric(vertical: 20, horizontal: 16),
+ hintStyle: TextStyle(color: AppColors.gray5), // text.disabled dark
+ labelStyle: TextStyle(color: cs.onSurfaceVariant), // text.secondary dark
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(16),
+ borderSide: BorderSide(color: cs.outlineVariant), // border.input dark
+ ),
+ enabledBorder: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(16),
+ borderSide: BorderSide(color: cs.outlineVariant),
+ ),
+ focusedBorder: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(16),
+ borderSide: BorderSide(color: AppColors.blue2, width: 2), // border.input-focus dark
+ ),
+ errorBorder: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(16),
+ borderSide: BorderSide(color: cs.error), // border.error dark
+ ),
+ focusedErrorBorder: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(16),
+ borderSide: BorderSide(color: cs.error, width: 2),
+ ),
+ disabledBorder: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(16),
+ borderSide: BorderSide(color: cs.outlineVariant),
+ ),
+ ),
+
+ // ── Dialog ──────────────────────────────────────────────────────────────
+ dialogTheme: DialogThemeData(
+ backgroundColor: cs.surface, // bg.elevated dark
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(16),
+ side: BorderSide(color: cs.outlineVariant, width: 1),
+ ),
+ titleTextStyle: AppTextStyles.headingSmall,
+ contentTextStyle: AppTextStyles.bodyMedium,
+ ),
+
+ // ── Bottom Sheet ─────────────────────────────────────────────────────────
+ bottomSheetTheme: BottomSheetThemeData(
+ backgroundColor: cs.surface, // bg.elevated dark
+ modalBackgroundColor: cs.surface,
+ dragHandleColor: AppColors.gray6,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
+ ),
+ ),
+
+ // ── ListTile (used by AppTile) ───────────────────────────────────────────
+ listTileTheme: ListTileThemeData(
+ textColor: cs.onSurface, // text.primary dark
+ iconColor: cs.onSurface,
+ selectedColor: cs.primary,
+ selectedTileColor: cs.primaryContainer, // bg.hover dark
+ ),
+
+ // ── TextButton (used by AppTextButton) ───────────────────────────────────
+ textButtonTheme: TextButtonThemeData(
+ style: TextButton.styleFrom(
+ foregroundColor: AppColors.blue2, // text.link dark
+ ),
+ ),
+
+ // ── Radio ───────────────────────────────────────────────────────────────
+ radioTheme: RadioThemeData(
+ fillColor: WidgetStatePropertyAll(cs.onSurface),
+ materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+ splashRadius: 10.0,
+ ),
+
+ // ── ElevatedButton (PrimaryButton) ───────────────────────────────────────
+ elevatedButtonTheme: ElevatedButtonThemeData(
+ style: ElevatedButton.styleFrom(
+ elevation: 0,
+ backgroundColor: cs.primary, // action.primary.primary-bg dark
+ enableFeedback: true,
+ foregroundColor: cs.onPrimary, // action.primary.primary-text
+ textStyle: AppTextStyles.primaryButtonTextStyle
+ .copyWith(fontSize: 18.0, color: cs.onPrimary),
+ overlayColor: AppColors.blue5, // action.primary.primary-bg-hover dark
+ minimumSize: const Size(double.infinity, 52),
+ tapTargetSize: MaterialTapTargetSize.padded,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(32.0),
+ side: BorderSide.none,
+ ),
+ ),
+ ),
+ );
}
}
diff --git a/lib/core/common/common.dart b/lib/core/common/common.dart
index 5046e4a002..b99a68f31f 100644
--- a/lib/core/common/common.dart
+++ b/lib/core/common/common.dart
@@ -4,9 +4,9 @@ import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
-
import 'package:lantern/core/common/app_build_info.dart';
import 'package:lantern/core/common/app_eum.dart';
import 'package:lantern/core/common/app_urls.dart';
@@ -32,11 +32,12 @@ export 'package:lantern/core/common/app_dialog.dart';
export 'package:lantern/core/common/app_dimens.dart';
export 'package:lantern/core/common/app_eum.dart';
export 'package:lantern/core/common/app_image_paths.dart';
+export 'package:lantern/core/common/app_semantic_colors.dart';
export 'package:lantern/core/common/app_text_field.dart';
export 'package:lantern/core/common/app_theme.dart';
-export 'package:lantern/core/common/date_formatters.dart';
// Utils
export 'package:lantern/core/common/app_urls.dart';
+export 'package:lantern/core/common/date_formatters.dart';
//Desktop export
export 'package:lantern/core/desktop/app_intent.dart';
export 'package:lantern/core/desktop/app_shortcuts.dart';
@@ -209,6 +210,17 @@ ServerLocationEntity initialServerLocation() {
);
}
+ThemeMode resolveThemeMode(String raw) {
+ switch (raw) {
+ case 'light':
+ return ThemeMode.light;
+ case 'dark':
+ return ThemeMode.dark;
+ default:
+ return ThemeMode.system;
+ }
+}
+
Future isStageEnvironment() async {
final dir = await AppStorageUtils.getAppDirectory();
final envFile = File('${dir.path}/.radiance_env');
diff --git a/lib/core/extensions/context.dart b/lib/core/extensions/context.dart
index 3a0512bc57..946b27a86e 100644
--- a/lib/core/extensions/context.dart
+++ b/lib/core/extensions/context.dart
@@ -1,6 +1,6 @@
// Extension for showing error SnackBars.
import 'package:flutter/material.dart';
-import 'package:lantern/core/common/app_colors.dart';
+import 'package:lantern/core/common/app_semantic_colors.dart';
import 'package:loader_overlay/loader_overlay.dart';
import '../common/app_dimens.dart' show defaultPadding;
@@ -15,13 +15,13 @@ extension SnackBarExtensions on BuildContext {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
- backgroundColor: AppColors.red7,
+ backgroundColor: bgSnackbarError,
showCloseIcon: closeButton,
- closeIconColor: AppColors.white,
+ closeIconColor: textInverse,
content: Text(
message,
style: textTheme!.copyWith(
- color: AppColors.white,
+ color: textInverse,
),
),
duration: Duration(seconds: 5),
@@ -38,13 +38,13 @@ extension SnackBarExtensions on BuildContext {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
- backgroundColor: AppColors.blue9,
+ backgroundColor: bgSnackbar,
showCloseIcon: closeButton,
- closeIconColor: AppColors.white,
+ closeIconColor: textInverse,
content: Text(
message,
style: textTheme!.copyWith(
- color: AppColors.white,
+ color: textInverse,
),
),
duration: Duration(seconds: 5),
diff --git a/lib/core/models/entity/app_setting_entity.dart b/lib/core/models/entity/app_setting_entity.dart
index 705d35b3ee..1283efbaab 100644
--- a/lib/core/models/entity/app_setting_entity.dart
+++ b/lib/core/models/entity/app_setting_entity.dart
@@ -20,6 +20,7 @@ class AppSetting {
String routingModeRaw;
String dataCapThreshold;
bool onboardingCompleted;
+ String themeMode;
String environment;
AppSetting({
@@ -38,6 +39,7 @@ class AppSetting {
this.routingModeRaw = 'full_tunnel',
this.dataCapThreshold = '',
this.onboardingCompleted = false,
+ this.themeMode = 'system',
this.environment = 'prod',
});
@@ -56,6 +58,7 @@ class AppSetting {
String? routingModeRaw,
String? dataCapThreshold,
bool? onboardingCompleted,
+ String? themeMode,
String? environment,
}) {
return AppSetting(
@@ -74,6 +77,7 @@ class AppSetting {
routingModeRaw: routingModeRaw ?? this.routingModeRaw,
dataCapThreshold: dataCapThreshold ?? this.dataCapThreshold,
onboardingCompleted: onboardingCompleted ?? this.onboardingCompleted,
+ themeMode: themeMode ?? this.themeMode,
environment: environment ?? this.environment,
);
}
diff --git a/lib/core/router/router.dart b/lib/core/router/router.dart
index 17cdd8b5ad..6bb8c84719 100644
--- a/lib/core/router/router.dart
+++ b/lib/core/router/router.dart
@@ -176,6 +176,10 @@ class AppRouter extends RootStackRouter {
path: '/developer-mode',
page: DeveloperMode.page,
),
+ AutoRoute(
+ path: '/appearance',
+ page: Appearance.page,
+ ),
AutoRoute(
path: '/smart-routing',
page: SmartRouting.page,
diff --git a/lib/core/router/router.gr.dart b/lib/core/router/router.gr.dart
index 65e33ae03e..f2e685b236 100644
--- a/lib/core/router/router.gr.dart
+++ b/lib/core/router/router.gr.dart
@@ -9,75 +9,76 @@
// coverage:ignore-file
// ignore_for_file: no_leading_underscores_for_library_prefixes
-import 'package:auto_route/auto_route.dart' as _i43;
-import 'package:collection/collection.dart' as _i47;
-import 'package:flutter/material.dart' as _i44;
-import 'package:lantern/core/common/common.dart' as _i45;
+import 'package:auto_route/auto_route.dart' as _i44;
+import 'package:collection/collection.dart' as _i48;
+import 'package:flutter/material.dart' as _i45;
+import 'package:lantern/core/common/common.dart' as _i46;
import 'package:lantern/core/widgets/app_webview.dart' as _i3;
import 'package:lantern/features/account/account.dart' as _i1;
-import 'package:lantern/features/account/delete_account.dart' as _i8;
+import 'package:lantern/features/account/delete_account.dart' as _i9;
import 'package:lantern/features/auth/add_email.dart' as _i2;
-import 'package:lantern/features/auth/choose_payment_method.dart' as _i5;
-import 'package:lantern/features/auth/confirm_email.dart' as _i6;
-import 'package:lantern/features/auth/create_password.dart' as _i7;
-import 'package:lantern/features/auth/device_limit_reached.dart' as _i10;
-import 'package:lantern/features/auth/lantern_pro_license.dart' as _i17;
-import 'package:lantern/features/auth/reset_password.dart' as _i31;
-import 'package:lantern/features/auth/reset_password_email.dart' as _i32;
-import 'package:lantern/features/auth/sign_in_email.dart' as _i35;
-import 'package:lantern/features/auth/sign_in_password.dart' as _i36;
-import 'package:lantern/features/developer/developer_mode.dart' as _i9;
-import 'package:lantern/features/home/home.dart' as _i13;
-import 'package:lantern/features/language/language.dart' as _i16;
-import 'package:lantern/features/logs/logs.dart' as _i18;
+import 'package:lantern/features/auth/choose_payment_method.dart' as _i6;
+import 'package:lantern/features/auth/confirm_email.dart' as _i7;
+import 'package:lantern/features/auth/create_password.dart' as _i8;
+import 'package:lantern/features/auth/device_limit_reached.dart' as _i11;
+import 'package:lantern/features/auth/lantern_pro_license.dart' as _i18;
+import 'package:lantern/features/auth/reset_password.dart' as _i32;
+import 'package:lantern/features/auth/reset_password_email.dart' as _i33;
+import 'package:lantern/features/auth/sign_in_email.dart' as _i36;
+import 'package:lantern/features/auth/sign_in_password.dart' as _i37;
+import 'package:lantern/features/developer/developer_mode.dart' as _i10;
+import 'package:lantern/features/home/home.dart' as _i14;
+import 'package:lantern/features/language/language.dart' as _i17;
+import 'package:lantern/features/logs/logs.dart' as _i19;
import 'package:lantern/features/macos_extension/macos_extension_dialog.dart'
- as _i19;
-import 'package:lantern/features/onboarding/onboarding.dart' as _i22;
-import 'package:lantern/features/plans/plans.dart' as _i23;
+ as _i20;
+import 'package:lantern/features/onboarding/onboarding.dart' as _i23;
+import 'package:lantern/features/plans/plans.dart' as _i24;
import 'package:lantern/features/private_server/join_private_server.dart'
- as _i15;
+ as _i16;
import 'package:lantern/features/private_server/manage_private_server.dart'
- as _i20;
-import 'package:lantern/features/private_server/manually_server_setup.dart'
as _i21;
+import 'package:lantern/features/private_server/manually_server_setup.dart'
+ as _i22;
import 'package:lantern/features/private_server/private_server_add_billing.dart'
- as _i24;
-import 'package:lantern/features/private_server/private_server_deploy.dart'
as _i25;
-import 'package:lantern/features/private_server/private_server_locations.dart'
+import 'package:lantern/features/private_server/private_server_deploy.dart'
as _i26;
-import 'package:lantern/features/private_server/private_server_setup.dart'
+import 'package:lantern/features/private_server/private_server_locations.dart'
as _i27;
-import 'package:lantern/features/private_server/private_sever_details.dart'
+import 'package:lantern/features/private_server/private_server_setup.dart'
as _i28;
-import 'package:lantern/features/qr_scanner/qr_code_scanner.dart' as _i29;
-import 'package:lantern/features/report_Issue/report_issue.dart' as _i30;
-import 'package:lantern/features/setting/download_links.dart' as _i11;
-import 'package:lantern/features/setting/follow_us.dart' as _i12;
-import 'package:lantern/features/setting/invite_friends.dart' as _i14;
-import 'package:lantern/features/setting/setting.dart' as _i34;
-import 'package:lantern/features/setting/smart_routing.dart' as _i37;
-import 'package:lantern/features/setting/vpn_setting.dart' as _i41;
+import 'package:lantern/features/private_server/private_sever_details.dart'
+ as _i29;
+import 'package:lantern/features/qr_scanner/qr_code_scanner.dart' as _i30;
+import 'package:lantern/features/report_Issue/report_issue.dart' as _i31;
+import 'package:lantern/features/setting/appearance.dart' as _i4;
+import 'package:lantern/features/setting/download_links.dart' as _i12;
+import 'package:lantern/features/setting/follow_us.dart' as _i13;
+import 'package:lantern/features/setting/invite_friends.dart' as _i15;
+import 'package:lantern/features/setting/setting.dart' as _i35;
+import 'package:lantern/features/setting/smart_routing.dart' as _i38;
+import 'package:lantern/features/setting/vpn_setting.dart' as _i42;
import 'package:lantern/features/split_tunneling/apps_split_tunneling.dart'
- as _i4;
-import 'package:lantern/features/split_tunneling/split_tunneling.dart' as _i38;
+ as _i5;
+import 'package:lantern/features/split_tunneling/split_tunneling.dart' as _i39;
import 'package:lantern/features/split_tunneling/split_tunneling_info.dart'
- as _i39;
+ as _i40;
import 'package:lantern/features/split_tunneling/website_split_tunneling.dart'
- as _i42;
-import 'package:lantern/features/support/support.dart' as _i40;
-import 'package:lantern/features/vpn/server_selection.dart' as _i33;
-import 'package:lantern/lantern/protos/protos/auth.pb.dart' as _i46;
+ as _i43;
+import 'package:lantern/features/support/support.dart' as _i41;
+import 'package:lantern/features/vpn/server_selection.dart' as _i34;
+import 'package:lantern/lantern/protos/protos/auth.pb.dart' as _i47;
/// generated route for
/// [_i1.Account]
-class Account extends _i43.PageRouteInfo {
- const Account({List<_i43.PageRouteInfo>? children})
+class Account extends _i44.PageRouteInfo {
+ const Account({List<_i44.PageRouteInfo>? children})
: super(Account.name, initialChildren: children);
static const String name = 'Account';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
return const _i1.Account();
@@ -87,12 +88,12 @@ class Account extends _i43.PageRouteInfo {
/// generated route for
/// [_i2.AddEmail]
-class AddEmail extends _i43.PageRouteInfo {
+class AddEmail extends _i44.PageRouteInfo {
AddEmail({
- _i44.Key? key,
- _i45.AuthFlow authFlow = _i45.AuthFlow.signUp,
+ _i45.Key? key,
+ _i46.AuthFlow authFlow = _i46.AuthFlow.signUp,
String? password,
- List<_i43.PageRouteInfo>? children,
+ List<_i44.PageRouteInfo>? children,
}) : super(
AddEmail.name,
args: AddEmailArgs(key: key, authFlow: authFlow, password: password),
@@ -101,7 +102,7 @@ class AddEmail extends _i43.PageRouteInfo {
static const String name = 'AddEmail';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs(
@@ -119,13 +120,13 @@ class AddEmail extends _i43.PageRouteInfo {
class AddEmailArgs {
const AddEmailArgs({
this.key,
- this.authFlow = _i45.AuthFlow.signUp,
+ this.authFlow = _i46.AuthFlow.signUp,
this.password,
});
- final _i44.Key? key;
+ final _i45.Key? key;
- final _i45.AuthFlow authFlow;
+ final _i46.AuthFlow authFlow;
final String? password;
@@ -149,12 +150,12 @@ class AddEmailArgs {
/// generated route for
/// [_i3.AppWebView]
-class AppWebview extends _i43.PageRouteInfo {
+class AppWebview extends _i44.PageRouteInfo {
AppWebview({
- _i44.Key? key,
+ _i45.Key? key,
required String title,
required String url,
- List<_i43.PageRouteInfo>? children,
+ List<_i44.PageRouteInfo>? children,
}) : super(
AppWebview.name,
args: AppWebviewArgs(key: key, title: title, url: url),
@@ -163,7 +164,7 @@ class AppWebview extends _i43.PageRouteInfo {
static const String name = 'AppWebview';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs();
@@ -175,7 +176,7 @@ class AppWebview extends _i43.PageRouteInfo {
class AppWebviewArgs {
const AppWebviewArgs({this.key, required this.title, required this.url});
- final _i44.Key? key;
+ final _i45.Key? key;
final String title;
@@ -198,30 +199,46 @@ class AppWebviewArgs {
}
/// generated route for
-/// [_i4.AppsSplitTunneling]
-class AppsSplitTunneling extends _i43.PageRouteInfo {
- const AppsSplitTunneling({List<_i43.PageRouteInfo>? children})
+/// [_i4.Appearance]
+class Appearance extends _i44.PageRouteInfo {
+ const Appearance({List<_i44.PageRouteInfo>? children})
+ : super(Appearance.name, initialChildren: children);
+
+ static const String name = 'Appearance';
+
+ static _i44.PageInfo page = _i44.PageInfo(
+ name,
+ builder: (data) {
+ return const _i4.Appearance();
+ },
+ );
+}
+
+/// generated route for
+/// [_i5.AppsSplitTunneling]
+class AppsSplitTunneling extends _i44.PageRouteInfo {
+ const AppsSplitTunneling({List<_i44.PageRouteInfo>? children})
: super(AppsSplitTunneling.name, initialChildren: children);
static const String name = 'AppsSplitTunneling';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i4.AppsSplitTunneling();
+ return const _i5.AppsSplitTunneling();
},
);
}
/// generated route for
-/// [_i5.ChoosePaymentMethod]
-class ChoosePaymentMethod extends _i43.PageRouteInfo {
+/// [_i6.ChoosePaymentMethod]
+class ChoosePaymentMethod extends _i44.PageRouteInfo {
ChoosePaymentMethod({
- _i44.Key? key,
+ _i45.Key? key,
required String email,
String? code,
- required _i45.AuthFlow authFlow,
- List<_i43.PageRouteInfo>? children,
+ required _i46.AuthFlow authFlow,
+ List<_i44.PageRouteInfo>? children,
}) : super(
ChoosePaymentMethod.name,
args: ChoosePaymentMethodArgs(
@@ -235,11 +252,11 @@ class ChoosePaymentMethod extends _i43.PageRouteInfo {
static const String name = 'ChoosePaymentMethod';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs();
- return _i5.ChoosePaymentMethod(
+ return _i6.ChoosePaymentMethod(
key: args.key,
email: args.email,
code: args.code,
@@ -257,13 +274,13 @@ class ChoosePaymentMethodArgs {
required this.authFlow,
});
- final _i44.Key? key;
+ final _i45.Key? key;
final String email;
final String? code;
- final _i45.AuthFlow authFlow;
+ final _i46.AuthFlow authFlow;
@override
String toString() {
@@ -286,14 +303,14 @@ class ChoosePaymentMethodArgs {
}
/// generated route for
-/// [_i6.ConfirmEmail]
-class ConfirmEmail extends _i43.PageRouteInfo {
+/// [_i7.ConfirmEmail]
+class ConfirmEmail extends _i44.PageRouteInfo {
ConfirmEmail({
- _i44.Key? key,
+ _i45.Key? key,
required String email,
String? password,
- _i45.AuthFlow authFlow = _i45.AuthFlow.signUp,
- List<_i43.PageRouteInfo>? children,
+ _i46.AuthFlow authFlow = _i46.AuthFlow.signUp,
+ List<_i44.PageRouteInfo>? children,
}) : super(
ConfirmEmail.name,
args: ConfirmEmailArgs(
@@ -307,11 +324,11 @@ class ConfirmEmail extends _i43.PageRouteInfo {
static const String name = 'ConfirmEmail';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs();
- return _i6.ConfirmEmail(
+ return _i7.ConfirmEmail(
key: args.key,
email: args.email,
password: args.password,
@@ -326,16 +343,16 @@ class ConfirmEmailArgs {
this.key,
required this.email,
this.password,
- this.authFlow = _i45.AuthFlow.signUp,
+ this.authFlow = _i46.AuthFlow.signUp,
});
- final _i44.Key? key;
+ final _i45.Key? key;
final String email;
final String? password;
- final _i45.AuthFlow authFlow;
+ final _i46.AuthFlow authFlow;
@override
String toString() {
@@ -358,14 +375,14 @@ class ConfirmEmailArgs {
}
/// generated route for
-/// [_i7.CreatePassword]
-class CreatePassword extends _i43.PageRouteInfo {
+/// [_i8.CreatePassword]
+class CreatePassword extends _i44.PageRouteInfo {
CreatePassword({
- _i44.Key? key,
+ _i45.Key? key,
required String email,
- required _i45.AuthFlow authFlow,
+ required _i46.AuthFlow authFlow,
required String code,
- List<_i43.PageRouteInfo>? children,
+ List<_i44.PageRouteInfo>? children,
}) : super(
CreatePassword.name,
args: CreatePasswordArgs(
@@ -379,11 +396,11 @@ class CreatePassword extends _i43.PageRouteInfo {
static const String name = 'CreatePassword';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs();
- return _i7.CreatePassword(
+ return _i8.CreatePassword(
key: args.key,
email: args.email,
authFlow: args.authFlow,
@@ -401,11 +418,11 @@ class CreatePasswordArgs {
required this.code,
});
- final _i44.Key? key;
+ final _i45.Key? key;
final String email;
- final _i45.AuthFlow authFlow;
+ final _i46.AuthFlow authFlow;
final String code;
@@ -430,44 +447,44 @@ class CreatePasswordArgs {
}
/// generated route for
-/// [_i8.DeleteAccount]
-class DeleteAccount extends _i43.PageRouteInfo {
- const DeleteAccount({List<_i43.PageRouteInfo>? children})
+/// [_i9.DeleteAccount]
+class DeleteAccount extends _i44.PageRouteInfo {
+ const DeleteAccount({List<_i44.PageRouteInfo>? children})
: super(DeleteAccount.name, initialChildren: children);
static const String name = 'DeleteAccount';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i8.DeleteAccount();
+ return const _i9.DeleteAccount();
},
);
}
/// generated route for
-/// [_i9.DeveloperMode]
-class DeveloperMode extends _i43.PageRouteInfo {
- const DeveloperMode({List<_i43.PageRouteInfo>? children})
+/// [_i10.DeveloperMode]
+class DeveloperMode extends _i44.PageRouteInfo {
+ const DeveloperMode({List<_i44.PageRouteInfo>? children})
: super(DeveloperMode.name, initialChildren: children);
static const String name = 'DeveloperMode';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i9.DeveloperMode();
+ return const _i10.DeveloperMode();
},
);
}
/// generated route for
-/// [_i10.DeviceLimitReached]
-class DeviceLimitReached extends _i43.PageRouteInfo {
+/// [_i11.DeviceLimitReached]
+class DeviceLimitReached extends _i44.PageRouteInfo {
DeviceLimitReached({
- _i44.Key? key,
- required List<_i46.UserResponse_Device> devices,
- List<_i43.PageRouteInfo>? children,
+ _i45.Key? key,
+ required List<_i47.UserResponse_Device> devices,
+ List<_i44.PageRouteInfo>? children,
}) : super(
DeviceLimitReached.name,
args: DeviceLimitReachedArgs(key: key, devices: devices),
@@ -476,11 +493,11 @@ class DeviceLimitReached extends _i43.PageRouteInfo {
static const String name = 'DeviceLimitReached';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs();
- return _i10.DeviceLimitReached(key: args.key, devices: args.devices);
+ return _i11.DeviceLimitReached(key: args.key, devices: args.devices);
},
);
}
@@ -488,9 +505,9 @@ class DeviceLimitReached extends _i43.PageRouteInfo {
class DeviceLimitReachedArgs {
const DeviceLimitReachedArgs({this.key, required this.devices});
- final _i44.Key? key;
+ final _i45.Key? key;
- final List<_i46.UserResponse_Device> devices;
+ final List<_i47.UserResponse_Device> devices;
@override
String toString() {
@@ -502,7 +519,7 @@ class DeviceLimitReachedArgs {
if (identical(this, other)) return true;
if (other is! DeviceLimitReachedArgs) return false;
return key == other.key &&
- const _i47.ListEquality<_i46.UserResponse_Device>().equals(
+ const _i48.ListEquality<_i47.UserResponse_Device>().equals(
devices,
other.devices,
);
@@ -511,80 +528,80 @@ class DeviceLimitReachedArgs {
@override
int get hashCode =>
key.hashCode ^
- const _i47.ListEquality<_i46.UserResponse_Device>().hash(devices);
+ const _i48.ListEquality<_i47.UserResponse_Device>().hash(devices);
}
/// generated route for
-/// [_i11.DownloadLinks]
-class DownloadLinks extends _i43.PageRouteInfo {
- const DownloadLinks({List<_i43.PageRouteInfo>? children})
+/// [_i12.DownloadLinks]
+class DownloadLinks extends _i44.PageRouteInfo {
+ const DownloadLinks({List<_i44.PageRouteInfo>? children})
: super(DownloadLinks.name, initialChildren: children);
static const String name = 'DownloadLinks';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i11.DownloadLinks();
+ return const _i12.DownloadLinks();
},
);
}
/// generated route for
-/// [_i12.FollowUs]
-class FollowUs extends _i43.PageRouteInfo {
- const FollowUs({List<_i43.PageRouteInfo>? children})
+/// [_i13.FollowUs]
+class FollowUs extends _i44.PageRouteInfo {
+ const FollowUs({List<_i44.PageRouteInfo>? children})
: super(FollowUs.name, initialChildren: children);
static const String name = 'FollowUs';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i12.FollowUs();
+ return const _i13.FollowUs();
},
);
}
/// generated route for
-/// [_i13.Home]
-class Home extends _i43.PageRouteInfo {
- const Home({List<_i43.PageRouteInfo>? children})
+/// [_i14.Home]
+class Home extends _i44.PageRouteInfo {
+ const Home({List<_i44.PageRouteInfo>? children})
: super(Home.name, initialChildren: children);
static const String name = 'Home';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i13.Home();
+ return const _i14.Home();
},
);
}
/// generated route for
-/// [_i14.InviteFriends]
-class InviteFriends extends _i43.PageRouteInfo {
- const InviteFriends({List<_i43.PageRouteInfo>? children})
+/// [_i15.InviteFriends]
+class InviteFriends extends _i44.PageRouteInfo {
+ const InviteFriends({List<_i44.PageRouteInfo>? children})
: super(InviteFriends.name, initialChildren: children);
static const String name = 'InviteFriends';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i14.InviteFriends();
+ return const _i15.InviteFriends();
},
);
}
/// generated route for
-/// [_i15.JoinPrivateServer]
-class JoinPrivateServer extends _i43.PageRouteInfo {
+/// [_i16.JoinPrivateServer]
+class JoinPrivateServer extends _i44.PageRouteInfo {
JoinPrivateServer({
- _i44.Key? key,
+ _i45.Key? key,
Map? deepLinkData,
- List<_i43.PageRouteInfo>? children,
+ List<_i44.PageRouteInfo>? children,
}) : super(
JoinPrivateServer.name,
args: JoinPrivateServerArgs(key: key, deepLinkData: deepLinkData),
@@ -593,13 +610,13 @@ class JoinPrivateServer extends _i43.PageRouteInfo {
static const String name = 'JoinPrivateServer';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs(
orElse: () => const JoinPrivateServerArgs(),
);
- return _i15.JoinPrivateServer(
+ return _i16.JoinPrivateServer(
key: args.key,
deepLinkData: args.deepLinkData,
);
@@ -610,7 +627,7 @@ class JoinPrivateServer extends _i43.PageRouteInfo {
class JoinPrivateServerArgs {
const JoinPrivateServerArgs({this.key, this.deepLinkData});
- final _i44.Key? key;
+ final _i45.Key? key;
final Map? deepLinkData;
@@ -624,7 +641,7 @@ class JoinPrivateServerArgs {
if (identical(this, other)) return true;
if (other is! JoinPrivateServerArgs) return false;
return key == other.key &&
- const _i47.MapEquality().equals(
+ const _i48.MapEquality().equals(
deepLinkData,
other.deepLinkData,
);
@@ -633,33 +650,33 @@ class JoinPrivateServerArgs {
@override
int get hashCode =>
key.hashCode ^
- const _i47.MapEquality().hash(deepLinkData);
+ const _i48.MapEquality().hash(deepLinkData);
}
/// generated route for
-/// [_i16.Language]
-class Language extends _i43.PageRouteInfo {
- const Language({List<_i43.PageRouteInfo>? children})
+/// [_i17.Language]
+class Language extends _i44.PageRouteInfo {
+ const Language({List<_i44.PageRouteInfo>? children})
: super(Language.name, initialChildren: children);
static const String name = 'Language';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i16.Language();
+ return const _i17.Language();
},
);
}
/// generated route for
-/// [_i17.LanternProLicense]
-class LanternProLicense extends _i43.PageRouteInfo {
+/// [_i18.LanternProLicense]
+class LanternProLicense extends _i44.PageRouteInfo {
LanternProLicense({
- _i44.Key? key,
+ _i45.Key? key,
required String email,
required String code,
- List<_i43.PageRouteInfo>? children,
+ List<_i44.PageRouteInfo>? children,
}) : super(
LanternProLicense.name,
args: LanternProLicenseArgs(key: key, email: email, code: code),
@@ -668,11 +685,11 @@ class LanternProLicense extends _i43.PageRouteInfo {
static const String name = 'LanternProLicense';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs();
- return _i17.LanternProLicense(
+ return _i18.LanternProLicense(
key: args.key,
email: args.email,
code: args.code,
@@ -688,7 +705,7 @@ class LanternProLicenseArgs {
required this.code,
});
- final _i44.Key? key;
+ final _i45.Key? key;
final String email;
@@ -711,124 +728,124 @@ class LanternProLicenseArgs {
}
/// generated route for
-/// [_i18.Logs]
-class Logs extends _i43.PageRouteInfo {
- const Logs({List<_i43.PageRouteInfo>? children})
+/// [_i19.Logs]
+class Logs extends _i44.PageRouteInfo {
+ const Logs({List<_i44.PageRouteInfo>? children})
: super(Logs.name, initialChildren: children);
static const String name = 'Logs';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i18.Logs();
+ return const _i19.Logs();
},
);
}
/// generated route for
-/// [_i19.MacOSExtensionDialog]
-class MacOSExtensionDialog extends _i43.PageRouteInfo {
- const MacOSExtensionDialog({List<_i43.PageRouteInfo>? children})
+/// [_i20.MacOSExtensionDialog]
+class MacOSExtensionDialog extends _i44.PageRouteInfo {
+ const MacOSExtensionDialog({List<_i44.PageRouteInfo>? children})
: super(MacOSExtensionDialog.name, initialChildren: children);
static const String name = 'MacOSExtensionDialog';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i19.MacOSExtensionDialog();
+ return const _i20.MacOSExtensionDialog();
},
);
}
/// generated route for
-/// [_i20.ManagePrivateServer]
-class ManagePrivateServer extends _i43.PageRouteInfo {
- const ManagePrivateServer({List<_i43.PageRouteInfo>? children})
+/// [_i21.ManagePrivateServer]
+class ManagePrivateServer extends _i44.PageRouteInfo {
+ const ManagePrivateServer({List<_i44.PageRouteInfo>? children})
: super(ManagePrivateServer.name, initialChildren: children);
static const String name = 'ManagePrivateServer';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i20.ManagePrivateServer();
+ return const _i21.ManagePrivateServer();
},
);
}
/// generated route for
-/// [_i21.ManuallyServerSetup]
-class ManuallyServerSetup extends _i43.PageRouteInfo {
- const ManuallyServerSetup({List<_i43.PageRouteInfo>? children})
+/// [_i22.ManuallyServerSetup]
+class ManuallyServerSetup extends _i44.PageRouteInfo {
+ const ManuallyServerSetup({List<_i44.PageRouteInfo>? children})
: super(ManuallyServerSetup.name, initialChildren: children);
static const String name = 'ManuallyServerSetup';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i21.ManuallyServerSetup();
+ return const _i22.ManuallyServerSetup();
},
);
}
/// generated route for
-/// [_i22.Onboarding]
-class Onboarding extends _i43.PageRouteInfo {
- const Onboarding({List<_i43.PageRouteInfo>? children})
+/// [_i23.Onboarding]
+class Onboarding extends _i44.PageRouteInfo {
+ const Onboarding({List<_i44.PageRouteInfo>? children})
: super(Onboarding.name, initialChildren: children);
static const String name = 'Onboarding';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i22.Onboarding();
+ return const _i23.Onboarding();
},
);
}
/// generated route for
-/// [_i23.Plans]
-class Plans extends _i43.PageRouteInfo {
- const Plans({List<_i43.PageRouteInfo>? children})
+/// [_i24.Plans]
+class Plans extends _i44.PageRouteInfo {
+ const Plans({List<_i44.PageRouteInfo>? children})
: super(Plans.name, initialChildren: children);
static const String name = 'Plans';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i23.Plans();
+ return const _i24.Plans();
},
);
}
/// generated route for
-/// [_i24.PrivateServerAddBilling]
-class PrivateServerAddBilling extends _i43.PageRouteInfo {
- const PrivateServerAddBilling({List<_i43.PageRouteInfo>? children})
+/// [_i25.PrivateServerAddBilling]
+class PrivateServerAddBilling extends _i44.PageRouteInfo {
+ const PrivateServerAddBilling({List<_i44.PageRouteInfo>? children})
: super(PrivateServerAddBilling.name, initialChildren: children);
static const String name = 'PrivateServerAddBilling';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i24.PrivateServerAddBilling();
+ return const _i25.PrivateServerAddBilling();
},
);
}
/// generated route for
-/// [_i25.PrivateServerDeploy]
-class PrivateServerDeploy extends _i43.PageRouteInfo {
+/// [_i26.PrivateServerDeploy]
+class PrivateServerDeploy extends _i44.PageRouteInfo {
PrivateServerDeploy({
- _i44.Key? key,
+ _i45.Key? key,
required String serverName,
- List<_i43.PageRouteInfo>? children,
+ List<_i44.PageRouteInfo>? children,
}) : super(
PrivateServerDeploy.name,
args: PrivateServerDeployArgs(key: key, serverName: serverName),
@@ -837,11 +854,11 @@ class PrivateServerDeploy extends _i43.PageRouteInfo {
static const String name = 'PrivateServerDeploy';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs();
- return _i25.PrivateServerDeploy(
+ return _i26.PrivateServerDeploy(
key: args.key,
serverName: args.serverName,
);
@@ -852,7 +869,7 @@ class PrivateServerDeploy extends _i43.PageRouteInfo {
class PrivateServerDeployArgs {
const PrivateServerDeployArgs({this.key, required this.serverName});
- final _i44.Key? key;
+ final _i45.Key? key;
final String serverName;
@@ -873,16 +890,16 @@ class PrivateServerDeployArgs {
}
/// generated route for
-/// [_i26.PrivateServerLocation]
+/// [_i27.PrivateServerLocation]
class PrivateServerLocation
- extends _i43.PageRouteInfo {
+ extends _i44.PageRouteInfo {
PrivateServerLocation({
- _i44.Key? key,
+ _i45.Key? key,
required List location,
required String? selectedLocation,
required dynamic Function(String) onLocationSelected,
- required _i45.CloudProvider provider,
- List<_i43.PageRouteInfo>? children,
+ required _i46.CloudProvider provider,
+ List<_i44.PageRouteInfo>? children,
}) : super(
PrivateServerLocation.name,
args: PrivateServerLocationArgs(
@@ -897,11 +914,11 @@ class PrivateServerLocation
static const String name = 'PrivateServerLocation';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs();
- return _i26.PrivateServerLocation(
+ return _i27.PrivateServerLocation(
key: args.key,
location: args.location,
selectedLocation: args.selectedLocation,
@@ -921,7 +938,7 @@ class PrivateServerLocationArgs {
required this.provider,
});
- final _i44.Key? key;
+ final _i45.Key? key;
final List location;
@@ -929,7 +946,7 @@ class PrivateServerLocationArgs {
final dynamic Function(String) onLocationSelected;
- final _i45.CloudProvider provider;
+ final _i46.CloudProvider provider;
@override
String toString() {
@@ -941,7 +958,7 @@ class PrivateServerLocationArgs {
if (identical(this, other)) return true;
if (other is! PrivateServerLocationArgs) return false;
return key == other.key &&
- const _i47.ListEquality().equals(location, other.location) &&
+ const _i48.ListEquality().equals(location, other.location) &&
selectedLocation == other.selectedLocation &&
provider == other.provider;
}
@@ -949,37 +966,37 @@ class PrivateServerLocationArgs {
@override
int get hashCode =>
key.hashCode ^
- const _i47.ListEquality().hash(location) ^
+ const _i48.ListEquality().hash(location) ^
selectedLocation.hashCode ^
provider.hashCode;
}
/// generated route for
-/// [_i27.PrivateServerSetup]
-class PrivateServerSetup extends _i43.PageRouteInfo {
- const PrivateServerSetup({List<_i43.PageRouteInfo>? children})
+/// [_i28.PrivateServerSetup]
+class PrivateServerSetup extends _i44.PageRouteInfo {
+ const PrivateServerSetup({List<_i44.PageRouteInfo>? children})
: super(PrivateServerSetup.name, initialChildren: children);
static const String name = 'PrivateServerSetup';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i27.PrivateServerSetup();
+ return const _i28.PrivateServerSetup();
},
);
}
/// generated route for
-/// [_i28.PrivateSeverDetails]
+/// [_i29.PrivateSeverDetails]
class PrivateServerDetails
- extends _i43.PageRouteInfo {
+ extends _i44.PageRouteInfo {
PrivateServerDetails({
- _i44.Key? key,
+ _i45.Key? key,
required List accounts,
- required _i45.CloudProvider provider,
+ required _i46.CloudProvider provider,
bool isPreFilled = false,
- List<_i43.PageRouteInfo>? children,
+ List<_i44.PageRouteInfo>? children,
}) : super(
PrivateServerDetails.name,
args: PrivateServerDetailsArgs(
@@ -993,11 +1010,11 @@ class PrivateServerDetails
static const String name = 'PrivateServerDetails';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs();
- return _i28.PrivateSeverDetails(
+ return _i29.PrivateSeverDetails(
key: args.key,
accounts: args.accounts,
provider: args.provider,
@@ -1015,11 +1032,11 @@ class PrivateServerDetailsArgs {
this.isPreFilled = false,
});
- final _i44.Key? key;
+ final _i45.Key? key;
final List accounts;
- final _i45.CloudProvider provider;
+ final _i46.CloudProvider provider;
final bool isPreFilled;
@@ -1033,7 +1050,7 @@ class PrivateServerDetailsArgs {
if (identical(this, other)) return true;
if (other is! PrivateServerDetailsArgs) return false;
return key == other.key &&
- const _i47.ListEquality().equals(accounts, other.accounts) &&
+ const _i48.ListEquality().equals(accounts, other.accounts) &&
provider == other.provider &&
isPreFilled == other.isPreFilled;
}
@@ -1041,35 +1058,35 @@ class PrivateServerDetailsArgs {
@override
int get hashCode =>
key.hashCode ^
- const _i47.ListEquality().hash(accounts) ^
+ const _i48.ListEquality().hash(accounts) ^
provider.hashCode ^
isPreFilled.hashCode;
}
/// generated route for
-/// [_i29.QrCodeScanner]
-class QrCodeScanner extends _i43.PageRouteInfo {
- const QrCodeScanner({List<_i43.PageRouteInfo>? children})
+/// [_i30.QrCodeScanner]
+class QrCodeScanner extends _i44.PageRouteInfo {
+ const QrCodeScanner({List<_i44.PageRouteInfo>? children})
: super(QrCodeScanner.name, initialChildren: children);
static const String name = 'QrCodeScanner';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i29.QrCodeScanner();
+ return const _i30.QrCodeScanner();
},
);
}
/// generated route for
-/// [_i30.ReportIssue]
-class ReportIssue extends _i43.PageRouteInfo {
+/// [_i31.ReportIssue]
+class ReportIssue extends _i44.PageRouteInfo {
ReportIssue({
- _i44.Key? key,
+ _i45.Key? key,
String? description,
String? type,
- List<_i43.PageRouteInfo>? children,
+ List<_i44.PageRouteInfo>? children,
}) : super(
ReportIssue.name,
args: ReportIssueArgs(key: key, description: description, type: type),
@@ -1078,13 +1095,13 @@ class ReportIssue extends _i43.PageRouteInfo {
static const String name = 'ReportIssue';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs(
orElse: () => const ReportIssueArgs(),
);
- return _i30.ReportIssue(
+ return _i31.ReportIssue(
key: args.key,
description: args.description,
type: args.type,
@@ -1096,7 +1113,7 @@ class ReportIssue extends _i43.PageRouteInfo {
class ReportIssueArgs {
const ReportIssueArgs({this.key, this.description, this.type});
- final _i44.Key? key;
+ final _i45.Key? key;
final String? description;
@@ -1121,13 +1138,13 @@ class ReportIssueArgs {
}
/// generated route for
-/// [_i31.ResetPassword]
-class ResetPassword extends _i43.PageRouteInfo {
+/// [_i32.ResetPassword]
+class ResetPassword extends _i44.PageRouteInfo {
ResetPassword({
- _i44.Key? key,
+ _i45.Key? key,
required String email,
required String code,
- List<_i43.PageRouteInfo>? children,
+ List<_i44.PageRouteInfo>? children,
}) : super(
ResetPassword.name,
args: ResetPasswordArgs(key: key, email: email, code: code),
@@ -1136,11 +1153,11 @@ class ResetPassword extends _i43.PageRouteInfo {
static const String name = 'ResetPassword';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs();
- return _i31.ResetPassword(
+ return _i32.ResetPassword(
key: args.key,
email: args.email,
code: args.code,
@@ -1152,7 +1169,7 @@ class ResetPassword extends _i43.PageRouteInfo {
class ResetPasswordArgs {
const ResetPasswordArgs({this.key, required this.email, required this.code});
- final _i44.Key? key;
+ final _i45.Key? key;
final String email;
@@ -1175,12 +1192,12 @@ class ResetPasswordArgs {
}
/// generated route for
-/// [_i32.ResetPasswordEmail]
-class ResetPasswordEmail extends _i43.PageRouteInfo {
+/// [_i33.ResetPasswordEmail]
+class ResetPasswordEmail extends _i44.PageRouteInfo {
ResetPasswordEmail({
- _i44.Key? key,
+ _i45.Key? key,
String? email,
- List<_i43.PageRouteInfo>? children,
+ List<_i44.PageRouteInfo>? children,
}) : super(
ResetPasswordEmail.name,
args: ResetPasswordEmailArgs(key: key, email: email),
@@ -1189,13 +1206,13 @@ class ResetPasswordEmail extends _i43.PageRouteInfo {
static const String name = 'ResetPasswordEmail';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs(
orElse: () => const ResetPasswordEmailArgs(),
);
- return _i32.ResetPasswordEmail(key: args.key, email: args.email);
+ return _i33.ResetPasswordEmail(key: args.key, email: args.email);
},
);
}
@@ -1203,7 +1220,7 @@ class ResetPasswordEmail extends _i43.PageRouteInfo {
class ResetPasswordEmailArgs {
const ResetPasswordEmailArgs({this.key, this.email});
- final _i44.Key? key;
+ final _i45.Key? key;
final String? email;
@@ -1224,61 +1241,61 @@ class ResetPasswordEmailArgs {
}
/// generated route for
-/// [_i33.ServerSelection]
-class ServerSelection extends _i43.PageRouteInfo {
- const ServerSelection({List<_i43.PageRouteInfo>? children})
+/// [_i34.ServerSelection]
+class ServerSelection extends _i44.PageRouteInfo {
+ const ServerSelection({List<_i44.PageRouteInfo>? children})
: super(ServerSelection.name, initialChildren: children);
static const String name = 'ServerSelection';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i33.ServerSelection();
+ return const _i34.ServerSelection();
},
);
}
/// generated route for
-/// [_i34.Setting]
-class Setting extends _i43.PageRouteInfo {
- const Setting({List<_i43.PageRouteInfo>? children})
+/// [_i35.Setting]
+class Setting extends _i44.PageRouteInfo {
+ const Setting({List<_i44.PageRouteInfo>? children})
: super(Setting.name, initialChildren: children);
static const String name = 'Setting';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i34.Setting();
+ return const _i35.Setting();
},
);
}
/// generated route for
-/// [_i35.SignInEmail]
-class SignInEmail extends _i43.PageRouteInfo {
- const SignInEmail({List<_i43.PageRouteInfo>? children})
+/// [_i36.SignInEmail]
+class SignInEmail extends _i44.PageRouteInfo {
+ const SignInEmail({List<_i44.PageRouteInfo>? children})
: super(SignInEmail.name, initialChildren: children);
static const String name = 'SignInEmail';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i35.SignInEmail();
+ return const _i36.SignInEmail();
},
);
}
/// generated route for
-/// [_i36.SignInPassword]
-class SignInPassword extends _i43.PageRouteInfo {
+/// [_i37.SignInPassword]
+class SignInPassword extends _i44.PageRouteInfo {
SignInPassword({
- _i44.Key? key,
+ _i45.Key? key,
required String email,
bool fromChangeEmail = false,
- List<_i43.PageRouteInfo>? children,
+ List<_i44.PageRouteInfo>? children,
}) : super(
SignInPassword.name,
args: SignInPasswordArgs(
@@ -1291,11 +1308,11 @@ class SignInPassword extends _i43.PageRouteInfo {
static const String name = 'SignInPassword';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
final args = data.argsAs();
- return _i36.SignInPassword(
+ return _i37.SignInPassword(
key: args.key,
email: args.email,
fromChangeEmail: args.fromChangeEmail,
@@ -1311,7 +1328,7 @@ class SignInPasswordArgs {
this.fromChangeEmail = false,
});
- final _i44.Key? key;
+ final _i45.Key? key;
final String email;
@@ -1336,97 +1353,97 @@ class SignInPasswordArgs {
}
/// generated route for
-/// [_i37.SmartRouting]
-class SmartRouting extends _i43.PageRouteInfo {
- const SmartRouting({List<_i43.PageRouteInfo>? children})
+/// [_i38.SmartRouting]
+class SmartRouting extends _i44.PageRouteInfo {
+ const SmartRouting({List<_i44.PageRouteInfo>? children})
: super(SmartRouting.name, initialChildren: children);
static const String name = 'SmartRouting';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i37.SmartRouting();
+ return const _i38.SmartRouting();
},
);
}
/// generated route for
-/// [_i38.SplitTunneling]
-class SplitTunneling extends _i43.PageRouteInfo {
- const SplitTunneling({List<_i43.PageRouteInfo>? children})
+/// [_i39.SplitTunneling]
+class SplitTunneling extends _i44.PageRouteInfo {
+ const SplitTunneling({List<_i44.PageRouteInfo>? children})
: super(SplitTunneling.name, initialChildren: children);
static const String name = 'SplitTunneling';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i38.SplitTunneling();
+ return const _i39.SplitTunneling();
},
);
}
/// generated route for
-/// [_i39.SplitTunnelingInfo]
-class SplitTunnelingInfo extends _i43.PageRouteInfo {
- const SplitTunnelingInfo({List<_i43.PageRouteInfo>? children})
+/// [_i40.SplitTunnelingInfo]
+class SplitTunnelingInfo extends _i44.PageRouteInfo {
+ const SplitTunnelingInfo({List<_i44.PageRouteInfo>? children})
: super(SplitTunnelingInfo.name, initialChildren: children);
static const String name = 'SplitTunnelingInfo';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i39.SplitTunnelingInfo();
+ return const _i40.SplitTunnelingInfo();
},
);
}
/// generated route for
-/// [_i40.Support]
-class Support extends _i43.PageRouteInfo {
- const Support({List<_i43.PageRouteInfo>? children})
+/// [_i41.Support]
+class Support extends _i44.PageRouteInfo {
+ const Support({List<_i44.PageRouteInfo>? children})
: super(Support.name, initialChildren: children);
static const String name = 'Support';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i40.Support();
+ return const _i41.Support();
},
);
}
/// generated route for
-/// [_i41.VPNSetting]
-class VPNSetting extends _i43.PageRouteInfo {
- const VPNSetting({List<_i43.PageRouteInfo>? children})
+/// [_i42.VPNSetting]
+class VPNSetting extends _i44.PageRouteInfo {
+ const VPNSetting({List<_i44.PageRouteInfo>? children})
: super(VPNSetting.name, initialChildren: children);
static const String name = 'VPNSetting';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i41.VPNSetting();
+ return const _i42.VPNSetting();
},
);
}
/// generated route for
-/// [_i42.WebsiteSplitTunneling]
-class WebsiteSplitTunneling extends _i43.PageRouteInfo {
- const WebsiteSplitTunneling({List<_i43.PageRouteInfo>? children})
+/// [_i43.WebsiteSplitTunneling]
+class WebsiteSplitTunneling extends _i44.PageRouteInfo {
+ const WebsiteSplitTunneling({List<_i44.PageRouteInfo>? children})
: super(WebsiteSplitTunneling.name, initialChildren: children);
static const String name = 'WebsiteSplitTunneling';
- static _i43.PageInfo page = _i43.PageInfo(
+ static _i44.PageInfo page = _i44.PageInfo(
name,
builder: (data) {
- return const _i42.WebsiteSplitTunneling();
+ return const _i43.WebsiteSplitTunneling();
},
);
}
diff --git a/lib/core/services/db/objectbox-model.json b/lib/core/services/db/objectbox-model.json
index 9926100149..064ce660ae 100644
--- a/lib/core/services/db/objectbox-model.json
+++ b/lib/core/services/db/objectbox-model.json
@@ -59,7 +59,7 @@
},
{
"id": "2:687217704776011576",
- "lastPropertyId": "22:1798613131332202898",
+ "lastPropertyId": "23:853140105317312758",
"name": "AppSetting",
"properties": [
{
@@ -142,6 +142,11 @@
"id": "22:1798613131332202898",
"name": "environment",
"type": 9
+ },
+ {
+ "id": "23:853140105317312758",
+ "name": "themeMode",
+ "type": 9
}
],
"relations": []
diff --git a/lib/core/services/db/objectbox.g.dart b/lib/core/services/db/objectbox.g.dart
index e86867a9aa..83066d1841 100644
--- a/lib/core/services/db/objectbox.g.dart
+++ b/lib/core/services/db/objectbox.g.dart
@@ -93,7 +93,7 @@ final _entities = [
obx_int.ModelEntity(
id: const obx_int.IdUid(2, 687217704776011576),
name: 'AppSetting',
- lastPropertyId: const obx_int.IdUid(22, 1798613131332202898),
+ lastPropertyId: const obx_int.IdUid(23, 853140105317312758),
flags: 0,
properties: [
obx_int.ModelProperty(
@@ -192,6 +192,12 @@ final _entities = [
type: 9,
flags: 0,
),
+ obx_int.ModelProperty(
+ id: const obx_int.IdUid(23, 853140105317312758),
+ name: 'themeMode',
+ type: 9,
+ flags: 0,
+ ),
],
relations: [],
backlinks: [],
@@ -1007,7 +1013,8 @@ obx_int.ModelDefinition getObjectBoxModel() {
final routingModeRawOffset = fbb.writeString(object.routingModeRaw);
final dataCapThresholdOffset = fbb.writeString(object.dataCapThreshold);
final environmentOffset = fbb.writeString(object.environment);
- fbb.startTable(23);
+ final themeModeOffset = fbb.writeString(object.themeMode);
+ fbb.startTable(24);
fbb.addInt64(0, object.id);
fbb.addBool(1, object.isPro);
fbb.addBool(2, object.isSplitTunnelingOn);
@@ -1024,6 +1031,7 @@ obx_int.ModelDefinition getObjectBoxModel() {
fbb.addOffset(19, dataCapThresholdOffset);
fbb.addBool(20, object.onboardingCompleted);
fbb.addOffset(21, environmentOffset);
+ fbb.addOffset(22, themeModeOffset);
fbb.finish(fbb.endTable());
return object.id;
},
@@ -1105,6 +1113,9 @@ obx_int.ModelDefinition getObjectBoxModel() {
44,
false,
);
+ final themeModeParam = const fb.StringReader(
+ asciiOptimization: true,
+ ).vTableGet(buffer, rootOffset, 48, '');
final environmentParam = const fb.StringReader(
asciiOptimization: true,
).vTableGet(buffer, rootOffset, 46, '');
@@ -1124,6 +1135,7 @@ obx_int.ModelDefinition getObjectBoxModel() {
routingModeRaw: routingModeRawParam,
dataCapThreshold: dataCapThresholdParam,
onboardingCompleted: onboardingCompletedParam,
+ themeMode: themeModeParam,
environment: environmentParam,
);
@@ -2060,6 +2072,11 @@ class AppSetting_ {
static final environment = obx.QueryStringProperty(
_entities[1].properties[15],
);
+
+ /// See [AppSetting.themeMode].
+ static final themeMode = obx.QueryStringProperty(
+ _entities[1].properties[16],
+ );
}
/// [DeviceEntity] entity fields to define ObjectBox queries.
diff --git a/lib/core/services/stripe_service.dart b/lib/core/services/stripe_service.dart
index 8bab05fd6d..735d98dbcd 100644
--- a/lib/core/services/stripe_service.dart
+++ b/lib/core/services/stripe_service.dart
@@ -30,11 +30,29 @@ class StripeService {
// It takes the StripeOptions object and a callback function for success and error handling
// this is only used by android
Future startStripeSDK({
+ required BuildContext context,
required StripeOptions options,
required OnPressed onSuccess,
required Function(dynamic error) onError,
}) async {
try {
+ // Extract all context-dependent values before any async gap
+ final brightness = Theme.of(context).brightness;
+ final style =
+ brightness == Brightness.dark ? ThemeMode.dark : ThemeMode.light;
+ final sheetColors = PaymentSheetAppearanceColors(
+ background: context.bgSurface,
+ componentBackground: context.bgElevated,
+ primary: context.actionPrimaryBg,
+ primaryText: context.textPrimary,
+ secondaryText: context.textSecondary,
+ icon: context.textTertiary,
+ componentBorder: context.borderInput,
+ componentDivider: context.borderDefault,
+ componentText: context.textPrimary,
+ error: AppColors.red4,
+ placeholderText: context.textDisabled,
+ );
if (options.publishableKey != null &&
options.publishableKey!.isNotEmpty) {
Stripe.publishableKey = options.publishableKey!;
@@ -63,22 +81,10 @@ class StripeService {
testEnv: kDebugMode,
),
appearance: PaymentSheetAppearance(
- colors: PaymentSheetAppearanceColors(
- background: AppColors.gray1,
- componentBackground: AppColors.white,
- primary: AppColors.blue10,
- primaryText: AppColors.gray8,
- secondaryText: AppColors.black,
- icon: AppColors.gray9,
- componentBorder: AppColors.gray3,
- componentDivider: AppColors.gray2,
- componentText: AppColors.gray8,
- error: AppColors.red4,
- placeholderText: AppColors.gray9,
- ),
+ colors: sheetColors,
shapes: PaymentSheetShape(borderRadius: 16),
),
- style: ThemeMode.light,
+ style: style,
),
);
diff --git a/lib/core/utils/decoration.dart b/lib/core/utils/decoration.dart
index c3e778f5c6..29d1c0d426 100644
--- a/lib/core/utils/decoration.dart
+++ b/lib/core/utils/decoration.dart
@@ -1,18 +1,3 @@
import 'package:flutter/material.dart';
import 'package:lantern/core/common/app_colors.dart';
-BoxDecoration get selectedDecoration {
- return BoxDecoration(
- color: AppColors.blue1,
- border: Border.all(color: AppColors.blue7, width: 3),
- borderRadius: BorderRadius.circular(16),
- );
-}
-
-BoxDecoration get unselectedDecoration {
- return BoxDecoration(
- color: AppColors.white,
- border: Border.all(color: AppColors.gray3, width: 1.5),
- borderRadius: BorderRadius.circular(16),
- );
-}
diff --git a/lib/core/utils/pro_utils.dart b/lib/core/utils/pro_utils.dart
index 6116f25bec..b382f3741b 100644
--- a/lib/core/utils/pro_utils.dart
+++ b/lib/core/utils/pro_utils.dart
@@ -23,7 +23,7 @@ Future showProAccountFlowDialog({
? 'set_account_password_message'.i18n
: 'update_pro_account_message'.i18n,
style: Theme.of(context).textTheme.bodySmall!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
],
@@ -31,7 +31,7 @@ Future showProAccountFlowDialog({
action: [
AppTextButton(
label: 'cancel'.i18n,
- textColor: AppColors.gray6,
+ textColor: context.textDisabled,
onPressed: () => appRouter.maybePop(),
),
AppTextButton(
diff --git a/lib/core/widgets/app_pin_field.dart b/lib/core/widgets/app_pin_field.dart
index 85b1a272c4..0ee735c43b 100644
--- a/lib/core/widgets/app_pin_field.dart
+++ b/lib/core/widgets/app_pin_field.dart
@@ -21,8 +21,8 @@ class AppPinField extends StatelessWidget {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 5),
decoration: BoxDecoration(
- color: AppColors.white,
- border: Border.all(color: AppColors.gray3),
+ color: context.bgElevated,
+ border: Border.all(color: context.borderInput),
borderRadius: BorderRadius.circular(16),
),
child: Row(
@@ -71,14 +71,14 @@ class AppPinField extends StatelessWidget {
Container(
width: 2,
height: 20,
- color: AppColors.gray4,
+ color: context.textDisabled,
),
],
),
preFilledWidget: Container(
width: 15,
height: 1,
- color: AppColors.gray4,
+ color: context.textDisabled,
),
defaultPinTheme: PinTheme(
width: 20,
diff --git a/lib/core/widgets/app_rich_text.dart b/lib/core/widgets/app_rich_text.dart
index 3a565b6f0a..7563d9819e 100644
--- a/lib/core/widgets/app_rich_text.dart
+++ b/lib/core/widgets/app_rich_text.dart
@@ -1,6 +1,7 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:lantern/core/common/app_buttons.dart';
+import 'package:lantern/core/common/app_semantic_colors.dart';
import '../common/app_colors.dart';
import '../common/app_text_styles.dart';
@@ -29,14 +30,14 @@ class AppRichText extends StatelessWidget {
text: TextSpan(
text: texts,
style: textTheme.labelLarge!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
children: [
TextSpan(
text: boldTexts,
style: AppTextStyles.labelLargeBold.copyWith(
fontWeight: FontWeight.bold,
- color: boldColor ?? AppColors.gray8,
+ color: boldColor ?? context.textSecondary,
decoration: boldUnderline
? TextDecoration.underline
: TextDecoration.none,
diff --git a/lib/core/widgets/app_text.dart b/lib/core/widgets/app_text.dart
index e2ed5276a1..06ae3f62e1 100644
--- a/lib/core/widgets/app_text.dart
+++ b/lib/core/widgets/app_text.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:lantern/core/common/common.dart';
+import 'package:lantern/core/common/app_semantic_colors.dart';
class HeaderText extends StatelessWidget {
final String text;
@@ -26,7 +26,9 @@ class HeaderText extends StatelessWidget {
final textTheme = Theme.of(context).textTheme;
return Text(
text,
- style: textTheme.labelLarge?.copyWith(color: AppColors.gray8),
+ style: textTheme.labelLarge?.copyWith(
+ color: color ?? context.textSecondary,
+ ),
textAlign: textAlign,
maxLines: maxLines,
overflow: overflow,
diff --git a/lib/core/widgets/app_tile.dart b/lib/core/widgets/app_tile.dart
index 49fa146f8c..3824514f4d 100644
--- a/lib/core/widgets/app_tile.dart
+++ b/lib/core/widgets/app_tile.dart
@@ -33,6 +33,7 @@ class AppTile extends StatelessWidget {
final BorderRadius? borderRadius;
final VisualDensity? visualDensity;
final ListTileTitleAlignment? titleAlignment;
+ final bool? iconUseThemeColor;
const AppTile({
super.key,
@@ -59,6 +60,7 @@ class AppTile extends StatelessWidget {
this.borderRadius,
this.visualDensity,
this.titleAlignment,
+ this.iconUseThemeColor,
});
factory AppTile.link({
@@ -92,7 +94,9 @@ class AppTile extends StatelessWidget {
final textStyle = tileTextStyle ??
theme.textTheme.labelLarge!.copyWith(
- color: enabled ? AppColors.gray9 : AppColors.gray6,
+ color: enabled
+ ? context.textPrimary // text.primary
+ : context.textPrimary.withValues(alpha: 0.38), // text.disabled
fontWeight: FontWeight.w400,
fontSize: 16,
);
@@ -103,11 +107,17 @@ class AppTile extends StatelessWidget {
computedLeading = SizedBox(
width: 24,
height: 24,
- child: AppImage(path: icon as String),
+ child: AppImage(
+ path: icon as String,
+ useThemeColor: iconUseThemeColor ?? true,
+ ),
);
} else if (icon is IconData) {
- computedLeading =
- Icon(icon as IconData, size: 24, color: AppColors.gray9);
+ computedLeading = Icon(
+ icon as IconData,
+ size: 24,
+ color: context.textPrimary, // text.primary
+ );
} else if (icon is Image) {
computedLeading = icon as Image;
} else if (icon is Widget) {
@@ -128,8 +138,10 @@ class AppTile extends StatelessWidget {
selected: selected,
titleAlignment: titleAlignment ?? ListTileTitleAlignment.center,
enableFeedback: true,
- hoverColor: hoverColor ?? AppColors.blue1,
- selectedTileColor: selectedTileColor ?? AppColors.blue1,
+ // hoverColor: hoverColor ?? AppColors.blue1,
+ hoverColor: hoverColor ?? theme.hoverColor,
+ // selectedTileColor: selectedTileColor ?? AppColors.blue1,
+ selectedTileColor: selectedTileColor ?? theme.hoverColor,
tileColor: tileColor,
minTileHeight: minHeight ?? effectiveMinHeight,
shape: RoundedRectangleBorder(
diff --git a/lib/core/widgets/app_webview.dart b/lib/core/widgets/app_webview.dart
index 1b41bc2d0f..919e358db2 100644
--- a/lib/core/widgets/app_webview.dart
+++ b/lib/core/widgets/app_webview.dart
@@ -33,8 +33,8 @@ class AppWebView extends HookConsumerWidget {
title: Text(title),
centerTitle: true,
leading: SizedBox(),
- backgroundColor: AppColors.white,
- iconTheme: IconThemeData(color: AppColors.black),
+ backgroundColor: context.bgElevated,
+ iconTheme: IconThemeData(color: context.textPrimary),
actions: [
IconButton(
icon: const Icon(Icons.close),
diff --git a/lib/core/widgets/base_screen.dart b/lib/core/widgets/base_screen.dart
index 753c576db2..23df336502 100644
--- a/lib/core/widgets/base_screen.dart
+++ b/lib/core/widgets/base_screen.dart
@@ -27,7 +27,8 @@ class BaseScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
- backgroundColor: backgroundColor ?? AppColors.gray1,
+ backgroundColor: backgroundColor ?? Theme.of(context).scaffoldBackgroundColor,
+ // backgroundColor: backgroundColor ?? AppColors.gray1,
appBar: appBar ??
CustomAppBar(
title: Text(title),
diff --git a/lib/core/widgets/bottomsheet.dart b/lib/core/widgets/bottomsheet.dart
index 2c4b19d51e..48f83d020f 100644
--- a/lib/core/widgets/bottomsheet.dart
+++ b/lib/core/widgets/bottomsheet.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:lantern/core/common/app_colors.dart';
+import 'package:lantern/core/common/app_semantic_colors.dart';
import 'package:lantern/core/widgets/divider_space.dart';
typedef BottomSheetBuilder = Function(
@@ -10,13 +10,12 @@ void showAppBottomSheet(
required BottomSheetBuilder builder,
required String title,
double scrollControlDisabledMaxHeightRatio = .75}) {
- final textTheme = Theme.of(context).textTheme.headlineSmall;
+ // backgroundColor and shape come from bottomSheetTheme in app_theme.dart
showModalBottomSheet(
context: context,
isDismissible: true,
enableDrag: true,
showDragHandle: true,
- backgroundColor: AppColors.white,
scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio,
builder: (context) {
return DraggableScrollableSheet(
@@ -32,14 +31,12 @@ void showAppBottomSheet(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
title,
- style: textTheme!.copyWith(
- color: AppColors.blue10,
+ style: Theme.of(context).textTheme.headlineSmall!.copyWith(
+ color: context.textPrimary,
),
),
),
- DividerSpace(
- padding: EdgeInsets.only(top: 16),
- ),
+ DividerSpace(padding: EdgeInsets.only(top: 16)),
builder(context, scrollController),
],
);
diff --git a/lib/core/widgets/card_dropdown.dart b/lib/core/widgets/card_dropdown.dart
index 8245fb44d0..9f20cb69d6 100644
--- a/lib/core/widgets/card_dropdown.dart
+++ b/lib/core/widgets/card_dropdown.dart
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:lantern/core/common/app_asset.dart';
import 'package:lantern/core/common/app_colors.dart';
+import 'package:lantern/core/common/app_semantic_colors.dart';
import 'package:lantern/core/common/app_text_styles.dart';
class CardDropdown extends StatelessWidget {
@@ -23,18 +24,18 @@ class CardDropdown extends StatelessWidget {
this.enabled = true,
});
- Widget? _buildPrefix(Object? iconPath) {
+ Widget? _buildPrefix(Object? iconPath, BuildContext context) {
if (iconPath == null) return null;
const pad = EdgeInsets.only(left: 16, right: 16);
if (iconPath is IconData) {
return Padding(
padding: pad,
- child: Icon(iconPath, color: AppColors.yellow9),
+ child: Icon(iconPath, color: context.textPromoIcon),
);
} else if (iconPath is String) {
return Padding(
padding: pad,
- child: AppImage(path: iconPath, color: AppColors.yellow9),
+ child: AppImage(path: iconPath, color: context.textPromoIcon),
);
} else if (iconPath is Widget) {
return Padding(padding: pad, child: iconPath);
@@ -50,20 +51,20 @@ class CardDropdown extends StatelessWidget {
onChanged: enabled ? onChanged : null,
validator: validator,
decoration: InputDecoration(
- prefixIcon: _buildPrefix(prefixIcon),
+ prefixIcon: _buildPrefix(prefixIcon, context),
contentPadding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
filled: true,
- fillColor: enabled ? AppColors.white : AppColors.gray3.withOpacity(0.3),
+ fillColor: enabled ? context.bgElevated : context.borderInput.withOpacity(0.3),
hintText: hintText,
- hintStyle: AppTextStyles.bodyMedium.copyWith(color: AppColors.gray4),
+ hintStyle: AppTextStyles.bodyMedium.copyWith(color: context.textDisabled),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
- borderSide: BorderSide(color: AppColors.gray3, width: 1),
+ borderSide: BorderSide(color: context.borderInput, width: 1),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
- borderSide: BorderSide(color: AppColors.gray3, width: 1),
+ borderSide: BorderSide(color: context.borderInput, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
@@ -71,16 +72,16 @@ class CardDropdown extends StatelessWidget {
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
- borderSide: BorderSide(color: AppColors.red5, width: 1.2),
+ borderSide: BorderSide(color: context.statusErrorBorder, width: 1.2),
),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide:
- BorderSide(color: AppColors.gray3.withOpacity(0.5), width: 1),
+ BorderSide(color: context.borderInput.withOpacity(0.5), width: 1),
),
),
style: AppTextStyles.bodyMedium.copyWith(
- color: enabled ? AppColors.black1 : AppColors.gray4,
+ color: enabled ? context.textPrimary : context.textDisabled,
),
icon: const Icon(Icons.keyboard_arrow_down_rounded,
color: null), // uses default IconTheme
diff --git a/lib/core/widgets/divider_space.dart b/lib/core/widgets/divider_space.dart
index 1a8572c181..b38ebb3787 100644
--- a/lib/core/widgets/divider_space.dart
+++ b/lib/core/widgets/divider_space.dart
@@ -1,7 +1,5 @@
import 'package:flutter/material.dart';
-import '../common/app_colors.dart';
-
class DividerSpace extends StatelessWidget {
final EdgeInsetsGeometry padding;
@@ -15,7 +13,9 @@ class DividerSpace extends StatelessWidget {
return Padding(
padding: padding,
child: Divider(
- color: AppColors.gray2,
+ // border.default: Gray.200 light / Gray.800 dark
+ // color: AppColors.gray2,
+ color: Theme.of(context).dividerTheme.color,
height: 1,
),
);
diff --git a/lib/core/widgets/email_tag.dart b/lib/core/widgets/email_tag.dart
index 09526deb27..d62117e941 100644
--- a/lib/core/widgets/email_tag.dart
+++ b/lib/core/widgets/email_tag.dart
@@ -14,7 +14,7 @@ class EmailTag extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Chip(
- color: WidgetStatePropertyAll(AppColors.blue1),
+ color: WidgetStatePropertyAll(context.bgCallout),
elevation: 0,
avatar: AppImage(
path: AppImagePaths.email,
@@ -27,7 +27,7 @@ class EmailTag extends StatelessWidget {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
side: BorderSide(
- color: AppColors.gray3,
+ color: context.borderInput,
width: 1,
),
),
diff --git a/lib/core/widgets/flag.dart b/lib/core/widgets/flag.dart
index be03441105..c096b766d7 100644
--- a/lib/core/widgets/flag.dart
+++ b/lib/core/widgets/flag.dart
@@ -1,7 +1,6 @@
import 'package:country_flags/country_flags.dart';
import 'package:flutter/material.dart';
-
-import '../common/app_colors.dart';
+import 'package:lantern/core/common/app_semantic_colors.dart';
class Flag extends StatelessWidget {
final String countryCode;
@@ -14,7 +13,7 @@ class Flag extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
- border: Border.all(color: AppColors.gray3, width: .5),
+ border: Border.all(color: context.borderInput, width: .5),
),
child: SizedBox.fromSize(
size: size,
diff --git a/lib/core/widgets/info_row.dart b/lib/core/widgets/info_row.dart
index c77fb407bb..8d3158ce2f 100644
--- a/lib/core/widgets/info_row.dart
+++ b/lib/core/widgets/info_row.dart
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:lantern/core/common/app_asset.dart';
-import 'package:lantern/core/common/app_colors.dart';
import 'package:lantern/core/common/app_image_paths.dart';
+import 'package:lantern/core/common/app_semantic_colors.dart';
class InfoRow extends StatelessWidget {
final Widget? icon;
@@ -38,13 +38,13 @@ class InfoRow extends StatelessWidget {
final textTheme = Theme.of(context).textTheme;
return ListTile(
minTileHeight: minTileHeight,
- tileColor: backgroundColor,
+ tileColor: backgroundColor?? context.bgElevated,
onTap: onPressed,
contentPadding:
padding ?? EdgeInsets.symmetric(horizontal: 16, vertical: 4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadius),
- side: BorderSide(color: borderColor ?? AppColors.gray2),
+ side: BorderSide(color: borderColor ?? context.borderDefault),
),
leading: showLeadingIcon
? AppImage(
@@ -56,7 +56,7 @@ class InfoRow extends StatelessWidget {
text,
style: textStyle ??
(textTheme.bodyMedium)!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
));
}
diff --git a/lib/core/widgets/labeled_card_dropdown.dart b/lib/core/widgets/labeled_card_dropdown.dart
index 255e22e665..a6e0119621 100644
--- a/lib/core/widgets/labeled_card_dropdown.dart
+++ b/lib/core/widgets/labeled_card_dropdown.dart
@@ -28,7 +28,7 @@ class LabeledCardDropdownWithFlag extends StatelessWidget {
decoration: BoxDecoration(
color: finalizeCardColor,
borderRadius: BorderRadius.circular(16),
- border: Border.all(color: AppColors.gray2, width: 1),
+ border: Border.all(color: context.borderDefault, width: 1),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -46,7 +46,7 @@ class LabeledCardDropdownWithFlag extends StatelessWidget {
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 4),
decoration: BoxDecoration(
border: Border.all(
- color: AppColors.gray2,
+ color: context.borderDefault,
width: 1,
),
borderRadius: BorderRadius.circular(12),
@@ -68,7 +68,7 @@ class LabeledCardDropdownWithFlag extends StatelessWidget {
Text(
countryLabelKey.i18n,
style: AppTextStyles.bodyLarge.copyWith(
- color: AppColors.black1,
+ color: context.textPrimary,
height: 1.62,
),
),
diff --git a/lib/core/widgets/labeled_card_input.dart b/lib/core/widgets/labeled_card_input.dart
index bd6002cf68..93b580bd1b 100644
--- a/lib/core/widgets/labeled_card_input.dart
+++ b/lib/core/widgets/labeled_card_input.dart
@@ -39,7 +39,7 @@ class LabeledCardInput extends StatelessWidget {
color: cardColor,
borderRadius: BorderRadius.circular(16),
border: Border.all(
- color: AppColors.gray2,
+ color: context.borderDefault,
width: 1,
),
),
diff --git a/lib/core/widgets/lantern_logo.dart b/lib/core/widgets/lantern_logo.dart
index 94b41f601a..9269520d1c 100644
--- a/lib/core/widgets/lantern_logo.dart
+++ b/lib/core/widgets/lantern_logo.dart
@@ -34,6 +34,7 @@ class LanternLogo extends StatelessWidget {
height: height,
width: width,
fit: BoxFit.contain,
+
);
}
}
diff --git a/lib/core/widgets/oauth_login.dart b/lib/core/widgets/oauth_login.dart
index 4a720b5c9b..14bf4f7374 100644
--- a/lib/core/widgets/oauth_login.dart
+++ b/lib/core/widgets/oauth_login.dart
@@ -29,6 +29,7 @@ class OAuthLogin extends HookConsumerWidget {
label: 'continue_with_apple'.i18n,
icon: AppImagePaths.apple,
isTaller: true,
+ iconColor: context.textPrimary,
onPressed: () => _handleSignIn(SignUpMethodType.apple, ref, context),
);
}
@@ -36,6 +37,7 @@ class OAuthLogin extends HookConsumerWidget {
label: 'continue_with_google'.i18n,
icon: AppImagePaths.google,
isTaller: true,
+ useThemeColor: false,
onPressed: () => _handleSignIn(SignUpMethodType.google, ref, context),
);
}
diff --git a/lib/core/widgets/password_criteria.dart b/lib/core/widgets/password_criteria.dart
index 514f5fb531..4ffb98b726 100644
--- a/lib/core/widgets/password_criteria.dart
+++ b/lib/core/widgets/password_criteria.dart
@@ -50,10 +50,10 @@ class _PasswordCriteriaWidgetState extends State {
return Container(
padding: const EdgeInsets.all(12.0),
decoration: BoxDecoration(
- color: AppColors.white,
+ color: context.bgElevated,
borderRadius: BorderRadius.circular(16.0),
border: Border.all(
- color: AppColors.gray3,
+ color: context.borderInput,
width: .5,
),
),
@@ -84,7 +84,7 @@ class _PasswordCriteriaWidgetState extends State {
children: [
Icon(
metCriteria ? Icons.check_circle : Icons.radio_button_unchecked,
- color: metCriteria ? AppColors.green6 : Colors.grey,
+ color: metCriteria ? context.statusSuccessBorder : Colors.grey,
size: 18,
),
const SizedBox(width: 8),
@@ -92,7 +92,7 @@ class _PasswordCriteriaWidgetState extends State {
criteria,
style: textTheme!.labelMedium!.copyWith(
fontSize: 14,
- color: AppColors.gray9,
+ color: context.textPrimary,
),
),
],
diff --git a/lib/core/widgets/platform_card.dart b/lib/core/widgets/platform_card.dart
index 8dba25820e..695889fd40 100644
--- a/lib/core/widgets/platform_card.dart
+++ b/lib/core/widgets/platform_card.dart
@@ -17,10 +17,11 @@ class PlatformCard extends StatelessWidget {
onPressed: onPressed,
style: IconButton.styleFrom(
padding: EdgeInsets.all(15.r),
- backgroundColor: AppColors.white,
+ backgroundColor: context.bgElevated,
+ hoverColor: context.bgHover,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
- side: BorderSide(color: AppColors.gray3, width: .5),
+ side: BorderSide(color: context.borderInput, width: .5),
)),
icon: AppImage(
fit: BoxFit.contain,
diff --git a/lib/core/widgets/pro_banner.dart b/lib/core/widgets/pro_banner.dart
index 3ce6a2eea2..24c572f31a 100644
--- a/lib/core/widgets/pro_banner.dart
+++ b/lib/core/widgets/pro_banner.dart
@@ -23,9 +23,9 @@ class ProBanner extends HookConsumerWidget {
margin: EdgeInsets.only(top: topMargin),
padding: EdgeInsets.all(defaultSize),
decoration: BoxDecoration(
- color: AppColors.yellow1,
+ color: context.bgPromo,
borderRadius: BorderRadius.circular(16),
- border: Border.all(color: AppColors.yellow4, width: 1)),
+ border: Border.all(color: context.borderPromo, width: 1)),
child: Column(
children: [
AutoSizeText(
@@ -37,7 +37,7 @@ class ProBanner extends HookConsumerWidget {
maxFontSize: 16,
overflow: TextOverflow.ellipsis,
style: textTheme.bodyMedium!.copyWith(
- color: AppColors.gray9,
+ color: context.textPrimary,
fontSize: 16,
),
),
diff --git a/lib/core/widgets/pro_button.dart b/lib/core/widgets/pro_button.dart
index b07b6047b5..2f45ae8e8f 100644
--- a/lib/core/widgets/pro_button.dart
+++ b/lib/core/widgets/pro_button.dart
@@ -18,6 +18,7 @@ class ProButton extends StatelessWidget {
icon: AppImagePaths.crown,
expanded: true,
isTaller: true,
+ useThemeColor: false,
onPressed: onPressed,
);
}
diff --git a/lib/core/widgets/search_bar.dart b/lib/core/widgets/search_bar.dart
index 021a1a65e4..fb1b09886f 100644
--- a/lib/core/widgets/search_bar.dart
+++ b/lib/core/widgets/search_bar.dart
@@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:lantern/core/common/app_asset.dart';
-import 'package:lantern/core/common/app_colors.dart';
import 'package:lantern/core/common/app_image_paths.dart';
+import 'package:lantern/core/common/app_semantic_colors.dart';
import 'package:lantern/features/split_tunneling/provider/search_query.dart';
class AppSearchBar extends AppBar {
@@ -56,26 +56,29 @@ class _SearchBarContent extends HookConsumerWidget {
// Search input or title
Expanded(
child: isSearching.value
- ? TextField(
- controller: controller,
- autofocus: true,
- onChanged: (value) =>
- ref.read(searchQueryProvider.notifier).setQuery(value),
- decoration: InputDecoration(
- hintText: hintText,
- hintStyle: TextStyle(
- color: AppColors.gray7,
+ ? Theme(
+ data: ThemeData(),
+ child: TextField(
+ controller: controller,
+ autofocus: true,
+ onChanged: (value) =>
+ ref.read(searchQueryProvider.notifier).setQuery(value),
+ decoration: InputDecoration(
+ hintText: hintText,
+ hintStyle: TextStyle(
+ color: context.textSecondary,
+ fontSize: 16,
+ fontWeight: FontWeight.w400,
+ ),
+ border: InputBorder.none,
+ isDense: true,
+ contentPadding: const EdgeInsets.symmetric(vertical: 8),
+ ),
+ style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
+ color: context.textPrimary,
),
- border: InputBorder.none,
- isDense: true,
- contentPadding: const EdgeInsets.symmetric(vertical: 8),
- ),
- style: TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.w400,
- color: AppColors.gray9,
),
)
: Text(
@@ -83,7 +86,7 @@ class _SearchBarContent extends HookConsumerWidget {
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w600,
- color: AppColors.gray9,
+ color: context.textPrimary,
),
),
),
diff --git a/lib/core/widgets/section_label.dart b/lib/core/widgets/section_label.dart
index c8f76fa91e..e794553525 100644
--- a/lib/core/widgets/section_label.dart
+++ b/lib/core/widgets/section_label.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:lantern/core/common/app_colors.dart';
+import 'package:lantern/core/common/app_semantic_colors.dart';
class SectionLabel extends StatelessWidget {
final String title;
@@ -13,7 +13,7 @@ class SectionLabel extends StatelessWidget {
child: Text(
title,
style: Theme.of(context).textTheme.labelLarge!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
fontSize: 14,
fontWeight: FontWeight.w500,
),
diff --git a/lib/core/widgets/setting_tile.dart b/lib/core/widgets/setting_tile.dart
index bf158e6289..31900b4553 100644
--- a/lib/core/widgets/setting_tile.dart
+++ b/lib/core/widgets/setting_tile.dart
@@ -1,7 +1,9 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
-import '../common/common.dart';
+import '../common/app_asset.dart';
+import '../common/app_semantic_colors.dart';
+import '../extensions/string.dart';
class SettingTile extends StatelessWidget {
final String label;
@@ -29,7 +31,7 @@ class SettingTile extends StatelessWidget {
return InkWell(
borderRadius: BorderRadius.circular(16),
onTap: onTap,
- splashColor: AppColors.gray2,
+ splashColor: context.bgCallout,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
child: Column(
@@ -43,9 +45,11 @@ class SettingTile extends StatelessWidget {
child: icon is String ? AppImage(path: icon) : icon as Widget,
),
SizedBox(width: 8),
- Text(label,
- style:
- textTheme.labelLarge!.copyWith(color: AppColors.gray7)),
+ Text(
+ label,
+ style: textTheme.labelLarge!
+ .copyWith(color: context.textSecondary),
+ ),
],
),
Row(
@@ -55,12 +59,14 @@ class SettingTile extends StatelessWidget {
Expanded(child: child!)
else
Expanded(
- child: AutoSizeText(value,
- maxLines: 1,
- maxFontSize: 16,
- minFontSize: 14,
- style: textTheme.titleMedium!
- .copyWith(color: AppColors.gray9)),
+ child: AutoSizeText(
+ value,
+ maxLines: 1,
+ maxFontSize: 16,
+ minFontSize: 14,
+ style: textTheme.titleMedium!
+ .copyWith(color: context.textPrimary),
+ ),
),
...actions
],
@@ -68,9 +74,11 @@ class SettingTile extends StatelessWidget {
if (subtitle != null && subtitle!.isNotEmpty)
Padding(
padding: const EdgeInsets.only(left: 32.0),
- child: Text(subtitle!.capitalize,
- style:
- textTheme.labelLarge!.copyWith(color: AppColors.gray7)),
+ child: Text(
+ subtitle!.capitalize,
+ style: textTheme.labelLarge!
+ .copyWith(color: context.textSecondary),
+ ),
),
],
),
diff --git a/lib/core/widgets/split_tunneling_tile.dart b/lib/core/widgets/split_tunneling_tile.dart
index c4ebca827e..a57f0be084 100644
--- a/lib/core/widgets/split_tunneling_tile.dart
+++ b/lib/core/widgets/split_tunneling_tile.dart
@@ -27,7 +27,7 @@ class SplitTunnelingTile extends StatelessWidget {
? Text(
subtitle!,
style: AppTextStyles.labelMedium.copyWith(
- color: AppColors.gray7,
+ color: context.textTertiary,
),
)
: null,
diff --git a/lib/core/widgets/subscription_tags.dart b/lib/core/widgets/subscription_tags.dart
index ae19beaf98..0f59e1222a 100644
--- a/lib/core/widgets/subscription_tags.dart
+++ b/lib/core/widgets/subscription_tags.dart
@@ -25,15 +25,15 @@ class SubscriptionTags extends StatelessWidget {
vertical: 4,
),
decoration: BoxDecoration(
- color: isExpired ? AppColors.red2 : AppColors.green2,
+ color: isExpired ? context.statusErrorBg : context.statusSuccessBg,
border: Border.all(
- color: isExpired ? AppColors.red4 : AppColors.green4,
+ color: isExpired ? context.statusErrorBorder : context.statusSuccessBorder,
),
borderRadius: BorderRadius.circular(8)),
child: Text(
isExpired ? 'subscription_expired'.i18n : 'pro'.i18n,
style: textTheme.labelMedium!.copyWith(
- color: isExpired ? AppColors.red8 : AppColors.green8,
+ color: isExpired ? context.statusErrorText : context.statusSuccessText,
),
),
);
diff --git a/lib/core/widgets/switch_button.dart b/lib/core/widgets/switch_button.dart
index d391f111d3..56dc6a0771 100644
--- a/lib/core/widgets/switch_button.dart
+++ b/lib/core/widgets/switch_button.dart
@@ -30,26 +30,34 @@ class SwitchButton extends StatelessWidget {
spacing: 10.h,
height: PlatformUtils.isDesktop ? 40.h : 30.h,
wrapperBuilder: (context, global, child) {
+ final isDark = Theme.of(context).brightness == Brightness.dark;
return Container(
width: trackWidth,
padding: const EdgeInsets.symmetric(horizontal: 5),
decoration: BoxDecoration(
- color: value ? (activeColor ?? AppColors.green5) : AppColors.gray7,
+ // toggle-active-bg: Green.500 light / Green.700 dark
+ // toggle-disabled-bg (off state): Gray.700 both
+ color: value
+ ? (activeColor ??
+ (isDark ? AppColors.green7 : AppColors.green5))
+ : AppColors.gray7,
borderRadius: BorderRadius.circular(100),
),
child: child,
);
},
foregroundIndicatorBuilder: (context, global) {
+ final isDark = Theme.of(context).brightness == Brightness.dark;
return GestureDetector(
onTap: () {
onChanged(value ? false : true);
},
child: Container(
- decoration: const BoxDecoration(
- color: Colors.white,
+ decoration: BoxDecoration(
+ // toggle-knob-bg: White light / Gray.100 dark
+ color: isDark ? AppColors.gray1 : Colors.white,
shape: BoxShape.circle,
- boxShadow: [
+ boxShadow: const [
BoxShadow(
color: Colors.black12,
blurRadius: 4,
diff --git a/lib/core/widgets/vpn_status_indicator.dart b/lib/core/widgets/vpn_status_indicator.dart
index 134a7c42d1..69647027a5 100644
--- a/lib/core/widgets/vpn_status_indicator.dart
+++ b/lib/core/widgets/vpn_status_indicator.dart
@@ -28,6 +28,7 @@ class VPNStatusIndicator extends StatelessWidget {
return AppImage(
path: indicator,
+ useThemeColor: false,
color: status == VPNStatus.disconnected ? AppColors.gray3 : null,
);
}
diff --git a/lib/features/account/account.dart b/lib/features/account/account.dart
index d38bbefe0b..03b04e139c 100644
--- a/lib/features/account/account.dart
+++ b/lib/features/account/account.dart
@@ -32,132 +32,134 @@ class Account extends HookConsumerWidget {
final appSettings = ref.watch(appSettingProvider);
final theme = Theme.of(buildContext).textTheme;
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- if (isExpired) ...{
- InfoRow(
- minTileHeight: 40,
- backgroundColor: AppColors.red1,
- borderColor: AppColors.red2,
- textStyle: theme.labelLarge!.copyWith(
- color: AppColors.red9,
+ return SafeArea(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ if (isExpired) ...{
+ InfoRow(
+ minTileHeight: 40,
+ backgroundColor: AppColors.red1,
+ borderColor: AppColors.red2,
+ textStyle: theme.labelLarge!.copyWith(
+ color: buildContext.statusErrorBg,
+ ),
+ text: 'pro_subscription_expired_message'.i18n,
),
- text: 'pro_subscription_expired_message'.i18n,
- ),
+ SizedBox(height: defaultSize),
+ ProButton(
+ label: 'renew_pro_subscription'.i18n,
+ onPressed: () {
+ appRouter.push(const Plans());
+ },
+ ),
+ },
SizedBox(height: defaultSize),
- ProButton(
- label: 'renew_pro_subscription'.i18n,
- onPressed: () {
- appRouter.push(const Plans());
- },
+ Padding(
+ padding: const EdgeInsets.only(left: 16),
+ child: Text(
+ 'lantern_pro_email'.i18n,
+ style: theme.labelLarge!.copyWith(
+ color: buildContext.textSecondary,
+ ),
+ ),
),
- },
- SizedBox(height: defaultSize),
- Padding(
- padding: const EdgeInsets.only(left: 16),
- child: Text(
- 'lantern_pro_email'.i18n,
- style: theme.labelLarge!.copyWith(
- color: AppColors.gray8,
+ AppCard(
+ padding: EdgeInsets.zero,
+ child: AppTile(
+ label: appSettings.email.toLowerCase(),
+ icon: AppImagePaths.email,
+ contentPadding: EdgeInsets.only(left: 16),
+ onPressed: kDebugMode
+ ? () {
+ copyToClipboard(appSettings.email);
+ }
+ : null,
+ trailing: AppTextButton(
+ label: 'change_email'.i18n,
+ onPressed: () {
+ appRouter.push(SignInPassword(
+ email: appSettings.email, fromChangeEmail: true));
+ },
+ ),
),
),
- ),
- AppCard(
- padding: EdgeInsets.zero,
- child: AppTile(
- label: appSettings.email.toLowerCase(),
- icon: AppImagePaths.email,
- contentPadding: EdgeInsets.only(left: 16),
- onPressed: kDebugMode
- ? () {
- copyToClipboard(appSettings.email);
- }
- : null,
- trailing: AppTextButton(
- label: 'change_email'.i18n,
- onPressed: () {
- appRouter.push(SignInPassword(
- email: appSettings.email, fromChangeEmail: true));
- },
+ SizedBox(height: defaultSize),
+ if (isExpired)
+ Padding(
+ padding: const EdgeInsets.only(left: 16),
+ child: Text(
+ 'last_subscription_renewal_date'.i18n,
+ style: theme.labelLarge!.copyWith(
+ color: buildContext.textSecondary,
+ ),
+ ),
+ )
+ else
+ Padding(
+ padding: const EdgeInsets.only(left: 16),
+ child: Text(
+ user!.legacyUserData.subscriptionData.autoRenew
+ ? 'subscription_renewal_date'.i18n
+ : 'pro_account_expiration'.i18n,
+ style: theme.labelLarge!.copyWith(
+ color: buildContext.textSecondary,
+ ),
+ ),
),
+ AppCard(
+ padding: EdgeInsets.zero,
+ child: AppTile(
+ label: user!.legacyUserData.toDate(),
+ contentPadding: EdgeInsets.only(left: 16),
+ icon: AppImagePaths.autoRenew,
+ trailing: planTrailingWidget(user, buildContext, ref)),
),
- ),
- SizedBox(height: defaultSize),
- if (isExpired)
+ SizedBox(height: defaultSize),
Padding(
padding: const EdgeInsets.only(left: 16),
child: Text(
- 'last_subscription_renewal_date'.i18n,
+ 'lantern_pro_devices'.i18n,
style: theme.labelLarge!.copyWith(
- color: AppColors.gray8,
+ color: buildContext.textSecondary,
),
),
- )
- else
+ ),
+ UserDevices(),
+ SizedBox(height: defaultSize),
+ if (appSettings.userLoggedIn)
+ AppCard(
+ padding: EdgeInsets.zero,
+ child: AppTile(
+ label: 'logout'.i18n,
+ icon: AppImagePaths.signIn,
+ onPressed: () => logoutDialog(buildContext, ref)),
+ ),
+ Spacer(),
Padding(
padding: const EdgeInsets.only(left: 16),
child: Text(
- user!.legacyUserData.subscriptionData.autoRenew
- ? 'subscription_renewal_date'.i18n
- : 'pro_account_expiration'.i18n,
+ 'danger_zone'.i18n,
style: theme.labelLarge!.copyWith(
- color: AppColors.gray8,
+ color: buildContext.textSecondary,
),
),
),
- AppCard(
- padding: EdgeInsets.zero,
- child: AppTile(
- label: user!.legacyUserData.toDate(),
- contentPadding: EdgeInsets.only(left: 16),
- icon: AppImagePaths.autoRenew,
- trailing: planTrailingWidget(user, buildContext, ref)),
- ),
- SizedBox(height: defaultSize),
- Padding(
- padding: const EdgeInsets.only(left: 16),
- child: Text(
- 'lantern_pro_devices'.i18n,
- style: theme.labelLarge!.copyWith(
- color: AppColors.gray8,
- ),
- ),
- ),
- UserDevices(),
- SizedBox(height: defaultSize),
- if (appSettings.userLoggedIn)
- AppCard(
- padding: EdgeInsets.zero,
+ Card(
child: AppTile(
- label: 'logout'.i18n,
- icon: AppImagePaths.signIn,
- onPressed: () => logoutDialog(buildContext, ref)),
- ),
- Spacer(),
- Padding(
- padding: const EdgeInsets.only(left: 16),
- child: Text(
- 'danger_zone'.i18n,
- style: theme.labelLarge!.copyWith(
- color: AppColors.gray8,
- ),
- ),
- ),
- Card(
- child: AppTile(
- contentPadding: EdgeInsets.only(left: 16),
- icon: AppImagePaths.delete,
- label: 'delete_account'.i18n,
- trailing: AppTextButton(
- label: 'delete'.i18n,
- textColor: AppColors.red7,
- onPressed: _onDeleteTap,
+ contentPadding: EdgeInsets.only(left: 16),
+ icon: AppImagePaths.delete,
+ label: 'delete_account'.i18n,
+ trailing: AppTextButton(
+ label: 'delete'.i18n,
+ textColor: buildContext.statusErrorText,
+ onPressed: _onDeleteTap,
+ ),
),
),
- ),
- SizedBox(height: defaultSize),
- ],
+ SizedBox(height: size24),
+ ],
+ ),
);
}
@@ -337,7 +339,7 @@ class Account extends HookConsumerWidget {
action: [
AppTextButton(
label: 'not_now'.i18n,
- textColor: AppColors.gray8,
+ textColor: context.textSecondary,
onPressed: () {
appRouter.pop();
},
@@ -362,7 +364,7 @@ class Account extends HookConsumerWidget {
Text(
isExpired ? 'logout_message_expired'.i18n : 'logout_message'.i18n,
style: theme.bodyMedium!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
],
diff --git a/lib/features/account/delete_account.dart b/lib/features/account/delete_account.dart
index cc7978bd4e..7d245662a6 100644
--- a/lib/features/account/delete_account.dart
+++ b/lib/features/account/delete_account.dart
@@ -48,7 +48,7 @@ class _DeleteAccountState extends ConsumerState {
child: Text(
'delete_account_message'.i18n,
style: textTheme.bodyLarge!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
),
@@ -58,7 +58,7 @@ class _DeleteAccountState extends ConsumerState {
child: Text(
'delete_account_message_two'.i18n,
style: textTheme.bodyLarge!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
),
diff --git a/lib/features/auth/add_email.dart b/lib/features/auth/add_email.dart
index 6f157003f3..22288b2adc 100644
--- a/lib/features/auth/add_email.dart
+++ b/lib/features/auth/add_email.dart
@@ -91,7 +91,7 @@ class _AddEmailState extends ConsumerState {
padding: EdgeInsets.symmetric(horizontal: defaultSize),
child: Text('lantern_pro_license_applied'.i18n,
style: textTheme!.bodyMedium!
- .copyWith(color: AppColors.gray6, fontSize: 12)),
+ .copyWith(color: context.textDisabled, fontSize: 12)),
),
SizedBox(height: defaultSize),
},
@@ -100,7 +100,7 @@ class _AddEmailState extends ConsumerState {
padding: EdgeInsets.symmetric(horizontal: defaultSize),
child: Text('change_email_message'.i18n,
style: textTheme!.bodyMedium!.copyWith(
- color: AppColors.gray6,
+ color: context.textDisabled,
)),
)
else
@@ -108,7 +108,7 @@ class _AddEmailState extends ConsumerState {
padding: EdgeInsets.symmetric(horizontal: defaultSize),
child: Text('add_your_email_message'.i18n,
style: textTheme!.bodyMedium!.copyWith(
- color: AppColors.gray6,
+ color: context.textDisabled,
)),
),
SizedBox(height: 32),
@@ -451,18 +451,18 @@ class _AddEmailState extends ConsumerState {
Text(
'email_deliverability_notice'.i18n,
style: textTheme!.headlineSmall!.copyWith(
- color: AppColors.gray9,
+ color: context.textPrimary,
),
),
SizedBox(height: defaultSize),
Text(
'email_deliverability_notice_message'.i18n,
- style: textTheme!.bodyMedium!.copyWith(color: AppColors.gray9),
+ style: textTheme!.bodyMedium!.copyWith(color: context.textPrimary),
),
SizedBox(height: defaultSize),
Text(
'email_deliverability_notice_message_two'.i18n,
- style: textTheme!.bodyMedium!.copyWith(color: AppColors.gray9),
+ style: textTheme!.bodyMedium!.copyWith(color: context.textPrimary),
),
],
),
diff --git a/lib/features/auth/choose_payment_method.dart b/lib/features/auth/choose_payment_method.dart
index 090da39e44..cdc9398f18 100644
--- a/lib/features/auth/choose_payment_method.dart
+++ b/lib/features/auth/choose_payment_method.dart
@@ -33,10 +33,7 @@ class ChoosePaymentMethod extends HookConsumerWidget {
final planData = ref.watch(plansProvider.notifier).getPlanData();
return BaseScreen(
title: '',
- appBar: CustomAppBar(
- title: Text('choose_payment_method'.i18n),
-
- ),
+ appBar: CustomAppBar(title: Text('choose_payment_method'.i18n)),
body: Column(
children: [
SizedBox(height: defaultSize),
@@ -109,7 +106,7 @@ class ChoosePaymentMethod extends HookConsumerWidget {
action: [
AppTextButton(
label: 'cancel'.i18n,
- textColor: AppColors.gray8,
+ textColor: context.textSecondary,
underLine: false,
onPressed: () {
appRouter.pop();
@@ -169,6 +166,7 @@ class ChoosePaymentMethod extends HookConsumerWidget {
/// Start stripe SDK
sl().startStripeSDK(
+ context: context,
options: StripeOptions.fromJson(stripeData),
onSuccess: () {
onPurchaseResult(true, context, ref);
@@ -334,19 +332,19 @@ class PaymentCheckoutMethods extends HookConsumerWidget {
padding: const EdgeInsets.only(bottom: 16),
child: ExpansionTile(
initiallyExpanded: index == 0,
- backgroundColor: AppColors.white,
- collapsedBackgroundColor: AppColors.white,
+ backgroundColor: context.bgElevated,
+ collapsedBackgroundColor: context.bgElevated,
collapsedShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: BorderSide(
- color: AppColors.gray3,
+ color: context.borderInput,
width: 1,
),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: BorderSide(
- color: AppColors.gray3,
+ color: context.borderInput,
width: 1,
),
),
@@ -372,7 +370,7 @@ class PaymentCheckoutMethods extends HookConsumerWidget {
Text(
'${userPlan.formattedMonthlyPrice}/month',
style: theme.bodyMedium!.copyWith(
- color: AppColors.gray6,
+ color: context.textDisabled,
),
),
],
@@ -390,7 +388,7 @@ class PaymentCheckoutMethods extends HookConsumerWidget {
Text(
'free'.i18n,
style: theme.bodyMedium!.copyWith(
- color: AppColors.gray6,
+ color: context.textDisabled,
),
),
],
@@ -402,12 +400,12 @@ class PaymentCheckoutMethods extends HookConsumerWidget {
children: [
Text('Order Total:',
style: theme.titleSmall!.copyWith(
- color: AppColors.gray9,
+ color: context.textPrimary,
)),
Text(
userPlan.formattedYearlyPrice,
style: theme.titleSmall!.copyWith(
- color: AppColors.blue10,
+ color: context.textPrimary,
),
),
],
@@ -419,7 +417,7 @@ class PaymentCheckoutMethods extends HookConsumerWidget {
? "Billed every ${userPlan.getDurationText()}. Cancel anytime."
: 'billed_once'.i18n.capitalize,
style: theme.bodySmall!.copyWith(
- color: AppColors.gray6,
+ color: context.textDisabled,
),
),
SizedBox(height: defaultSize),
diff --git a/lib/features/auth/confirm_email.dart b/lib/features/auth/confirm_email.dart
index 6e46abe55e..5f1fc15b39 100644
--- a/lib/features/auth/confirm_email.dart
+++ b/lib/features/auth/confirm_email.dart
@@ -54,7 +54,7 @@ class ConfirmEmail extends HookConsumerWidget {
child: Text(
'confirm_email_code'.i18n,
style: textTheme.labelLarge?.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
fontSize: 14.sp,
),
),
@@ -90,7 +90,7 @@ class ConfirmEmail extends HookConsumerWidget {
Center(
child: AppTextButton(
label: 'resend_email'.i18n,
- textColor: AppColors.black,
+ textColor: context.textPrimary,
onPressed: () => onResendEmail(context, ref),
),
)
diff --git a/lib/features/auth/create_password.dart b/lib/features/auth/create_password.dart
index 289c2a2db6..413af39310 100644
--- a/lib/features/auth/create_password.dart
+++ b/lib/features/auth/create_password.dart
@@ -45,7 +45,7 @@ class CreatePassword extends HookConsumerWidget {
hintText: '',
prefixIcon: AppImagePaths.lock,
label: "create_password".i18n,
- suffixIcon: _buildSuffix(obscureText),
+ suffixIcon: _buildSuffix(obscureText, context),
obscureText: obscureText.value,
onSubmitted: (_) {
if (passwordTextController.text.isPasswordValid()) {
@@ -74,9 +74,9 @@ class CreatePassword extends HookConsumerWidget {
);
}
- Widget _buildSuffix(ValueNotifier obscureText) {
+ Widget _buildSuffix(ValueNotifier obscureText, BuildContext context) {
return AppImage(
- color: AppColors.yellow9,
+ color: context.textPromoIcon,
path: obscureText.value ? AppImagePaths.eyeHide : AppImagePaths.eye,
onPressed: () {
obscureText.value = !obscureText.value;
diff --git a/lib/features/auth/device_limit_reached.dart b/lib/features/auth/device_limit_reached.dart
index 92bf3bf34c..0772287b76 100644
--- a/lib/features/auth/device_limit_reached.dart
+++ b/lib/features/auth/device_limit_reached.dart
@@ -38,7 +38,7 @@ class DeviceLimitReached extends HookConsumerWidget {
padding: const EdgeInsets.only(left: 16.0),
child: Text("lantern_pro_devices".i18n,
style: textTheme.labelLarge!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
)),
),
AppCard(
@@ -79,7 +79,7 @@ class DeviceLimitReached extends HookConsumerWidget {
Center(
child: AppTextButton(
label: 'cancel_sign_in'.i18n,
- textColor: AppColors.gray9,
+ textColor: context.textPrimary,
onPressed: () {
appRouter.popUntilRoot();
},
diff --git a/lib/features/auth/lantern_pro_license.dart b/lib/features/auth/lantern_pro_license.dart
index 15c7066d57..9f2b5f7d9d 100644
--- a/lib/features/auth/lantern_pro_license.dart
+++ b/lib/features/auth/lantern_pro_license.dart
@@ -83,7 +83,7 @@ class LanternProLicense extends HookConsumerWidget {
child: Text(
'${normalizedLen.value}/25',
style: Theme.of(context).textTheme.labelSmall?.copyWith(
- color: AppColors.gray6,
+ color: context.textDisabled,
),
),
),
diff --git a/lib/features/auth/reset_password.dart b/lib/features/auth/reset_password.dart
index c4f7288bd5..294c37a092 100644
--- a/lib/features/auth/reset_password.dart
+++ b/lib/features/auth/reset_password.dart
@@ -43,7 +43,7 @@ class ResetPassword extends HookConsumerWidget {
controller: passwordController,
prefixIcon: AppImagePaths.lock,
onChanged: (value) {},
- suffixIcon: _buildSuffix(obscureText),
+ suffixIcon: _buildSuffix(obscureText, context),
),
SizedBox(height: 20),
AppTextField(
@@ -76,7 +76,7 @@ class ResetPassword extends HookConsumerWidget {
}
return null;
},
- suffixIcon: _buildSuffix(obscureText),
+ suffixIcon: _buildSuffix(obscureText, context),
),
SizedBox(height: 32),
PrimaryButton(
@@ -96,9 +96,9 @@ class ResetPassword extends HookConsumerWidget {
);
}
- Widget _buildSuffix(ValueNotifier obscureText) {
+ Widget _buildSuffix(ValueNotifier obscureText, BuildContext context) {
return AppImage(
- color: AppColors.yellow9,
+ color: context.textPromoIcon,
path: obscureText.value ? AppImagePaths.eyeHide : AppImagePaths.eye,
onPressed: () {
obscureText.value = !obscureText.value;
@@ -138,7 +138,7 @@ class ResetPassword extends HookConsumerWidget {
action: [
AppTextButton(
label: 'continue'.i18n,
- textColor: AppColors.gray7,
+ textColor: context.textTertiary,
onPressed: () {
appRouter.popUntilRoot();
},
diff --git a/lib/features/auth/sign_in_password.dart b/lib/features/auth/sign_in_password.dart
index 485bbf0146..4e44501fa1 100644
--- a/lib/features/auth/sign_in_password.dart
+++ b/lib/features/auth/sign_in_password.dart
@@ -59,23 +59,22 @@ class _SignInPasswordState extends ConsumerState {
signInWithPassword(passwordController.text.trim()),
onChanged: (value) {},
),
- SizedBox(height: 4),
+ SizedBox(height: 8),
if (!widget.fromChangeEmail)
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: defaultSize),
- child: Text(
- 'if_you_have_not_set_password'.i18n,
- textAlign: TextAlign.start,
- style: textTheme.labelMedium!.copyWith(
- color: AppColors.gray6,
- ),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: defaultSize),
+ child: Text(
+ 'if_you_have_not_set_password'.i18n,
+ textAlign: TextAlign.start,
+ style: textTheme.labelMedium!.copyWith(
+ color: context.textDisabled,
),
- ),
+ )),
SizedBox(height: 16),
if (widget.fromChangeEmail)
Text('confirm_password_to_continue'.i18n,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
)),
SizedBox(height: 32),
PrimaryButton(
@@ -90,7 +89,7 @@ class _SignInPasswordState extends ConsumerState {
SizedBox(height: 32),
AppTextButton(
label: 'forgot_password'.i18n,
- textColor: AppColors.gray9,
+ textColor: context.textPrimary,
onPressed: () {
appRouter.push(ResetPasswordEmail(email: widget.email));
},
@@ -104,7 +103,7 @@ class _SignInPasswordState extends ConsumerState {
Widget _buildSuffix(ValueNotifier obscureText) {
return AppImage(
- color: AppColors.yellow9,
+ color: context.textPrimary,
path: obscureText.value ? AppImagePaths.eyeHide : AppImagePaths.eye,
onPressed: () {
obscureText.value = !obscureText.value;
diff --git a/lib/features/home/data_usage.dart b/lib/features/home/data_usage.dart
index 2dd835d2a4..754b237775 100644
--- a/lib/features/home/data_usage.dart
+++ b/lib/features/home/data_usage.dart
@@ -85,8 +85,8 @@ class DataUsage extends ConsumerWidget {
: 'daily_data_usage'.i18n,
style: textTheme.labelLarge!.copyWith(
color: isDataCapReached
- ? AppColors.red8
- : AppColors.gray7,
+ ? context.statusErrorBg
+ : context.textTertiary,
),
),
Spacer(),
@@ -94,7 +94,7 @@ class DataUsage extends ConsumerWidget {
Text(
'$usageString${'mb'.i18n}',
style: textTheme.titleSmall!.copyWith(
- color: AppColors.gray9,
+ color: context.textPrimary,
),
),
],
@@ -108,7 +108,7 @@ class DataUsage extends ConsumerWidget {
maxFontSize: 12,
maxLines: 1,
style: textTheme.bodySmall!.copyWith(
- color: AppColors.red8,
+ color: context.statusErrorBg,
),
),
),
@@ -118,7 +118,7 @@ class DataUsage extends ConsumerWidget {
shape: RoundedRectangleBorder(
side: isDataCapReached
? BorderSide.none
- : BorderSide(width: 1, color: AppColors.gray3),
+ : BorderSide(width: 1, color: context.borderInput),
borderRadius: BorderRadius.circular(8),
),
),
@@ -134,9 +134,9 @@ class DataUsage extends ConsumerWidget {
Radius.circular(defaultSize),
),
trackGap: 10,
- backgroundColor: AppColors.gray1,
+ backgroundColor: context.bgSurface,
valueColor: AlwaysStoppedAnimation(
- isDataCapReached ? AppColors.red6 : AppColors.yellow3,
+ isDataCapReached ? context.borderError : AppColors.yellow3,
),
),
),
diff --git a/lib/features/home/home.dart b/lib/features/home/home.dart
index 3ad13717dd..811d16978f 100644
--- a/lib/features/home/home.dart
+++ b/lib/features/home/home.dart
@@ -90,8 +90,7 @@ class _HomeState extends ConsumerState {
ref.read(appEventProvider);
return Scaffold(
appBar: AppBar(
- backgroundColor: AppColors.white,
- title: LanternLogo(isPro: isUserPro),
+ title: LanternLogo(isPro: isUserPro,color: context.textPrimary,),
bottom: PreferredSize(
preferredSize: Size.fromHeight(0),
child: DividerSpace(padding: EdgeInsets.zero),
@@ -264,31 +263,31 @@ class _HomeState extends ConsumerState {
SizedBox(height: 24),
Text(
'help_improve_lantern'.i18n,
- style: textTheme!.headlineSmall!.copyWith(color: AppColors.gray9),
+ style: textTheme!.headlineSmall!.copyWith(color: context.textPrimary),
),
SizedBox(height: defaultSize),
Text(
'share_anonymous_usage_data'.i18n,
- style: textTheme!.bodyMedium!.copyWith(color: AppColors.gray8),
+ style: textTheme!.bodyMedium!.copyWith(color: context.textSecondary),
),
SizedBox(height: defaultSize),
Text(
'data_we_collect'.i18n,
style: AppTextStyles.bodyMediumBold.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
SizedBox(height: defaultSize),
Text(
'you_can_change_anytime'.i18n,
- style: textTheme!.bodyMedium!.copyWith(color: AppColors.gray8),
+ style: textTheme!.bodyMedium!.copyWith(color: context.textSecondary),
),
],
),
action: [
AppTextButton(
label: 'dont_allow'.i18n,
- textColor: AppColors.gray6,
+ textColor: context.textDisabled,
onPressed: () {
context.pop();
ref
diff --git a/lib/features/home/provider/app_setting_notifier.dart b/lib/features/home/provider/app_setting_notifier.dart
index f75e90cbce..b922acb553 100644
--- a/lib/features/home/provider/app_setting_notifier.dart
+++ b/lib/features/home/provider/app_setting_notifier.dart
@@ -10,6 +10,7 @@ import 'package:lantern/core/utils/storage_utils.dart';
import 'package:lantern/lantern/lantern_service.dart';
import 'package:lantern/lantern/lantern_service_notifier.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
+import 'package:window_manager/window_manager.dart';
part 'app_setting_notifier.g.dart';
@@ -20,14 +21,33 @@ class AppSettingNotifier extends _$AppSettingNotifier {
@override
AppSetting build() {
_db = sl();
+ final setting = _db.getAppSetting();
+
+ if (setting != null && setting.locale.isNotEmpty) {
+ updateToolbarThemeMode();
+ return setting;
+ }
+ // First-time user → use device locale
// First-time user or DB was wiped after env switch → use device locale
final fallback = _detectDeviceLocale();
final initial = AppSetting(locale: fallback.toString());
_db.updateAppSetting(initial);
+ updateToolbarThemeMode();
_detectEnvironmentFromFile();
return initial;
}
+ void updateToolbarThemeMode() {
+ final setting = _db.getAppSetting();
+ final mode = setting?.themeMode ?? 'system';
+ final modeEnum = resolveThemeMode(mode);
+ if (modeEnum == ThemeMode.system || modeEnum == ThemeMode.light) {
+ windowManager.setBrightness(Brightness.light);
+ } else {
+ windowManager.setBrightness(Brightness.dark);
+ }
+ }
+
Future update(AppSetting updated) async {
state = updated;
_db.updateAppSetting(updated);
@@ -111,6 +131,19 @@ class AppSettingNotifier extends _$AppSettingNotifier {
update(state.copyWith(onboardingCompleted: value));
}
+ void setThemeMode(String mode) {
+ update(state.copyWith(themeMode: mode));
+ if (PlatformUtils.isDesktop) {
+ final modeEnum = resolveThemeMode(mode);
+ if (modeEnum == ThemeMode.system || modeEnum == ThemeMode.light) {
+ windowManager.setBrightness(Brightness.light);
+ } else {
+ windowManager.setBrightness(Brightness.dark);
+ }
+ }
+ }
+
+
Future setEnvironment(bool isStaging) async {
final env = isStaging ? 'stage' : 'prod';
update(state.copyWith(environment: env));
diff --git a/lib/features/home/provider/app_setting_notifier.g.dart b/lib/features/home/provider/app_setting_notifier.g.dart
index 02ac8fb3d5..5b2f2c05cf 100644
--- a/lib/features/home/provider/app_setting_notifier.g.dart
+++ b/lib/features/home/provider/app_setting_notifier.g.dart
@@ -42,7 +42,7 @@ final class AppSettingNotifierProvider
}
String _$appSettingNotifierHash() =>
- r'49e35afce80b0b7b25c62d647cdf3924ee6cc49a';
+ r'355d669c54fd042f337506102347b94dcf12c03f';
abstract class _$AppSettingNotifier extends $Notifier {
AppSetting build();
diff --git a/lib/features/home/provider/home_notifier.g.dart b/lib/features/home/provider/home_notifier.g.dart
index c36c756f93..ac185b25bf 100644
--- a/lib/features/home/provider/home_notifier.g.dart
+++ b/lib/features/home/provider/home_notifier.g.dart
@@ -33,7 +33,7 @@ final class HomeNotifierProvider
HomeNotifier create() => HomeNotifier();
}
-String _$homeNotifierHash() => r'8c1c7e93ef15d1bc9bb6a7adf7422e93423294b8';
+String _$homeNotifierHash() => r'acb597e5a3f386fddf86e5b3f3af742ffa93e2c7';
abstract class _$HomeNotifier extends $AsyncNotifier {
FutureOr build();
diff --git a/lib/features/language/language.dart b/lib/features/language/language.dart
index 243bcee5ff..dc8bdcfb0f 100644
--- a/lib/features/language/language.dart
+++ b/lib/features/language/language.dart
@@ -74,14 +74,13 @@ class LanguageListView extends HookConsumerWidget {
AppTile(
label: displayLanguage(langCode),
onPressed: () => onLanguageTap(langCode),
- trailing: Radio(
- materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+ trailing: AppRadioButton(
value: langCode,
groupValue: locale.toString(),
onChanged: (value) {
onLanguageTap(value!);
},
- activeColor: AppColors.blue7,
+ // activeColor: AppColors.blue7,
),
minHeight: 56,
),
diff --git a/lib/features/logs/log_line.dart b/lib/features/logs/log_line.dart
index eccfb24f5d..fff26b2bec 100644
--- a/lib/features/logs/log_line.dart
+++ b/lib/features/logs/log_line.dart
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
+import 'package:lantern/core/common/app_semantic_colors.dart';
import 'package:lantern/core/common/app_text_styles.dart';
import 'package:lantern/features/logs/parsed_log.dart';
@@ -15,7 +16,7 @@ class LogLineWidget extends StatelessWidget {
return Text(
line,
style: AppTextStyles.monospace(
- color: Colors.white,
+ color: context.textPrimary,
),
);
}
diff --git a/lib/features/logs/logs.dart b/lib/features/logs/logs.dart
index d7f198c0a7..0b5189a2a4 100644
--- a/lib/features/logs/logs.dart
+++ b/lib/features/logs/logs.dart
@@ -80,9 +80,9 @@ class Logs extends HookConsumerWidget {
Expanded(
child: Container(
decoration: ShapeDecoration(
- color: AppColors.black1,
+ color: context.bgElevated,
shape: RoundedRectangleBorder(
- side: BorderSide(width: 1),
+ side: BorderSide(width: 1,color: context.borderDefault),
borderRadius: BorderRadius.circular(16),
),
),
diff --git a/lib/features/macos_extension/macos_extension_dialog.dart b/lib/features/macos_extension/macos_extension_dialog.dart
index a6f3e91587..5c9643ab27 100644
--- a/lib/features/macos_extension/macos_extension_dialog.dart
+++ b/lib/features/macos_extension/macos_extension_dialog.dart
@@ -54,7 +54,7 @@ class _MacOSExtensionDialogState extends ConsumerState {
actions: [
CloseButton(),
],
- backgroundColor: AppColors.white,
+ backgroundColor: context.bgElevated,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
@@ -62,7 +62,7 @@ class _MacOSExtensionDialogState extends ConsumerState {
AppImage(path: AppImagePaths.sysDialog),
const SizedBox(height: 48.0),
Text('enable_network_extension'.i18n,
- style: textTheme.headlineSmall!.copyWith(color: AppColors.gray8),
+ style: textTheme.headlineSmall!.copyWith(color: context.textSecondary),
textAlign: TextAlign.center),
const SizedBox(height: 16.0),
Padding(
@@ -70,21 +70,21 @@ class _MacOSExtensionDialogState extends ConsumerState {
child: Text(
'enable_network_extension_message'.i18n,
style: textTheme.bodyLarge!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
),
const SizedBox(height: 16.0),
RichText(
text: TextSpan(
- style: textTheme.bodyLarge!.copyWith(color: AppColors.gray7),
+ style: textTheme.bodyLarge!.copyWith(color: context.textTertiary),
children: [
TextSpan(text: 'click'.i18n),
WidgetSpan(child: SizedBox(width: 4.0)),
TextSpan(
text: 'open_system_settings'.i18n,
style: AppTextStyles.bodyLargeBold.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
WidgetSpan(child: SizedBox(width: 4.0)),
diff --git a/lib/features/onboarding/onboarding.dart b/lib/features/onboarding/onboarding.dart
index 46a7adf4b0..49bb8a9de8 100644
--- a/lib/features/onboarding/onboarding.dart
+++ b/lib/features/onboarding/onboarding.dart
@@ -45,15 +45,15 @@ class _OnboardingState extends ConsumerState {
return Scaffold(
appBar: AppBar(
leading: const SizedBox.shrink(),
- backgroundColor: AppColors.white,
- title: const LanternLogo(),
+ backgroundColor: context.bgElevated,
+ title: LanternLogo(color: context.textPrimary),
bottom: PreferredSize(
preferredSize: Size.fromHeight(0),
child: DividerSpace(padding: EdgeInsets.zero),
),
),
body: Container(
- color: AppColors.white,
+ color: context.bgElevated,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: SafeArea(
child: Column(
@@ -76,7 +76,7 @@ class _OnboardingState extends ConsumerState {
itemSpacing: 15,
indicatorBorderWidth: 0.0,
currentIndicatorColor: AppColors.blue3,
- indicatorBackgroundColor: AppColors.gray3,
+ indicatorBackgroundColor: context.borderInput,
enableAnimation: true,
padding: EdgeInsets.only(bottom: 10.0),
alignment: Alignment.bottomCenter,
@@ -91,13 +91,14 @@ class _OnboardingState extends ConsumerState {
children: [
AppImage(
path: AppImagePaths.appIconSVG,
+ useThemeColor: false,
),
SizedBox(height: 48),
Text(
'welcome_to_lantern'.i18n,
style: textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.bold,
- color: AppColors.gray8),
+ color: context.textSecondary),
),
SizedBox(height: 16),
Text('lantern_pro_tagline'.i18n)
@@ -128,7 +129,7 @@ class _OnboardingState extends ConsumerState {
SizedBox(height: 12.0),
AppTextButton(
label: 'skip_connect_now'.i18n,
- textColor: AppColors.gray9,
+ textColor: context.textPrimary,
onPressed: () {
onboardingCompleted();
},
@@ -150,34 +151,34 @@ class _OnboardingState extends ConsumerState {
Text(
'what_makes_lantern_different'.i18n,
style: textTheme.headlineSmall!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
SizedBox(height: 8.0),
Text(
'built_for_privacy_speed_freedom'.i18n,
style: textTheme.bodyLarge!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
SizedBox(height: 24.0),
AppTile(
icon: Padding(
padding: const EdgeInsets.only(top: 5.0),
- child: AppImage(path: AppImagePaths.smartRouteMode),
+ child: AppImage(path: AppImagePaths.smartRouteMode,useThemeColor: false,),
),
label: '',
titleAlignment: ListTileTitleAlignment.top,
labelWidget: Text(
'smart_routing_mode'.i18n,
style: textTheme.titleMedium!.copyWith(
- color: AppColors.black,
+ color: context.textPrimary,
),
),
subtitle: Text(
'region_specific_routing_description'.i18n,
style: textTheme.bodyMedium!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
),
@@ -185,20 +186,20 @@ class _OnboardingState extends ConsumerState {
AppTile(
icon: Padding(
padding: const EdgeInsets.only(top: 5.0),
- child: AppImage(path: AppImagePaths.advanceProtocol),
+ child: AppImage(path: AppImagePaths.advanceProtocol,useThemeColor: false),
),
label: '',
titleAlignment: ListTileTitleAlignment.top,
labelWidget: Text(
'advanced_protocols'.i18n,
style: textTheme.titleMedium!.copyWith(
- color: AppColors.black,
+ color: context.textPrimary,
),
),
subtitle: Text(
'advanced_protocols_description'.i18n,
style: textTheme.bodyMedium!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
),
@@ -206,20 +207,20 @@ class _OnboardingState extends ConsumerState {
AppTile(
icon: Padding(
padding: const EdgeInsets.only(top: 5.0),
- child: AppImage(path: AppImagePaths.privateServerIntro),
+ child: AppImage(path: AppImagePaths.privateServerIntro,useThemeColor: false),
),
label: '',
titleAlignment: ListTileTitleAlignment.top,
labelWidget: Text(
'private_servers'.i18n,
style: textTheme.titleMedium!.copyWith(
- color: AppColors.black,
+ color: context.textPrimary,
),
),
subtitle: Text(
'private_servers_description'.i18n,
style: textTheme.bodyMedium!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
),
@@ -227,20 +228,20 @@ class _OnboardingState extends ConsumerState {
AppTile(
icon: Padding(
padding: const EdgeInsets.only(top: 5.0),
- child: AppImage(path: AppImagePaths.nonProfit),
+ child: AppImage(path: AppImagePaths.nonProfit,useThemeColor: false),
),
label: '',
titleAlignment: ListTileTitleAlignment.top,
labelWidget: Text(
'nonprofit_mission'.i18n,
style: textTheme.titleMedium!.copyWith(
- color: AppColors.black,
+ color: context.textPrimary,
),
),
subtitle: Text(
'built_by_nonprofit'.i18n,
style: textTheme.bodyMedium!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
),
@@ -284,7 +285,7 @@ class _OnboardingState extends ConsumerState {
Text(
'choose_your_routing_mode'.i18n,
style: textTheme.headlineSmall!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
SizedBox(height: 24.0),
@@ -328,11 +329,11 @@ class RouteModeContainer extends StatelessWidget {
duration: Duration(milliseconds: 250),
padding: EdgeInsets.all(16.0),
decoration: BoxDecoration(
- color: isSelected ? AppColors.blue1 : AppColors.gray1,
+ color: isSelected ? context.bgHover : context.bgElevated,
borderRadius: BorderRadius.circular(16.0),
border: isSelected
- ? Border.all(color: AppColors.blue7, width: 3.0)
- : Border.all(color: AppColors.gray2, width: 1.0),
+ ? Border.all(color: context.borderInputFocus, width: 3.0)
+ : Border.all(color: context.borderDefault, width: 1.0),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -347,7 +348,7 @@ class RouteModeContainer extends StatelessWidget {
Text(
title(),
style: textTheme.titleMedium!.copyWith(
- color: AppColors.black,
+ color: context.textPrimary,
),
),
SizedBox(width: 8.0),
@@ -356,13 +357,13 @@ class RouteModeContainer extends StatelessWidget {
EdgeInsets.symmetric(horizontal: 10.0, vertical: 3.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
- border: Border.all(color: AppColors.blue4),
- color: AppColors.blue2,
+ border: Border.all(color: context.statusInfoBorder),
+ color: context.statusInfoBg,
),
child: Text(
tags(),
style:
- textTheme.labelMedium!.copyWith(color: AppColors.blue8),
+ textTheme.labelMedium!.copyWith(color: context.statusInfoText),
))
],
),
@@ -370,7 +371,7 @@ class RouteModeContainer extends StatelessWidget {
Padding(
padding: const EdgeInsets.only(left: 38),
child: Text(description(),
- style: textTheme.bodyMedium!.copyWith(color: AppColors.gray8)),
+ style: textTheme.bodyMedium!.copyWith(color: context.textSecondary)),
)
],
),
diff --git a/lib/features/plans/feature_list.dart b/lib/features/plans/feature_list.dart
index f363a91052..199d4491ed 100644
--- a/lib/features/plans/feature_list.dart
+++ b/lib/features/plans/feature_list.dart
@@ -53,7 +53,7 @@ class _FeatureTile extends StatelessWidget {
children: [
AppImage(
path: image,
- color: AppColors.blue10,
+ color: context.textPrimary,
height: 24,
),
SizedBox(width: defaultSize),
diff --git a/lib/features/plans/plan_item.dart b/lib/features/plans/plan_item.dart
index 72a0e7d19d..56d4a1da44 100644
--- a/lib/features/plans/plan_item.dart
+++ b/lib/features/plans/plan_item.dart
@@ -2,7 +2,6 @@ import 'package:badges/badges.dart' as badges;
import 'package:flutter/material.dart';
import 'package:lantern/core/extensions/plan.dart';
import 'package:lantern/core/models/plan_data.dart';
-import 'package:lantern/core/utils/decoration.dart';
import '../../core/common/common.dart';
@@ -35,16 +34,16 @@ class PlanItem extends StatelessWidget {
badgeStyle: badges.BadgeStyle(
shape: badges.BadgeShape.square,
borderSide: BorderSide(
- color: AppColors.yellow4,
+ color: context.statusWarningText,
width: 1,
),
borderRadius: BorderRadius.circular(16),
- badgeColor: AppColors.yellow3,
+ badgeColor: context.statusWarningBgDot,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 6),
),
badgeContent: Text(
'best_value'.i18n,
- style: textTheme.labelMedium,
+ style: textTheme.labelMedium!,
),
child: GestureDetector(
onTap: () {
@@ -54,7 +53,7 @@ class PlanItem extends StatelessWidget {
margin: EdgeInsets.only(top: 16),
padding: EdgeInsets.symmetric(horizontal: defaultSize, vertical: 12),
duration: Duration(milliseconds: 300),
- decoration: planSelected ? selectedDecoration : unselectedDecoration,
+ decoration: getPlanDecoration(planSelected, context),
child: Row(
children: [
Column(
@@ -62,7 +61,9 @@ class PlanItem extends StatelessWidget {
children: [
Text(
plan.description.toTitleCase(),
- style: textTheme.titleMedium,
+ style: textTheme.titleMedium!.copyWith(
+ color: context.textPrimary,
+ ),
),
if (referralMessage.isNotEmpty)
Text(
@@ -78,13 +79,13 @@ class PlanItem extends StatelessWidget {
Text(
plan.formattedYearlyPrice,
style: textTheme.titleMedium!.copyWith(
- color: AppColors.blue7,
+ color: context.textLink,
),
),
Text(
'${plan.formattedMonthlyPrice}/month',
style: textTheme.labelMedium!.copyWith(
- color: AppColors.gray7,
+ color: context.textTertiary,
),
),
],
@@ -92,7 +93,7 @@ class PlanItem extends StatelessWidget {
Radio(
value: true,
groupValue: planSelected,
- fillColor: WidgetStatePropertyAll(AppColors.gray9),
+ fillColor: WidgetStatePropertyAll(context.textPrimary),
onChanged: (value) {
onPressed.call(plan);
},
@@ -103,4 +104,15 @@ class PlanItem extends StatelessWidget {
),
);
}
+
+ BoxDecoration getPlanDecoration(bool isSelected, BuildContext context) {
+ return BoxDecoration(
+ color: isSelected ? context.bgHover : context.bgElevated,
+ border: Border.all(
+ color: isSelected ? context.textLink : context.borderInput,
+ width: isSelected ? 3 : 1.5,
+ ),
+ borderRadius: BorderRadius.circular(16),
+ );
+ }
}
diff --git a/lib/features/plans/plans.dart b/lib/features/plans/plans.dart
index 41a57df896..615fd0cf25 100644
--- a/lib/features/plans/plans.dart
+++ b/lib/features/plans/plans.dart
@@ -38,17 +38,17 @@ class _PlansState extends ConsumerState {
Widget build(BuildContext context) {
textTheme = Theme.of(context).textTheme;
return BaseScreen(
- backgroundColor: AppColors.white,
+ backgroundColor: context.bgElevated,
padded: false,
appBar: CustomAppBar(
title: SizedBox(
height: 20.h,
child: LanternLogo(
- color: AppColors.gray9,
+ color: context.textPrimary,
isPro: true,
),
),
- backgroundColor: AppColors.white,
+ backgroundColor: context.bgElevated,
leading: IconButton(
icon: Icon(Icons.close),
onPressed: () {
@@ -63,7 +63,10 @@ class _PlansState extends ConsumerState {
],
),
title: "",
- body: SafeArea(child: _buildBody()),
+ body: SafeArea(
+ bottom: !PlatformUtils.isIOS,
+ child: _buildBody(),
+ ),
);
}
@@ -84,7 +87,7 @@ class _PlansState extends ConsumerState {
DividerSpace(padding: EdgeInsets.zero),
Expanded(
child: Container(
- color: AppColors.gray1,
+ color: context.bgSurface,
padding: EdgeInsets.symmetric(
horizontal: context.isSmallDevice ? 0 : defaultSize),
child: Column(
@@ -139,7 +142,7 @@ class _PlansState extends ConsumerState {
child: Text(
'subscription_renewal_info'.i18n,
style: textTheme.labelMedium!.copyWith(
- color: AppColors.gray7,
+ color: context.textTertiary,
),
),
),
@@ -150,7 +153,7 @@ class _PlansState extends ConsumerState {
AppTextButton(
label: 'privacy_policy'.i18n,
fontSize: 12,
- textColor: AppColors.gray7,
+ textColor: context.textTertiary,
onPressed: () {
UrlUtils.openWithSystemBrowser(
AppUrls.privacyPolicy);
@@ -163,7 +166,7 @@ class _PlansState extends ConsumerState {
AppTextButton(
label: 'terms_of_service'.i18n,
fontSize: 12,
- textColor: AppColors.gray7,
+ textColor: context.textTertiary,
onPressed: () {
UrlUtils.openWithSystemBrowser(
AppUrls.termsOfService);
@@ -239,7 +242,7 @@ class _PlansState extends ConsumerState {
SizedBox(height: defaultSize),
Text('referral_code'.i18n,
style: textTheme.headlineSmall!.copyWith(
- color: AppColors.gray9,
+ color: context.textPrimary,
)),
SizedBox(height: 24),
AppTextField(
@@ -257,7 +260,7 @@ class _PlansState extends ConsumerState {
AppTextButton(
label: 'cancel'.i18n,
underLine: false,
- textColor: AppColors.gray6,
+ textColor: context.textDisabled,
onPressed: () {
appRouter.pop();
},
diff --git a/lib/features/plans/provider/payment_notifier.g.dart b/lib/features/plans/provider/payment_notifier.g.dart
index f30196ea47..b999fa1da0 100644
--- a/lib/features/plans/provider/payment_notifier.g.dart
+++ b/lib/features/plans/provider/payment_notifier.g.dart
@@ -41,7 +41,7 @@ final class PaymentNotifierProvider
}
}
-String _$paymentNotifierHash() => r'4348c0acda395c71a0951848746f98000316ef0f';
+String _$paymentNotifierHash() => r'593bf59110bb4eb70a843d440467573d9b5bb5cd';
abstract class _$PaymentNotifier extends $Notifier {
void build();
diff --git a/lib/features/private_server/join_private_server.dart b/lib/features/private_server/join_private_server.dart
index ee26ee3ba3..5bbab35be5 100644
--- a/lib/features/private_server/join_private_server.dart
+++ b/lib/features/private_server/join_private_server.dart
@@ -56,7 +56,7 @@ class _JoinPrivateServerState extends ConsumerState {
child: Column(children: [
// SizedBox(height: 16),
InfoRow(
- backgroundColor: AppColors.yellow1,
+ backgroundColor: context.bgPromo,
showLeadingIcon: false,
text: '',
child: Row(
@@ -106,7 +106,7 @@ class _JoinPrivateServerState extends ConsumerState {
child: Text(
"how_server_appears".i18n,
style: textTheme.labelMedium!.copyWith(
- color: AppColors.gray6,
+ color: context.textDisabled,
),
),
),
@@ -185,7 +185,7 @@ class _JoinPrivateServerState extends ConsumerState {
AppImage(
path: AppImagePaths.security,
height: 40,
- color: AppColors.gray9,
+ color: context.textPrimary,
),
SizedBox(height: 16),
Text(
@@ -273,7 +273,7 @@ class _JoinPrivateServerState extends ConsumerState {
onPressed: () {
appRouter.popUntilRoot();
},
- textColor: AppColors.gray6,
+ textColor: context.textDisabled,
),
AppTextButton(
label: "go_to_server_locations".i18n,
diff --git a/lib/features/private_server/manage_private_server.dart b/lib/features/private_server/manage_private_server.dart
index e197d0d2c1..cc68bf1833 100644
--- a/lib/features/private_server/manage_private_server.dart
+++ b/lib/features/private_server/manage_private_server.dart
@@ -52,7 +52,7 @@ class _ManagePrivateServerState extends ConsumerState {
unselectedLabelColor: Colors.grey,
labelStyle: textTheme!.titleSmall,
indicator: BoxDecoration(
- color: AppColors.blue2,
+ color: context.textLink,
borderRadius: BorderRadius.circular(40),
shape: BoxShape.rectangle,
border: Border.all(color: AppColors.blue3, width: 1),
@@ -110,7 +110,7 @@ class _ManagePrivateServerState extends ConsumerState {
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
- icon: Icon(Icons.delete_outline, color: AppColors.gray9),
+ icon: Icon(Icons.delete_outline, color: context.textPrimary),
iconSize: 24,
onPressed: () => showDeleteDialog(item.serverName),
),
@@ -123,9 +123,9 @@ class _ManagePrivateServerState extends ConsumerState {
label: 'share_access_key'.i18n,
bgColor: AppColors.blue1,
icon: AppImagePaths.shareV2,
- iconColor: AppColors.gray9,
+ iconColor: context.textPrimary,
showBorder: true,
- textColor: AppColors.gray9,
+ textColor: context.textPrimary,
onPressed: () => onTapShareAccessKey(item)),
SizedBox(height: 16),
}
@@ -181,7 +181,7 @@ class _ManagePrivateServerState extends ConsumerState {
action: [
AppTextButton(
label: 'cancel'.i18n,
- textColor: AppColors.gray6,
+ textColor: context.textDisabled,
onPressed: () {
appRouter.pop();
},
@@ -253,7 +253,7 @@ class _ManagePrivateServerState extends ConsumerState {
action: [
AppTextButton(
label: 'cancel',
- textColor: AppColors.gray6,
+ textColor: context.textDisabled,
onPressed: () {
appRouter.pop();
},
@@ -292,7 +292,7 @@ class _ManagePrivateServerState extends ConsumerState {
action: [
AppTextButton(
label: 'cancel'.i18n,
- textColor: AppColors.gray6,
+ textColor: context.textDisabled,
onPressed: () {
appRouter.pop();
},
diff --git a/lib/features/private_server/manually_server_setup.dart b/lib/features/private_server/manually_server_setup.dart
index 9cfd9fd607..b79b80cf6c 100644
--- a/lib/features/private_server/manually_server_setup.dart
+++ b/lib/features/private_server/manually_server_setup.dart
@@ -6,7 +6,6 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:lantern/core/common/common.dart';
import 'package:lantern/core/models/entity/private_server_entity.dart';
-import 'package:lantern/core/models/private_server_status.dart';
import 'package:lantern/features/private_server/provider/private_server_notifier.dart';
import '../../core/services/injection_container.dart';
@@ -62,7 +61,6 @@ class _ManuallyServerSetupState extends ConsumerState {
SizedBox(height: 16),
PrimaryButton(
icon: AppImagePaths.github,
- iconColor: AppColors.white,
isTaller: true,
label: 'view_instructions_github'.i18n,
onPressed: () {
@@ -99,7 +97,7 @@ class _ManuallyServerSetupState extends ConsumerState {
child: Text(
"how_server_appears".i18n,
style: textTheme.labelMedium!.copyWith(
- color: AppColors.gray6,
+ color: context.textDisabled,
),
),
),
@@ -225,7 +223,7 @@ class _ManuallyServerSetupState extends ConsumerState {
onPressed: () {
appRouter.popUntilRoot();
},
- textColor: AppColors.gray6,
+ textColor: context.textDisabled,
),
AppTextButton(
label: "connect_now".i18n,
diff --git a/lib/features/private_server/private_server_add_billing.dart b/lib/features/private_server/private_server_add_billing.dart
index f189e8272f..c55a8a8810 100644
--- a/lib/features/private_server/private_server_add_billing.dart
+++ b/lib/features/private_server/private_server_add_billing.dart
@@ -70,7 +70,7 @@ class PrivateServerAddBilling extends HookConsumerWidget {
Center(
child: AppImage(
path: AppImagePaths.creditCard,
- color: AppColors.gray9,
+ color: context.textPrimary,
height: 30,
),
),
@@ -87,14 +87,14 @@ class PrivateServerAddBilling extends HookConsumerWidget {
textAlign: TextAlign.left,
text: TextSpan(
style:
- textTheme.bodyMedium!.copyWith(color: AppColors.gray8),
+ textTheme.bodyMedium!.copyWith(color: context.textSecondary),
text: '${'1'.i18n}. ',
children: [
TextSpan(text: '${'tap'.i18n} '),
TextSpan(
text: '${'open_system_settings'.i18n} ',
style: AppTextStyles.bodyMediumBold!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
)),
TextSpan(text: 'below_to_go_to_do'.i18n),
],
@@ -104,7 +104,7 @@ class PrivateServerAddBilling extends HookConsumerWidget {
RichText(
text: TextSpan(
style:
- textTheme.bodyMedium!.copyWith(color: AppColors.gray8),
+ textTheme.bodyMedium!.copyWith(color: context.textSecondary),
text: '${'2'.i18n}. ',
children: [
TextSpan(text: '${'add_payment_method'.i18n} '),
@@ -115,7 +115,7 @@ class PrivateServerAddBilling extends HookConsumerWidget {
RichText(
text: TextSpan(
style:
- textTheme.bodyMedium!.copyWith(color: AppColors.gray8),
+ textTheme.bodyMedium!.copyWith(color: context.textSecondary),
text: '${'3'.i18n}. ',
children: [
TextSpan(text: '${'return_to_lantern'.i18n} '),
@@ -130,7 +130,7 @@ class PrivateServerAddBilling extends HookConsumerWidget {
PrimaryButton(
isTaller: true,
icon: AppImagePaths.outsideBrowser,
- iconColor: AppColors.white,
+ iconColor: context.textInverse,
label: 'open_system_settings'.i18n,
onPressed: () {
UrlUtils.openUrl(AppUrls.digitalOceanBillingUrl);
diff --git a/lib/features/private_server/private_server_deploy.dart b/lib/features/private_server/private_server_deploy.dart
index 61e84c4767..914e97e3c7 100644
--- a/lib/features/private_server/private_server_deploy.dart
+++ b/lib/features/private_server/private_server_deploy.dart
@@ -69,7 +69,7 @@ class _PrivateServerDeployState extends ConsumerState {
child: Text(
'private_server_setup_in_progress'.i18n,
style: textTheme!.bodyLarge!.copyWith(
- color: AppColors.gray8,
+ color: context.textSecondary,
),
),
),
@@ -106,7 +106,7 @@ class _PrivateServerDeployState extends ConsumerState {
SizedBox(height: 16),
Text(
'private_server_ready_message'.i18n.fill([widget.serverName]),
- style: textTheme!.bodyMedium!.copyWith(color: AppColors.gray8),
+ style: textTheme!.bodyMedium!.copyWith(color: context.textSecondary),
),
],
),
@@ -116,7 +116,7 @@ class _PrivateServerDeployState extends ConsumerState {
onPressed: () {
appRouter.popUntilRoot();
},
- textColor: AppColors.gray6,
+ textColor: context.textDisabled,
),
AppTextButton(
label: "go_to_server_locations".i18n,
@@ -149,7 +149,7 @@ class _PrivateServerDeployState extends ConsumerState