diff --git a/lib/core/theme/app_theme.dart b/lib/core/theme/app_theme.dart index 3ad06df..55ecc3b 100644 --- a/lib/core/theme/app_theme.dart +++ b/lib/core/theme/app_theme.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; import 'package:lazurite/core/theme/catppuccin_theme.dart'; +import 'package:lazurite/core/theme/lazurite_theme.dart'; import 'package:lazurite/core/theme/nord_theme.dart'; import 'package:lazurite/core/theme/oxocarbon_theme.dart'; import 'package:lazurite/core/theme/rose_pine_theme.dart'; -enum AppThemePalette { oxocarbon, catppuccin, nord, rosePine } +enum AppThemePalette { lazurite, oxocarbon, catppuccin, nord, rosePine } enum AppThemeVariant { light, dark } @@ -13,6 +14,8 @@ class AppTheme { static ThemeData getTheme(AppThemePalette palette, AppThemeVariant variant) { switch (palette) { + case AppThemePalette.lazurite: + return variant == AppThemeVariant.light ? LazuriteTheme.light() : LazuriteTheme.dark(); case AppThemePalette.oxocarbon: return variant == AppThemeVariant.light ? OxocarbonTheme.light() : OxocarbonTheme.dark(); case AppThemePalette.catppuccin: @@ -26,6 +29,8 @@ class AppTheme { static String getPaletteName(AppThemePalette palette) { switch (palette) { + case AppThemePalette.lazurite: + return 'Lazurite'; case AppThemePalette.oxocarbon: return 'Oxocarbon'; case AppThemePalette.catppuccin: @@ -48,6 +53,8 @@ class AppTheme { static AppThemePalette parsePalette(String? value) { switch (value) { + case 'lazurite': + return AppThemePalette.lazurite; case 'oxocarbon': return AppThemePalette.oxocarbon; case 'catppuccin': @@ -57,12 +64,14 @@ class AppTheme { case 'rosePine': return AppThemePalette.rosePine; default: - return AppThemePalette.oxocarbon; + return AppThemePalette.lazurite; } } static String paletteToString(AppThemePalette palette) { switch (palette) { + case AppThemePalette.lazurite: + return 'lazurite'; case AppThemePalette.oxocarbon: return 'oxocarbon'; case AppThemePalette.catppuccin: @@ -96,6 +105,8 @@ class AppTheme { static List getSwatchColors(AppThemePalette palette) { switch (palette) { + case AppThemePalette.lazurite: + return const [Color(0xFF7dafff), Color(0xFF0b63d1), Color(0xFF0073de), Color(0xFFff8080)]; case AppThemePalette.oxocarbon: return const [Color(0xFF78a9ff), Color(0xFFbe95ff), Color(0xFF08bdba), Color(0xFFee5396)]; case AppThemePalette.catppuccin: diff --git a/lib/core/theme/catppuccin_theme.dart b/lib/core/theme/catppuccin_theme.dart index 7cac884..05806ed 100644 --- a/lib/core/theme/catppuccin_theme.dart +++ b/lib/core/theme/catppuccin_theme.dart @@ -67,7 +67,7 @@ class CatppuccinTheme { backgroundColor: mochaBase, foregroundColor: mochaText, surfaceTintColor: mochaLavender, - titleTextStyle: AppTypography.dmSans(fontSize: 18, fontWeight: FontWeight.w600, color: mochaText), + titleTextStyle: AppTypography.googleSans(fontSize: 18, fontWeight: FontWeight.w600, color: mochaText), ), cardTheme: const CardThemeData(color: mochaMantle, surfaceTintColor: mochaLavender), dividerTheme: const DividerThemeData(color: mochaSurface0), @@ -75,8 +75,8 @@ class CatppuccinTheme { listTileTheme: ListTileThemeData( textColor: mochaText, iconColor: mochaSubtext0, - titleTextStyle: AppTypography.dmSans(fontSize: 16, fontWeight: FontWeight.w500, color: mochaText), - subtitleTextStyle: AppTypography.dmSans(fontSize: 14, color: mochaSubtext0), + titleTextStyle: AppTypography.googleSans(fontSize: 16, fontWeight: FontWeight.w500, color: mochaText), + subtitleTextStyle: AppTypography.googleSans(fontSize: 14, color: mochaSubtext0), ), textTheme: AppTypography.textTheme(bodyColor: mochaText, headlineColor: mochaText, captionColor: mochaSurface1), floatingActionButtonTheme: const FloatingActionButtonThemeData( @@ -87,13 +87,13 @@ class CatppuccinTheme { style: ElevatedButton.styleFrom( backgroundColor: mochaLavender, foregroundColor: mochaBase, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( foregroundColor: mochaLavender, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), inputDecorationTheme: InputDecorationTheme( @@ -102,12 +102,12 @@ class CatppuccinTheme { border: const OutlineInputBorder(borderSide: BorderSide(color: mochaSurface0)), enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: mochaSurface0)), focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: mochaLavender)), - labelStyle: AppTypography.dmSans(color: mochaSurface1), - hintStyle: AppTypography.dmSans(color: mochaSurface1), + labelStyle: AppTypography.googleSans(color: mochaSurface1), + hintStyle: AppTypography.googleSans(color: mochaSurface1), ), snackBarTheme: SnackBarThemeData( backgroundColor: mochaMantle, - contentTextStyle: AppTypography.dmSans(color: mochaText), + contentTextStyle: AppTypography.googleSans(color: mochaText), ), ); } @@ -143,7 +143,7 @@ class CatppuccinTheme { backgroundColor: latteBase, foregroundColor: latteText, surfaceTintColor: latteLavender, - titleTextStyle: AppTypography.dmSans(fontSize: 18, fontWeight: FontWeight.w600, color: latteText), + titleTextStyle: AppTypography.googleSans(fontSize: 18, fontWeight: FontWeight.w600, color: latteText), ), cardTheme: const CardThemeData(color: latteMantle, surfaceTintColor: latteLavender), dividerTheme: const DividerThemeData(color: latteSurface0), @@ -151,8 +151,8 @@ class CatppuccinTheme { listTileTheme: ListTileThemeData( textColor: latteText, iconColor: latteSubtext0, - titleTextStyle: AppTypography.dmSans(fontSize: 16, fontWeight: FontWeight.w500, color: latteText), - subtitleTextStyle: AppTypography.dmSans(fontSize: 14, color: latteSubtext0), + titleTextStyle: AppTypography.googleSans(fontSize: 16, fontWeight: FontWeight.w500, color: latteText), + subtitleTextStyle: AppTypography.googleSans(fontSize: 14, color: latteSubtext0), ), textTheme: AppTypography.textTheme(bodyColor: latteText, headlineColor: latteText, captionColor: latteSurface1), floatingActionButtonTheme: const FloatingActionButtonThemeData( @@ -163,13 +163,13 @@ class CatppuccinTheme { style: ElevatedButton.styleFrom( backgroundColor: latteLavender, foregroundColor: latteBase, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( foregroundColor: latteLavender, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), inputDecorationTheme: InputDecorationTheme( @@ -178,12 +178,12 @@ class CatppuccinTheme { border: const OutlineInputBorder(borderSide: BorderSide(color: latteSurface0)), enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: latteSurface0)), focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: latteLavender)), - labelStyle: AppTypography.dmSans(color: latteSurface1), - hintStyle: AppTypography.dmSans(color: latteSurface1), + labelStyle: AppTypography.googleSans(color: latteSurface1), + hintStyle: AppTypography.googleSans(color: latteSurface1), ), snackBarTheme: SnackBarThemeData( backgroundColor: latteMantle, - contentTextStyle: AppTypography.dmSans(color: latteText), + contentTextStyle: AppTypography.googleSans(color: latteText), ), ); } diff --git a/lib/core/theme/lazurite_theme.dart b/lib/core/theme/lazurite_theme.dart new file mode 100644 index 0000000..91f4771 --- /dev/null +++ b/lib/core/theme/lazurite_theme.dart @@ -0,0 +1,226 @@ +import 'package:flutter/material.dart'; +import 'package:lazurite/core/theme/typography.dart'; + +class LazuriteTheme { + LazuriteTheme._(); + + static const Color darkPrimary = Color(0xFF7dafff); + static const Color darkOnPrimary = Color(0xFF05080f); + static const Color darkPrimaryContainer = Color(0xFF0073de); + static const Color darkOnPrimaryContainer = Color(0xFFf4f6fb); + static const Color darkSurface = Color(0xFF0e0e0e); + static const Color darkOnSurface = Color(0xFFf4f6fb); + static const Color darkSurfaceVariant = Color(0xFF191919); + static const Color darkOnSurfaceVariant = Color(0xFFababab); + static const Color darkSurfaceContainerLowest = Color(0xFF000000); + static const Color darkSurfaceContainer = Color(0xFF191919); + static const Color darkSurfaceContainerHigh = Color(0xFF1f1f1f); + static const Color darkSurfaceContainerHighest = Color(0xF5242424); + static const Color darkSurfaceBright = Color(0x0Dffffff); + static const Color darkOutline = Color(0x33ffffff); + static const Color darkOutlineVariant = Color(0x1Affffff); + static const Color darkError = Color(0xFFff8080); + static const Color darkErrorContainer = Color(0xB88a1f1f); + + static const Color lightPrimary = Color(0xFF0b63d1); + static const Color lightOnPrimary = Color(0xFFffffff); + static const Color lightPrimaryContainer = Color(0xFF0953af); + static const Color lightOnPrimaryContainer = Color(0xFFffffff); + static const Color lightSurface = Color(0xFFffffff); + static const Color lightOnSurface = Color(0xFF101418); + static const Color lightSurfaceVariant = Color(0xFFf4f6f9); + static const Color lightOnSurfaceVariant = Color(0xFF45505e); + static const Color lightSurfaceContainerLowest = Color(0xFFeef1f5); + static const Color lightSurfaceContainer = Color(0xFFf4f6f9); + static const Color lightSurfaceContainerHigh = Color(0xFFeceff4); + static const Color lightSurfaceContainerHighest = Color(0xF5f6f8fc); + static const Color lightSurfaceBright = Color(0x0F111827); + static const Color lightOutline = Color(0x3D111827); + static const Color lightOutlineVariant = Color(0x24111827); + static const Color lightError = Color(0xFFb42318); + static const Color lightErrorContainer = Color(0xF2fee2e2); + + static ThemeData dark() { + return ThemeData( + useMaterial3: true, + brightness: Brightness.dark, + colorScheme: const ColorScheme( + brightness: Brightness.dark, + primary: darkPrimary, + onPrimary: darkOnPrimary, + primaryContainer: darkPrimaryContainer, + onPrimaryContainer: darkOnPrimaryContainer, + secondary: darkPrimaryContainer, + onSecondary: darkOnPrimaryContainer, + secondaryContainer: darkSurfaceContainer, + onSecondaryContainer: darkOnSurface, + tertiary: darkPrimary, + onTertiary: darkOnPrimary, + tertiaryContainer: darkSurfaceContainerHigh, + onTertiaryContainer: darkOnSurface, + error: darkError, + onError: darkOnPrimary, + errorContainer: darkErrorContainer, + onErrorContainer: darkOnSurface, + surface: darkSurface, + onSurface: darkOnSurface, + surfaceBright: darkSurfaceBright, + surfaceContainerLowest: darkSurfaceContainerLowest, + surfaceContainerLow: darkSurfaceVariant, + surfaceContainer: darkSurfaceContainer, + surfaceContainerHigh: darkSurfaceContainerHigh, + surfaceContainerHighest: darkSurfaceContainerHighest, + onSurfaceVariant: darkOnSurfaceVariant, + outline: darkOutline, + outlineVariant: darkOutlineVariant, + inverseSurface: lightSurface, + onInverseSurface: lightOnSurface, + inversePrimary: lightPrimary, + surfaceTint: darkPrimary, + ), + scaffoldBackgroundColor: darkSurfaceContainerLowest, + appBarTheme: AppBarTheme( + backgroundColor: darkSurfaceContainerLowest, + foregroundColor: darkOnSurface, + surfaceTintColor: darkPrimary, + titleTextStyle: AppTypography.googleSans(fontSize: 18, fontWeight: FontWeight.w600, color: darkOnSurface), + ), + cardTheme: const CardThemeData(color: darkSurfaceContainer, surfaceTintColor: darkPrimary), + dividerTheme: const DividerThemeData(color: darkOutlineVariant), + iconTheme: const IconThemeData(color: darkOnSurfaceVariant), + listTileTheme: ListTileThemeData( + textColor: darkOnSurface, + iconColor: darkOnSurfaceVariant, + titleTextStyle: AppTypography.googleSans(fontSize: 16, fontWeight: FontWeight.w500, color: darkOnSurface), + subtitleTextStyle: AppTypography.googleSans(fontSize: 14, color: darkOnSurfaceVariant), + ), + textTheme: AppTypography.textTheme( + bodyColor: darkOnSurface, + headlineColor: darkOnSurface, + captionColor: darkOnSurfaceVariant, + ), + floatingActionButtonTheme: const FloatingActionButtonThemeData( + backgroundColor: darkPrimary, + foregroundColor: darkOnPrimary, + ), + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: darkPrimary, + foregroundColor: darkOnPrimary, + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), + ), + ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + foregroundColor: darkPrimary, + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), + ), + ), + inputDecorationTheme: InputDecorationTheme( + filled: true, + fillColor: darkSurfaceContainerHigh, + border: const OutlineInputBorder(borderSide: BorderSide(color: darkOutlineVariant)), + enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: darkOutlineVariant)), + focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: darkPrimary)), + labelStyle: AppTypography.googleSans(color: darkOnSurfaceVariant), + hintStyle: AppTypography.googleSans(color: darkOnSurfaceVariant), + ), + snackBarTheme: SnackBarThemeData( + backgroundColor: darkSurfaceContainerHighest, + contentTextStyle: AppTypography.googleSans(color: darkOnSurface), + ), + ); + } + + static ThemeData light() { + return ThemeData( + useMaterial3: true, + brightness: Brightness.light, + colorScheme: const ColorScheme( + brightness: Brightness.light, + primary: lightPrimary, + onPrimary: lightOnPrimary, + primaryContainer: lightPrimaryContainer, + onPrimaryContainer: lightOnPrimaryContainer, + secondary: lightPrimaryContainer, + onSecondary: lightOnPrimaryContainer, + secondaryContainer: lightSurfaceContainer, + onSecondaryContainer: lightOnSurface, + tertiary: lightPrimary, + onTertiary: lightOnPrimary, + tertiaryContainer: lightSurfaceContainerHigh, + onTertiaryContainer: lightOnSurface, + error: lightError, + onError: lightOnPrimary, + errorContainer: lightErrorContainer, + onErrorContainer: lightOnSurface, + surface: lightSurface, + onSurface: lightOnSurface, + surfaceBright: lightSurfaceBright, + surfaceContainerLowest: lightSurfaceContainerLowest, + surfaceContainerLow: lightSurfaceVariant, + surfaceContainer: lightSurfaceContainer, + surfaceContainerHigh: lightSurfaceContainerHigh, + surfaceContainerHighest: lightSurfaceContainerHighest, + onSurfaceVariant: lightOnSurfaceVariant, + outline: lightOutline, + outlineVariant: lightOutlineVariant, + inverseSurface: darkSurface, + onInverseSurface: darkOnSurface, + inversePrimary: darkPrimary, + surfaceTint: lightPrimary, + ), + scaffoldBackgroundColor: lightSurface, + appBarTheme: AppBarTheme( + backgroundColor: lightSurface, + foregroundColor: lightOnSurface, + surfaceTintColor: lightPrimary, + titleTextStyle: AppTypography.googleSans(fontSize: 18, fontWeight: FontWeight.w600, color: lightOnSurface), + ), + cardTheme: const CardThemeData(color: lightSurfaceContainer, surfaceTintColor: lightPrimary), + dividerTheme: const DividerThemeData(color: lightOutlineVariant), + iconTheme: const IconThemeData(color: lightOnSurfaceVariant), + listTileTheme: ListTileThemeData( + textColor: lightOnSurface, + iconColor: lightOnSurfaceVariant, + titleTextStyle: AppTypography.googleSans(fontSize: 16, fontWeight: FontWeight.w500, color: lightOnSurface), + subtitleTextStyle: AppTypography.googleSans(fontSize: 14, color: lightOnSurfaceVariant), + ), + textTheme: AppTypography.textTheme( + bodyColor: lightOnSurface, + headlineColor: lightOnSurface, + captionColor: lightOnSurfaceVariant, + ), + floatingActionButtonTheme: const FloatingActionButtonThemeData( + backgroundColor: lightPrimary, + foregroundColor: lightOnPrimary, + ), + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: lightPrimary, + foregroundColor: lightOnPrimary, + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), + ), + ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + foregroundColor: lightPrimary, + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), + ), + ), + inputDecorationTheme: InputDecorationTheme( + filled: true, + fillColor: lightSurfaceContainer, + border: const OutlineInputBorder(borderSide: BorderSide(color: lightOutlineVariant)), + enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: lightOutlineVariant)), + focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: lightPrimary)), + labelStyle: AppTypography.googleSans(color: lightOnSurfaceVariant), + hintStyle: AppTypography.googleSans(color: lightOnSurfaceVariant), + ), + snackBarTheme: SnackBarThemeData( + backgroundColor: lightSurfaceContainerHighest, + contentTextStyle: AppTypography.googleSans(color: lightOnSurface), + ), + ); + } +} diff --git a/lib/core/theme/nord_theme.dart b/lib/core/theme/nord_theme.dart index ec4b967..c2d5cf9 100644 --- a/lib/core/theme/nord_theme.dart +++ b/lib/core/theme/nord_theme.dart @@ -52,7 +52,7 @@ class NordTheme { backgroundColor: nord0, foregroundColor: nord5, surfaceTintColor: nord8, - titleTextStyle: AppTypography.dmSans(fontSize: 18, fontWeight: FontWeight.w600, color: nord5), + titleTextStyle: AppTypography.googleSans(fontSize: 18, fontWeight: FontWeight.w600, color: nord5), ), cardTheme: const CardThemeData(color: nord1, surfaceTintColor: nord8), dividerTheme: const DividerThemeData(color: nord2), @@ -60,8 +60,8 @@ class NordTheme { listTileTheme: ListTileThemeData( textColor: nord5, iconColor: nord4, - titleTextStyle: AppTypography.dmSans(fontSize: 16, fontWeight: FontWeight.w500, color: nord5), - subtitleTextStyle: AppTypography.dmSans(fontSize: 14, color: nord4), + titleTextStyle: AppTypography.googleSans(fontSize: 16, fontWeight: FontWeight.w500, color: nord5), + subtitleTextStyle: AppTypography.googleSans(fontSize: 14, color: nord4), ), textTheme: AppTypography.textTheme(bodyColor: nord5, headlineColor: nord6, captionColor: nord3), floatingActionButtonTheme: const FloatingActionButtonThemeData(backgroundColor: nord8, foregroundColor: nord0), @@ -69,13 +69,13 @@ class NordTheme { style: ElevatedButton.styleFrom( backgroundColor: nord8, foregroundColor: nord0, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( foregroundColor: nord8, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), inputDecorationTheme: InputDecorationTheme( @@ -84,12 +84,12 @@ class NordTheme { border: const OutlineInputBorder(borderSide: BorderSide(color: nord2)), enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: nord2)), focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: nord8)), - labelStyle: AppTypography.dmSans(color: nord3), - hintStyle: AppTypography.dmSans(color: nord3), + labelStyle: AppTypography.googleSans(color: nord3), + hintStyle: AppTypography.googleSans(color: nord3), ), snackBarTheme: SnackBarThemeData( backgroundColor: nord1, - contentTextStyle: AppTypography.dmSans(color: nord5), + contentTextStyle: AppTypography.googleSans(color: nord5), ), ); } @@ -125,7 +125,7 @@ class NordTheme { backgroundColor: nord6, foregroundColor: nord3, surfaceTintColor: nord8, - titleTextStyle: AppTypography.dmSans(fontSize: 18, fontWeight: FontWeight.w600, color: nord3), + titleTextStyle: AppTypography.googleSans(fontSize: 18, fontWeight: FontWeight.w600, color: nord3), ), cardTheme: const CardThemeData(color: nord5, surfaceTintColor: nord8), dividerTheme: const DividerThemeData(color: nord2), @@ -133,8 +133,8 @@ class NordTheme { listTileTheme: ListTileThemeData( textColor: nord3, iconColor: nord4, - titleTextStyle: AppTypography.dmSans(fontSize: 16, fontWeight: FontWeight.w500, color: nord3), - subtitleTextStyle: AppTypography.dmSans(fontSize: 14, color: nord4), + titleTextStyle: AppTypography.googleSans(fontSize: 16, fontWeight: FontWeight.w500, color: nord3), + subtitleTextStyle: AppTypography.googleSans(fontSize: 14, color: nord4), ), textTheme: AppTypography.textTheme(bodyColor: nord3, headlineColor: nord0, captionColor: nord3), floatingActionButtonTheme: const FloatingActionButtonThemeData(backgroundColor: nord8, foregroundColor: nord0), @@ -142,13 +142,13 @@ class NordTheme { style: ElevatedButton.styleFrom( backgroundColor: nord8, foregroundColor: nord0, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( foregroundColor: nord8, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), inputDecorationTheme: InputDecorationTheme( @@ -157,12 +157,12 @@ class NordTheme { border: const OutlineInputBorder(borderSide: BorderSide(color: nord2)), enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: nord2)), focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: nord8)), - labelStyle: AppTypography.dmSans(color: nord3), - hintStyle: AppTypography.dmSans(color: nord3), + labelStyle: AppTypography.googleSans(color: nord3), + hintStyle: AppTypography.googleSans(color: nord3), ), snackBarTheme: SnackBarThemeData( backgroundColor: nord5, - contentTextStyle: AppTypography.dmSans(color: nord3), + contentTextStyle: AppTypography.googleSans(color: nord3), ), ); } diff --git a/lib/core/theme/oxocarbon_theme.dart b/lib/core/theme/oxocarbon_theme.dart index 540f7dc..0520a12 100644 --- a/lib/core/theme/oxocarbon_theme.dart +++ b/lib/core/theme/oxocarbon_theme.dart @@ -69,7 +69,7 @@ class OxocarbonTheme { backgroundColor: darkBase00, foregroundColor: darkBase05, surfaceTintColor: darkBase09, - titleTextStyle: AppTypography.dmSans(fontSize: 18, fontWeight: FontWeight.w600, color: darkBase05), + titleTextStyle: AppTypography.googleSans(fontSize: 18, fontWeight: FontWeight.w600, color: darkBase05), ), cardTheme: const CardThemeData(color: darkBase01, surfaceTintColor: darkBase09), dividerTheme: const DividerThemeData(color: darkBase02), @@ -77,8 +77,8 @@ class OxocarbonTheme { listTileTheme: ListTileThemeData( textColor: darkBase05, iconColor: darkBase04, - titleTextStyle: AppTypography.dmSans(fontSize: 16, fontWeight: FontWeight.w500, color: darkBase05), - subtitleTextStyle: AppTypography.dmSans(fontSize: 14, color: darkBase04), + titleTextStyle: AppTypography.googleSans(fontSize: 16, fontWeight: FontWeight.w500, color: darkBase05), + subtitleTextStyle: AppTypography.googleSans(fontSize: 14, color: darkBase04), ), textTheme: AppTypography.textTheme(bodyColor: darkBase05, headlineColor: darkBase06, captionColor: darkBase03), floatingActionButtonTheme: const FloatingActionButtonThemeData( @@ -89,13 +89,13 @@ class OxocarbonTheme { style: ElevatedButton.styleFrom( backgroundColor: darkBase09, foregroundColor: darkBase00, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( foregroundColor: darkBase09, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), inputDecorationTheme: InputDecorationTheme( @@ -104,12 +104,12 @@ class OxocarbonTheme { border: const OutlineInputBorder(borderSide: BorderSide(color: darkBase02)), enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: darkBase02)), focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: darkBase09)), - labelStyle: AppTypography.dmSans(color: darkBase03), - hintStyle: AppTypography.dmSans(color: darkBase03), + labelStyle: AppTypography.googleSans(color: darkBase03), + hintStyle: AppTypography.googleSans(color: darkBase03), ), snackBarTheme: SnackBarThemeData( backgroundColor: darkBase01, - contentTextStyle: AppTypography.dmSans(color: darkBase05), + contentTextStyle: AppTypography.googleSans(color: darkBase05), ), ); } @@ -145,7 +145,7 @@ class OxocarbonTheme { backgroundColor: lightBase00, foregroundColor: lightBase03, surfaceTintColor: lightBase0B, - titleTextStyle: AppTypography.dmSans(fontSize: 18, fontWeight: FontWeight.w600, color: lightBase03), + titleTextStyle: AppTypography.googleSans(fontSize: 18, fontWeight: FontWeight.w600, color: lightBase03), ), cardTheme: const CardThemeData(color: lightBase01, surfaceTintColor: lightBase0B), dividerTheme: const DividerThemeData(color: lightBase02), @@ -153,8 +153,8 @@ class OxocarbonTheme { listTileTheme: ListTileThemeData( textColor: lightBase03, iconColor: lightBase04, - titleTextStyle: AppTypography.dmSans(fontSize: 16, fontWeight: FontWeight.w500, color: lightBase03), - subtitleTextStyle: AppTypography.dmSans(fontSize: 14, color: lightBase04), + titleTextStyle: AppTypography.googleSans(fontSize: 16, fontWeight: FontWeight.w500, color: lightBase03), + subtitleTextStyle: AppTypography.googleSans(fontSize: 14, color: lightBase04), ), textTheme: AppTypography.textTheme(bodyColor: lightBase03, headlineColor: lightBase03, captionColor: lightBase05), floatingActionButtonTheme: const FloatingActionButtonThemeData( @@ -165,13 +165,13 @@ class OxocarbonTheme { style: ElevatedButton.styleFrom( backgroundColor: lightBase0B, foregroundColor: lightBase00, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( foregroundColor: lightBase0B, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), inputDecorationTheme: InputDecorationTheme( @@ -180,12 +180,12 @@ class OxocarbonTheme { border: const OutlineInputBorder(borderSide: BorderSide(color: lightBase02)), enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: lightBase02)), focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: lightBase0B)), - labelStyle: AppTypography.dmSans(color: lightBase05), - hintStyle: AppTypography.dmSans(color: lightBase05), + labelStyle: AppTypography.googleSans(color: lightBase05), + hintStyle: AppTypography.googleSans(color: lightBase05), ), snackBarTheme: SnackBarThemeData( backgroundColor: lightBase01, - contentTextStyle: AppTypography.dmSans(color: lightBase03), + contentTextStyle: AppTypography.googleSans(color: lightBase03), ), ); } diff --git a/lib/core/theme/rose_pine_theme.dart b/lib/core/theme/rose_pine_theme.dart index 3031939..c0c2258 100644 --- a/lib/core/theme/rose_pine_theme.dart +++ b/lib/core/theme/rose_pine_theme.dart @@ -61,7 +61,7 @@ class RosePineTheme { backgroundColor: mainBase, foregroundColor: mainText, surfaceTintColor: mainRose, - titleTextStyle: AppTypography.dmSans(fontSize: 18, fontWeight: FontWeight.w600, color: mainText), + titleTextStyle: AppTypography.googleSans(fontSize: 18, fontWeight: FontWeight.w600, color: mainText), ), cardTheme: const CardThemeData(color: mainSurface, surfaceTintColor: mainRose), dividerTheme: const DividerThemeData(color: mainOverlay), @@ -69,8 +69,8 @@ class RosePineTheme { listTileTheme: ListTileThemeData( textColor: mainText, iconColor: mainSubtle, - titleTextStyle: AppTypography.dmSans(fontSize: 16, fontWeight: FontWeight.w500, color: mainText), - subtitleTextStyle: AppTypography.dmSans(fontSize: 14, color: mainSubtle), + titleTextStyle: AppTypography.googleSans(fontSize: 16, fontWeight: FontWeight.w500, color: mainText), + subtitleTextStyle: AppTypography.googleSans(fontSize: 14, color: mainSubtle), ), textTheme: AppTypography.textTheme(bodyColor: mainText, headlineColor: mainText, captionColor: mainMuted), floatingActionButtonTheme: const FloatingActionButtonThemeData( @@ -81,13 +81,13 @@ class RosePineTheme { style: ElevatedButton.styleFrom( backgroundColor: mainRose, foregroundColor: mainBase, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( foregroundColor: mainRose, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), inputDecorationTheme: InputDecorationTheme( @@ -96,12 +96,12 @@ class RosePineTheme { border: const OutlineInputBorder(borderSide: BorderSide(color: mainOverlay)), enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: mainOverlay)), focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: mainRose)), - labelStyle: AppTypography.dmSans(color: mainMuted), - hintStyle: AppTypography.dmSans(color: mainMuted), + labelStyle: AppTypography.googleSans(color: mainMuted), + hintStyle: AppTypography.googleSans(color: mainMuted), ), snackBarTheme: SnackBarThemeData( backgroundColor: mainSurface, - contentTextStyle: AppTypography.dmSans(color: mainText), + contentTextStyle: AppTypography.googleSans(color: mainText), ), ); } @@ -137,7 +137,7 @@ class RosePineTheme { backgroundColor: dawnBase, foregroundColor: dawnText, surfaceTintColor: dawnRose, - titleTextStyle: AppTypography.dmSans(fontSize: 18, fontWeight: FontWeight.w600, color: dawnText), + titleTextStyle: AppTypography.googleSans(fontSize: 18, fontWeight: FontWeight.w600, color: dawnText), ), cardTheme: const CardThemeData(color: dawnSurface, surfaceTintColor: dawnRose), dividerTheme: const DividerThemeData(color: dawnOverlay), @@ -145,8 +145,8 @@ class RosePineTheme { listTileTheme: ListTileThemeData( textColor: dawnText, iconColor: dawnSubtle, - titleTextStyle: AppTypography.dmSans(fontSize: 16, fontWeight: FontWeight.w500, color: dawnText), - subtitleTextStyle: AppTypography.dmSans(fontSize: 14, color: dawnSubtle), + titleTextStyle: AppTypography.googleSans(fontSize: 16, fontWeight: FontWeight.w500, color: dawnText), + subtitleTextStyle: AppTypography.googleSans(fontSize: 14, color: dawnSubtle), ), textTheme: AppTypography.textTheme(bodyColor: dawnText, headlineColor: dawnText, captionColor: dawnMuted), floatingActionButtonTheme: const FloatingActionButtonThemeData( @@ -157,13 +157,13 @@ class RosePineTheme { style: ElevatedButton.styleFrom( backgroundColor: dawnRose, foregroundColor: dawnBase, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( foregroundColor: dawnRose, - textStyle: AppTypography.dmSans(fontSize: 14, fontWeight: FontWeight.w500), + textStyle: AppTypography.googleSans(fontSize: 14, fontWeight: FontWeight.w500), ), ), inputDecorationTheme: InputDecorationTheme( @@ -172,12 +172,12 @@ class RosePineTheme { border: const OutlineInputBorder(borderSide: BorderSide(color: dawnOverlay)), enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: dawnOverlay)), focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: dawnRose)), - labelStyle: AppTypography.dmSans(color: dawnMuted), - hintStyle: AppTypography.dmSans(color: dawnMuted), + labelStyle: AppTypography.googleSans(color: dawnMuted), + hintStyle: AppTypography.googleSans(color: dawnMuted), ), snackBarTheme: SnackBarThemeData( backgroundColor: dawnSurface, - contentTextStyle: AppTypography.dmSans(color: dawnText), + contentTextStyle: AppTypography.googleSans(color: dawnText), ), ); } diff --git a/lib/core/theme/typography.dart b/lib/core/theme/typography.dart index d4c151e..3caa29c 100644 --- a/lib/core/theme/typography.dart +++ b/lib/core/theme/typography.dart @@ -4,14 +4,14 @@ import 'package:google_fonts/google_fonts.dart'; class AppTypography { AppTypography._(); - static TextStyle dmSans({ + static TextStyle googleSans({ double fontSize = 14, FontWeight fontWeight = FontWeight.normal, Color? color, double? letterSpacing, double? height, }) { - return GoogleFonts.dmSans( + return GoogleFonts.googleSans( fontSize: fontSize, fontWeight: fontWeight, color: color, @@ -36,14 +36,14 @@ class AppTypography { ); } - static TextStyle jetBrainsMono({ + static TextStyle googleSansCode({ double fontSize = 14, FontWeight fontWeight = FontWeight.normal, Color? color, double? letterSpacing, double? height, }) { - return GoogleFonts.jetBrainsMono( + return GoogleFonts.googleSansCode( fontSize: fontSize, fontWeight: fontWeight, color: color, @@ -63,12 +63,12 @@ class AppTypography { titleLarge: lora(fontSize: 22, fontWeight: FontWeight.w600, color: bodyColor), titleMedium: lora(fontSize: 16, fontWeight: FontWeight.w500, color: bodyColor, letterSpacing: 0.15), titleSmall: lora(fontSize: 14, fontWeight: FontWeight.w500, color: bodyColor, letterSpacing: 0.1), - bodyLarge: dmSans(fontSize: 16, fontWeight: FontWeight.w400, color: bodyColor, letterSpacing: 0.5), - bodyMedium: dmSans(fontSize: 14, fontWeight: FontWeight.w400, color: bodyColor, letterSpacing: 0.25), - bodySmall: dmSans(fontSize: 12, fontWeight: FontWeight.w400, color: captionColor, letterSpacing: 0.4), - labelLarge: dmSans(fontSize: 14, fontWeight: FontWeight.w500, color: bodyColor, letterSpacing: 0.1), - labelMedium: dmSans(fontSize: 12, fontWeight: FontWeight.w500, color: bodyColor, letterSpacing: 0.5), - labelSmall: dmSans(fontSize: 12, fontWeight: FontWeight.w500, color: captionColor, letterSpacing: 0.5), + bodyLarge: googleSans(fontSize: 16, fontWeight: FontWeight.w400, color: bodyColor, letterSpacing: 0.5), + bodyMedium: googleSans(fontSize: 14, fontWeight: FontWeight.w400, color: bodyColor, letterSpacing: 0.25), + bodySmall: googleSans(fontSize: 12, fontWeight: FontWeight.w400, color: captionColor, letterSpacing: 0.4), + labelLarge: googleSans(fontSize: 14, fontWeight: FontWeight.w500, color: bodyColor, letterSpacing: 0.1), + labelMedium: googleSans(fontSize: 12, fontWeight: FontWeight.w500, color: bodyColor, letterSpacing: 0.5), + labelSmall: googleSans(fontSize: 12, fontWeight: FontWeight.w500, color: captionColor, letterSpacing: 0.5), ); } } diff --git a/lib/core/widgets/lazurite_app_bar.dart b/lib/core/widgets/lazurite_app_bar.dart index bfd792d..141dd19 100644 --- a/lib/core/widgets/lazurite_app_bar.dart +++ b/lib/core/widgets/lazurite_app_bar.dart @@ -2,25 +2,22 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:lazurite/core/logging/app_logger.dart'; import 'package:lazurite/core/router/app_shell.dart'; -import 'package:lazurite/features/auth/bloc/auth_bloc.dart'; import 'package:lazurite/features/connectivity/cubit/connectivity_cubit.dart'; import 'package:lazurite/features/settings/bloc/settings_cubit.dart'; /// Custom top app bar for the Lazurite shell screens. /// -/// Shows a hamburger button on the left, a section label (uppercase, -/// letterSpacing 3, labelSmall, onSurfaceVariant), and a square user -/// avatar thumbnail on the right. +/// Shows a hamburger button on the left and a section label (uppercase, +/// letterSpacing 3, labelSmall, onSurfaceVariant) /// /// Pass [bottom] to add an additional row below the toolbar (e.g., for the /// home-screen feed-switcher tabs). class LazuriteAppBar extends StatelessWidget implements PreferredSizeWidget { - const LazuriteAppBar({super.key, required this.sectionLabel, this.bottom, this.actions, this.showAvatar = true}); + const LazuriteAppBar({super.key, required this.sectionLabel, this.bottom, this.actions}); final String sectionLabel; final PreferredSizeWidget? bottom; final List? actions; - final bool showAvatar; static const double _toolbarHeight = 64; @@ -43,11 +40,7 @@ class LazuriteAppBar extends StatelessWidget implements PreferredSizeWidget { ), centerTitle: false, titleSpacing: 0, - actions: [ - ...?actions, - const _AppBarOfflineIndicator(), - if (showAvatar) ...[const _AppBarAvatar(), const SizedBox(width: 8)], - ], + actions: [...?actions, const _AppBarOfflineIndicator()], bottom: bottom, shape: Border(bottom: BorderSide(color: theme.colorScheme.outlineVariant)), ); @@ -99,38 +92,3 @@ class _AppBarOfflineIndicator extends StatelessWidget { ); } } - -class _AppBarAvatar extends StatelessWidget { - const _AppBarAvatar(); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - AuthState? authState; - try { - authState = context.watch().state; - } catch (_) { - log.d('showing default avatar'); - } - final tokens = authState?.tokens; - final initials = _initialsFor(tokens?.displayName ?? tokens?.handle ?? 'L'); - - return Container( - width: 32, - height: 32, - decoration: BoxDecoration( - color: theme.colorScheme.surfaceContainerHigh, - border: Border.all(color: theme.colorScheme.outlineVariant), - ), - child: Center( - child: Text(initials, style: theme.textTheme.labelSmall?.copyWith(fontWeight: FontWeight.w600)), - ), - ); - } - - String _initialsFor(String value) { - final parts = value.trim().split(RegExp(r'\s+')).where((p) => p.isNotEmpty).take(2).toList(); - if (parts.isEmpty) return 'L'; - return parts.map((p) => p[0].toUpperCase()).join(); - } -} diff --git a/lib/features/devtools/presentation/dev_tools_screen.dart b/lib/features/devtools/presentation/dev_tools_screen.dart index 497dd9c..80bf302 100644 --- a/lib/features/devtools/presentation/dev_tools_screen.dart +++ b/lib/features/devtools/presentation/dev_tools_screen.dart @@ -569,7 +569,7 @@ class _RecordInspector extends StatelessWidget { children: [ TextButton.icon( icon: const Icon(Icons.copy, size: 16), - label: const Text('Copy'), + label: const Text('Copy JSON'), onPressed: () { Clipboard.setData(ClipboardData(text: jsonString)); ScaffoldMessenger.of(context).showSnackBar( diff --git a/lib/features/settings/bloc/settings_cubit.dart b/lib/features/settings/bloc/settings_cubit.dart index 58fddc8..1260839 100644 --- a/lib/features/settings/bloc/settings_cubit.dart +++ b/lib/features/settings/bloc/settings_cubit.dart @@ -16,7 +16,7 @@ class SettingsCubit extends Cubit { String? initialConstellationUrl, }) : super( SettingsState( - themePalette: initialPalette ?? AppThemePalette.oxocarbon, + themePalette: initialPalette ?? AppThemePalette.lazurite, themeVariant: initialVariant ?? AppThemeVariant.dark, useSystemTheme: initialUseSystemTheme ?? false, feedLayout: initialFeedLayout ?? FeedLayout.card, diff --git a/lib/features/settings/presentation/settings_screen.dart b/lib/features/settings/presentation/settings_screen.dart index e27b56f..28a93f1 100644 --- a/lib/features/settings/presentation/settings_screen.dart +++ b/lib/features/settings/presentation/settings_screen.dart @@ -302,8 +302,8 @@ class SettingsScreen extends StatelessWidget { ), child: _SettingsTile( icon: Icons.cloud_off_outlined, - title: 'Simulate Offline', - subtitle: 'Force offline UI for testing network resilience', + title: 'Go Offline', + subtitle: 'Turn off online connectivity', trailing: Switch.adaptive(value: state.simulateOffline, onChanged: settingsCubit.setSimulateOffline), ), ); diff --git a/lib/main.dart b/lib/main.dart index d093946..fea25c9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -237,11 +237,10 @@ class _LazuriteAppState extends State { ListRepository(bluesky: bluesky, moderationService: context.read()), ), RepositoryProvider( - create: (context) => ProfileRepository( - database: widget.database, - bluesky: bluesky, - moderationService: context.read(), - ), + create: (context) { + final service = context.read(); + return ProfileRepository(database: widget.database, bluesky: bluesky, moderationService: service); + }, ), RepositoryProvider( create: (context) => diff --git a/pubspec.lock b/pubspec.lock index d0adb36..15873c6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -564,10 +564,10 @@ packages: dependency: "direct main" description: name: google_fonts - sha256: ba03d03bcaa2f6cb7bd920e3b5027181db75ab524f8891c8bc3aa603885b8055 + sha256: db9df7a5898d894eeda4c78143f35c30a243558be439518972366880b80bf88e url: "https://pub.dev" source: hosted - version: "6.3.3" + version: "8.0.2" graphs: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 8bd2176..a7e3cb7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: crypto: ^3.0.6 url_launcher: ^6.3.1 intl: ^0.19.0 - google_fonts: ^6.2.1 + google_fonts: ^8.0.2 logger: ^2.6.2 share_plus: ^10.1.4 http: ^1.2.2 diff --git a/test/core/theme/app_theme_test.dart b/test/core/theme/app_theme_test.dart index a918a2f..4efef95 100644 --- a/test/core/theme/app_theme_test.dart +++ b/test/core/theme/app_theme_test.dart @@ -4,6 +4,10 @@ import 'package:lazurite/core/theme/app_theme.dart'; void main() { group('AppTheme', () { group('getPaletteName', () { + test('returns correct name for lazurite', () { + expect(AppTheme.getPaletteName(AppThemePalette.lazurite), 'Lazurite'); + }); + test('returns correct name for oxocarbon', () { expect(AppTheme.getPaletteName(AppThemePalette.oxocarbon), 'Oxocarbon'); }); @@ -32,6 +36,10 @@ void main() { }); group('parsePalette', () { + test('parses lazurite', () { + expect(AppTheme.parsePalette('lazurite'), AppThemePalette.lazurite); + }); + test('parses oxocarbon', () { expect(AppTheme.parsePalette('oxocarbon'), AppThemePalette.oxocarbon); }); @@ -48,16 +56,20 @@ void main() { expect(AppTheme.parsePalette('rosePine'), AppThemePalette.rosePine); }); - test('returns oxocarbon for null', () { - expect(AppTheme.parsePalette(null), AppThemePalette.oxocarbon); + test('returns lazurite for null', () { + expect(AppTheme.parsePalette(null), AppThemePalette.lazurite); }); - test('returns oxocarbon for unknown value', () { - expect(AppTheme.parsePalette('unknown'), AppThemePalette.oxocarbon); + test('returns lazurite for unknown value', () { + expect(AppTheme.parsePalette('unknown'), AppThemePalette.lazurite); }); }); group('paletteToString', () { + test('converts lazurite to string', () { + expect(AppTheme.paletteToString(AppThemePalette.lazurite), 'lazurite'); + }); + test('converts oxocarbon to string', () { expect(AppTheme.paletteToString(AppThemePalette.oxocarbon), 'oxocarbon'); }); diff --git a/test/core/theme/lazurite_theme_test.dart b/test/core/theme/lazurite_theme_test.dart new file mode 100644 index 0000000..fca542e --- /dev/null +++ b/test/core/theme/lazurite_theme_test.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:lazurite/core/theme/lazurite_theme.dart'; + +void main() { + group('LazuriteTheme', () { + group('Dark color values', () { + test('matches expected palette tokens', () { + expect(LazuriteTheme.darkPrimary, const Color(0xFF7dafff)); + expect(LazuriteTheme.darkOnPrimary, const Color(0xFF05080f)); + expect(LazuriteTheme.darkPrimaryContainer, const Color(0xFF0073de)); + expect(LazuriteTheme.darkOnPrimaryContainer, const Color(0xFFf4f6fb)); + expect(LazuriteTheme.darkSurface, const Color(0xFF0e0e0e)); + expect(LazuriteTheme.darkOnSurface, const Color(0xFFf4f6fb)); + expect(LazuriteTheme.darkSurfaceVariant, const Color(0xFF191919)); + expect(LazuriteTheme.darkOnSurfaceVariant, const Color(0xFFababab)); + expect(LazuriteTheme.darkSurfaceContainerLowest, const Color(0xFF000000)); + expect(LazuriteTheme.darkSurfaceContainer, const Color(0xFF191919)); + expect(LazuriteTheme.darkSurfaceContainerHigh, const Color(0xFF1f1f1f)); + expect(LazuriteTheme.darkSurfaceContainerHighest, const Color(0xF5242424)); + expect(LazuriteTheme.darkSurfaceBright, const Color(0x0Dffffff)); + expect(LazuriteTheme.darkOutline, const Color(0x33ffffff)); + expect(LazuriteTheme.darkOutlineVariant, const Color(0x1Affffff)); + expect(LazuriteTheme.darkError, const Color(0xFFff8080)); + expect(LazuriteTheme.darkErrorContainer, const Color(0xB88a1f1f)); + }); + }); + + group('Light color values', () { + test('matches expected palette tokens', () { + expect(LazuriteTheme.lightPrimary, const Color(0xFF0b63d1)); + expect(LazuriteTheme.lightOnPrimary, const Color(0xFFffffff)); + expect(LazuriteTheme.lightPrimaryContainer, const Color(0xFF0953af)); + expect(LazuriteTheme.lightOnPrimaryContainer, const Color(0xFFffffff)); + expect(LazuriteTheme.lightSurface, const Color(0xFFffffff)); + expect(LazuriteTheme.lightOnSurface, const Color(0xFF101418)); + expect(LazuriteTheme.lightSurfaceVariant, const Color(0xFFf4f6f9)); + expect(LazuriteTheme.lightOnSurfaceVariant, const Color(0xFF45505e)); + expect(LazuriteTheme.lightSurfaceContainerLowest, const Color(0xFFeef1f5)); + expect(LazuriteTheme.lightSurfaceContainer, const Color(0xFFf4f6f9)); + expect(LazuriteTheme.lightSurfaceContainerHigh, const Color(0xFFeceff4)); + expect(LazuriteTheme.lightSurfaceContainerHighest, const Color(0xF5f6f8fc)); + expect(LazuriteTheme.lightSurfaceBright, const Color(0x0F111827)); + expect(LazuriteTheme.lightOutline, const Color(0x3D111827)); + expect(LazuriteTheme.lightOutlineVariant, const Color(0x24111827)); + expect(LazuriteTheme.lightError, const Color(0xFFb42318)); + expect(LazuriteTheme.lightErrorContainer, const Color(0xF2fee2e2)); + }); + }); + + group('ThemeData', () { + testWidgets('dark theme maps key color scheme roles', (tester) async { + final theme = LazuriteTheme.dark(); + final scheme = theme.colorScheme; + + expect(theme.brightness, Brightness.dark); + expect(scheme.primary, LazuriteTheme.darkPrimary); + expect(scheme.onPrimary, LazuriteTheme.darkOnPrimary); + expect(scheme.primaryContainer, LazuriteTheme.darkPrimaryContainer); + expect(scheme.surfaceContainerLowest, LazuriteTheme.darkSurfaceContainerLowest); + expect(scheme.surfaceContainerHigh, LazuriteTheme.darkSurfaceContainerHigh); + expect(scheme.surfaceContainerHighest, LazuriteTheme.darkSurfaceContainerHighest); + expect(scheme.onSurfaceVariant, LazuriteTheme.darkOnSurfaceVariant); + expect(scheme.outlineVariant, LazuriteTheme.darkOutlineVariant); + expect(scheme.errorContainer, LazuriteTheme.darkErrorContainer); + }); + + testWidgets('light theme maps key color scheme roles', (tester) async { + final theme = LazuriteTheme.light(); + final scheme = theme.colorScheme; + + expect(theme.brightness, Brightness.light); + expect(scheme.primary, LazuriteTheme.lightPrimary); + expect(scheme.onPrimary, LazuriteTheme.lightOnPrimary); + expect(scheme.primaryContainer, LazuriteTheme.lightPrimaryContainer); + expect(scheme.surfaceContainerLowest, LazuriteTheme.lightSurfaceContainerLowest); + expect(scheme.surfaceContainerHigh, LazuriteTheme.lightSurfaceContainerHigh); + expect(scheme.surfaceContainerHighest, LazuriteTheme.lightSurfaceContainerHighest); + expect(scheme.onSurfaceVariant, LazuriteTheme.lightOnSurfaceVariant); + expect(scheme.outlineVariant, LazuriteTheme.lightOutlineVariant); + expect(scheme.errorContainer, LazuriteTheme.lightErrorContainer); + }); + }); + }); +} diff --git a/test/core/widgets/lazurite_app_bar_test.dart b/test/core/widgets/lazurite_app_bar_test.dart index 68aff7f..937e200 100644 --- a/test/core/widgets/lazurite_app_bar_test.dart +++ b/test/core/widgets/lazurite_app_bar_test.dart @@ -6,8 +6,8 @@ import 'package:lazurite/core/router/app_shell.dart'; import 'package:lazurite/core/theme/app_theme.dart'; import 'package:lazurite/core/widgets/lazurite_app_bar.dart'; import 'package:lazurite/features/auth/bloc/auth_bloc.dart'; -import 'package:lazurite/features/connectivity/cubit/connectivity_cubit.dart'; import 'package:lazurite/features/auth/data/models/auth_models.dart'; +import 'package:lazurite/features/connectivity/cubit/connectivity_cubit.dart'; import 'package:lazurite/features/settings/bloc/settings_cubit.dart'; import 'package:lazurite/features/settings/bloc/settings_state.dart'; import 'package:mocktail/mocktail.dart'; @@ -62,12 +62,7 @@ void main() { when(() => settingsCubit.setSimulateOffline(any())).thenAnswer((_) async {}); }); - Widget buildSubject({ - required String sectionLabel, - PreferredSizeWidget? bottom, - List? actions, - bool showAvatar = true, - }) { + Widget buildSubject({required String sectionLabel, PreferredSizeWidget? bottom, List? actions}) { return MultiBlocProvider( providers: [ BlocProvider.value(value: authBloc), @@ -76,7 +71,7 @@ void main() { ], child: MaterialApp( home: Scaffold( - appBar: LazuriteAppBar(sectionLabel: sectionLabel, bottom: bottom, actions: actions, showAvatar: showAvatar), + appBar: LazuriteAppBar(sectionLabel: sectionLabel, bottom: bottom, actions: actions), body: const SizedBox.shrink(), ), ), @@ -95,12 +90,6 @@ void main() { expect(find.byType(AppShellMenuButton), findsOneWidget); }); - testWidgets('renders user initials in avatar from displayName', (tester) async { - await tester.pumpWidget(buildSubject(sectionLabel: 'Home')); - await tester.pumpAndSettle(); - expect(find.text('RT'), findsOneWidget); - }); - testWidgets('renders initials from handle when displayName is absent', (tester) async { authBloc = MockAuthBloc(); const noDisplayName = AuthTokens( @@ -118,33 +107,6 @@ void main() { expect(find.text('A'), findsOneWidget); }); - testWidgets('renders additional actions alongside avatar', (tester) async { - await tester.pumpWidget( - buildSubject( - sectionLabel: 'Alerts', - actions: [TextButton(onPressed: () {}, child: const Text('Mark All Read'))], - ), - ); - await tester.pumpAndSettle(); - - expect(find.text('Mark All Read'), findsOneWidget); - expect(find.text('ALERTS'), findsOneWidget); - }); - - testWidgets('can hide avatar when custom trailing actions are used', (tester) async { - await tester.pumpWidget( - buildSubject( - sectionLabel: 'Home', - showAvatar: false, - actions: [IconButton(onPressed: () {}, icon: const Icon(Icons.rss_feed))], - ), - ); - await tester.pumpAndSettle(); - - expect(find.byIcon(Icons.rss_feed), findsOneWidget); - expect(find.text('RT'), findsNothing); - }); - testWidgets('shows simulated offline indicator and lets the user disable it', (tester) async { when(() => connectivityCubit.state).thenReturn(const ConnectivityState.online(isSimulatedOffline: true)); whenListen( diff --git a/test/features/settings/bloc/settings_cubit_test.dart b/test/features/settings/bloc/settings_cubit_test.dart index cc44cd1..dca23fb 100644 --- a/test/features/settings/bloc/settings_cubit_test.dart +++ b/test/features/settings/bloc/settings_cubit_test.dart @@ -21,7 +21,7 @@ void main() { group('SettingsCubit', () { test('initial state has default values', () { final cubit = SettingsCubit(database: database); - expect(cubit.state.themePalette, AppThemePalette.oxocarbon); + expect(cubit.state.themePalette, AppThemePalette.lazurite); expect(cubit.state.themeVariant, AppThemeVariant.dark); expect(cubit.state.useSystemTheme, false); expect(cubit.state.feedLayout, FeedLayout.card); @@ -76,7 +76,7 @@ void main() { act: (cubit) => cubit.loadSettings(), expect: () => [ isA() - .having((s) => s.themePalette, 'themePalette', AppThemePalette.oxocarbon) + .having((s) => s.themePalette, 'themePalette', AppThemePalette.lazurite) .having((s) => s.themeVariant, 'themeVariant', AppThemeVariant.dark) .having((s) => s.useSystemTheme, 'useSystemTheme', false) .having((s) => s.feedLayout, 'feedLayout', FeedLayout.card)