2023-07-29 10:55:35 -04:00
|
|
|
// ignore_for_file: always_put_required_named_parameters_first
|
|
|
|
|
2023-07-28 20:36:05 -04:00
|
|
|
import 'dart:convert';
|
|
|
|
|
|
|
|
import 'package:flutter/material.dart';
|
2023-08-17 18:10:24 -04:00
|
|
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
2023-07-28 20:36:05 -04:00
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
|
|
|
|
import '../entities/preferences.dart';
|
|
|
|
import 'radix_generator.dart';
|
|
|
|
|
2023-08-17 18:10:24 -04:00
|
|
|
part 'theme_service.g.dart';
|
|
|
|
|
2023-07-29 10:55:35 -04:00
|
|
|
class ScaleColor {
|
|
|
|
ScaleColor({
|
|
|
|
required this.appBackground,
|
|
|
|
required this.subtleBackground,
|
|
|
|
required this.elementBackground,
|
|
|
|
required this.hoverElementBackground,
|
2023-09-24 15:30:54 -04:00
|
|
|
required this.activeElementBackground,
|
2023-07-29 10:55:35 -04:00
|
|
|
required this.subtleBorder,
|
|
|
|
required this.border,
|
|
|
|
required this.hoverBorder,
|
|
|
|
required this.background,
|
|
|
|
required this.hoverBackground,
|
|
|
|
required this.subtleText,
|
|
|
|
required this.text,
|
|
|
|
});
|
|
|
|
|
|
|
|
Color appBackground;
|
|
|
|
Color subtleBackground;
|
|
|
|
Color elementBackground;
|
|
|
|
Color hoverElementBackground;
|
2023-09-24 15:30:54 -04:00
|
|
|
Color activeElementBackground;
|
2023-07-29 10:55:35 -04:00
|
|
|
Color subtleBorder;
|
|
|
|
Color border;
|
|
|
|
Color hoverBorder;
|
|
|
|
Color background;
|
|
|
|
Color hoverBackground;
|
|
|
|
Color subtleText;
|
|
|
|
Color text;
|
2023-08-02 21:09:28 -04:00
|
|
|
|
|
|
|
ScaleColor copyWith(
|
|
|
|
{Color? appBackground,
|
|
|
|
Color? subtleBackground,
|
|
|
|
Color? elementBackground,
|
|
|
|
Color? hoverElementBackground,
|
2023-09-24 15:30:54 -04:00
|
|
|
Color? activeElementBackground,
|
2023-08-02 21:09:28 -04:00
|
|
|
Color? subtleBorder,
|
|
|
|
Color? border,
|
|
|
|
Color? hoverBorder,
|
|
|
|
Color? background,
|
|
|
|
Color? hoverBackground,
|
|
|
|
Color? subtleText,
|
|
|
|
Color? text}) =>
|
|
|
|
ScaleColor(
|
|
|
|
appBackground: appBackground ?? this.appBackground,
|
|
|
|
subtleBackground: subtleBackground ?? this.subtleBackground,
|
|
|
|
elementBackground: elementBackground ?? this.elementBackground,
|
|
|
|
hoverElementBackground:
|
|
|
|
hoverElementBackground ?? this.hoverElementBackground,
|
2023-09-24 15:30:54 -04:00
|
|
|
activeElementBackground:
|
|
|
|
activeElementBackground ?? this.activeElementBackground,
|
2023-08-02 21:09:28 -04:00
|
|
|
subtleBorder: subtleBorder ?? this.subtleBorder,
|
|
|
|
border: border ?? this.border,
|
|
|
|
hoverBorder: hoverBorder ?? this.hoverBorder,
|
|
|
|
background: background ?? this.background,
|
|
|
|
hoverBackground: hoverBackground ?? this.hoverBackground,
|
|
|
|
subtleText: subtleText ?? this.subtleText,
|
|
|
|
text: text ?? this.text,
|
|
|
|
);
|
|
|
|
|
|
|
|
// ignore: prefer_constructors_over_static_methods
|
|
|
|
static ScaleColor lerp(ScaleColor a, ScaleColor b, double t) => ScaleColor(
|
|
|
|
appBackground: Color.lerp(a.appBackground, b.appBackground, t) ??
|
|
|
|
const Color(0x00000000),
|
|
|
|
subtleBackground:
|
|
|
|
Color.lerp(a.subtleBackground, b.subtleBackground, t) ??
|
|
|
|
const Color(0x00000000),
|
|
|
|
elementBackground:
|
|
|
|
Color.lerp(a.elementBackground, b.elementBackground, t) ??
|
|
|
|
const Color(0x00000000),
|
|
|
|
hoverElementBackground:
|
|
|
|
Color.lerp(a.hoverElementBackground, b.hoverElementBackground, t) ??
|
|
|
|
const Color(0x00000000),
|
2023-09-24 15:30:54 -04:00
|
|
|
activeElementBackground: Color.lerp(
|
|
|
|
a.activeElementBackground, b.activeElementBackground, t) ??
|
2023-08-02 21:09:28 -04:00
|
|
|
const Color(0x00000000),
|
|
|
|
subtleBorder: Color.lerp(a.subtleBorder, b.subtleBorder, t) ??
|
|
|
|
const Color(0x00000000),
|
|
|
|
border: Color.lerp(a.border, b.border, t) ?? const Color(0x00000000),
|
|
|
|
hoverBorder: Color.lerp(a.hoverBorder, b.hoverBorder, t) ??
|
|
|
|
const Color(0x00000000),
|
|
|
|
background: Color.lerp(a.background, b.background, t) ??
|
|
|
|
const Color(0x00000000),
|
|
|
|
hoverBackground: Color.lerp(a.hoverBackground, b.hoverBackground, t) ??
|
|
|
|
const Color(0x00000000),
|
|
|
|
subtleText: Color.lerp(a.subtleText, b.subtleText, t) ??
|
|
|
|
const Color(0x00000000),
|
|
|
|
text: Color.lerp(a.text, b.text, t) ?? const Color(0x00000000),
|
|
|
|
);
|
2023-07-29 10:55:35 -04:00
|
|
|
}
|
|
|
|
|
2023-08-02 21:09:28 -04:00
|
|
|
class ScaleScheme extends ThemeExtension<ScaleScheme> {
|
2023-07-29 10:55:35 -04:00
|
|
|
ScaleScheme(
|
|
|
|
{required this.primaryScale,
|
|
|
|
required this.primaryAlphaScale,
|
|
|
|
required this.secondaryScale,
|
|
|
|
required this.tertiaryScale,
|
|
|
|
required this.grayScale,
|
|
|
|
required this.errorScale});
|
|
|
|
|
2023-08-02 21:09:28 -04:00
|
|
|
final ScaleColor primaryScale;
|
|
|
|
final ScaleColor primaryAlphaScale;
|
|
|
|
final ScaleColor secondaryScale;
|
|
|
|
final ScaleColor tertiaryScale;
|
|
|
|
final ScaleColor grayScale;
|
|
|
|
final ScaleColor errorScale;
|
|
|
|
|
|
|
|
@override
|
|
|
|
ScaleScheme copyWith(
|
|
|
|
{ScaleColor? primaryScale,
|
|
|
|
ScaleColor? primaryAlphaScale,
|
|
|
|
ScaleColor? secondaryScale,
|
|
|
|
ScaleColor? tertiaryScale,
|
|
|
|
ScaleColor? grayScale,
|
|
|
|
ScaleColor? errorScale}) =>
|
|
|
|
ScaleScheme(
|
|
|
|
primaryScale: primaryScale ?? this.primaryScale,
|
|
|
|
primaryAlphaScale: primaryAlphaScale ?? this.primaryAlphaScale,
|
|
|
|
secondaryScale: secondaryScale ?? this.secondaryScale,
|
|
|
|
tertiaryScale: tertiaryScale ?? this.tertiaryScale,
|
|
|
|
grayScale: grayScale ?? this.grayScale,
|
|
|
|
errorScale: errorScale ?? this.errorScale,
|
|
|
|
);
|
|
|
|
|
|
|
|
@override
|
|
|
|
ScaleScheme lerp(ScaleScheme? other, double t) {
|
|
|
|
if (other is! ScaleScheme) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
return ScaleScheme(
|
|
|
|
primaryScale: ScaleColor.lerp(primaryScale, other.primaryScale, t),
|
|
|
|
primaryAlphaScale:
|
|
|
|
ScaleColor.lerp(primaryAlphaScale, other.primaryAlphaScale, t),
|
|
|
|
secondaryScale: ScaleColor.lerp(secondaryScale, other.secondaryScale, t),
|
|
|
|
tertiaryScale: ScaleColor.lerp(tertiaryScale, other.tertiaryScale, t),
|
|
|
|
grayScale: ScaleColor.lerp(grayScale, other.grayScale, t),
|
|
|
|
errorScale: ScaleColor.lerp(errorScale, other.errorScale, t),
|
|
|
|
);
|
|
|
|
}
|
2023-07-29 10:55:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2023-07-28 20:36:05 -04:00
|
|
|
class ThemeService {
|
|
|
|
ThemeService._();
|
|
|
|
static late SharedPreferences prefs;
|
|
|
|
static ThemeService? _instance;
|
|
|
|
|
|
|
|
static Future<ThemeService> get instance async {
|
|
|
|
if (_instance == null) {
|
|
|
|
prefs = await SharedPreferences.getInstance();
|
|
|
|
_instance = ThemeService._();
|
|
|
|
}
|
|
|
|
return _instance!;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool get isPlatformDark =>
|
|
|
|
WidgetsBinding.instance.platformDispatcher.platformBrightness ==
|
|
|
|
Brightness.dark;
|
|
|
|
|
|
|
|
ThemeData get initial {
|
2023-08-17 18:10:24 -04:00
|
|
|
final themePreferences = load();
|
2023-07-28 20:36:05 -04:00
|
|
|
return get(themePreferences);
|
|
|
|
}
|
|
|
|
|
2023-08-17 18:10:24 -04:00
|
|
|
ThemePreferences load() {
|
|
|
|
final themePreferencesJson = prefs.getString('themePreferences');
|
|
|
|
ThemePreferences? themePreferences;
|
|
|
|
if (themePreferencesJson != null) {
|
|
|
|
try {
|
2023-08-27 11:51:42 -04:00
|
|
|
themePreferences =
|
|
|
|
ThemePreferences.fromJson(jsonDecode(themePreferencesJson));
|
2023-08-17 18:10:24 -04:00
|
|
|
// ignore: avoid_catches_without_on_clauses
|
|
|
|
} catch (_) {
|
|
|
|
// ignore
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return themePreferences ??
|
|
|
|
const ThemePreferences(
|
|
|
|
colorPreference: ColorPreference.vapor,
|
|
|
|
brightnessPreference: BrightnessPreference.system,
|
|
|
|
displayScale: 1,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-07-28 20:36:05 -04:00
|
|
|
Future<void> save(ThemePreferences themePreferences) async {
|
|
|
|
await prefs.setString(
|
|
|
|
'themePreferences', jsonEncode(themePreferences.toJson()));
|
|
|
|
}
|
|
|
|
|
|
|
|
ThemeData get(ThemePreferences themePreferences) {
|
|
|
|
late final Brightness brightness;
|
|
|
|
switch (themePreferences.brightnessPreference) {
|
|
|
|
case BrightnessPreference.system:
|
|
|
|
if (isPlatformDark) {
|
|
|
|
brightness = Brightness.dark;
|
|
|
|
} else {
|
|
|
|
brightness = Brightness.light;
|
|
|
|
}
|
|
|
|
case BrightnessPreference.light:
|
|
|
|
brightness = Brightness.light;
|
|
|
|
case BrightnessPreference.dark:
|
|
|
|
brightness = Brightness.dark;
|
|
|
|
}
|
|
|
|
|
|
|
|
late final ThemeData themeData;
|
|
|
|
switch (themePreferences.colorPreference) {
|
|
|
|
// Special cases
|
|
|
|
case ColorPreference.contrast:
|
|
|
|
// xxx do contrastGenerator
|
|
|
|
themeData = radixGenerator(brightness, RadixThemeColor.grim);
|
|
|
|
// Generate from Radix
|
|
|
|
case ColorPreference.scarlet:
|
|
|
|
themeData = radixGenerator(brightness, RadixThemeColor.scarlet);
|
|
|
|
case ColorPreference.babydoll:
|
|
|
|
themeData = radixGenerator(brightness, RadixThemeColor.babydoll);
|
|
|
|
case ColorPreference.vapor:
|
|
|
|
themeData = radixGenerator(brightness, RadixThemeColor.vapor);
|
|
|
|
case ColorPreference.gold:
|
|
|
|
themeData = radixGenerator(brightness, RadixThemeColor.gold);
|
|
|
|
case ColorPreference.garden:
|
|
|
|
themeData = radixGenerator(brightness, RadixThemeColor.garden);
|
|
|
|
case ColorPreference.forest:
|
|
|
|
themeData = radixGenerator(brightness, RadixThemeColor.forest);
|
|
|
|
case ColorPreference.arctic:
|
|
|
|
themeData = radixGenerator(brightness, RadixThemeColor.arctic);
|
|
|
|
case ColorPreference.lapis:
|
|
|
|
themeData = radixGenerator(brightness, RadixThemeColor.lapis);
|
|
|
|
case ColorPreference.eggplant:
|
|
|
|
themeData = radixGenerator(brightness, RadixThemeColor.eggplant);
|
|
|
|
case ColorPreference.lime:
|
|
|
|
themeData = radixGenerator(brightness, RadixThemeColor.lime);
|
|
|
|
case ColorPreference.grim:
|
|
|
|
themeData = radixGenerator(brightness, RadixThemeColor.grim);
|
|
|
|
}
|
|
|
|
|
|
|
|
return themeData;
|
|
|
|
}
|
|
|
|
}
|
2023-08-17 18:10:24 -04:00
|
|
|
|
|
|
|
@riverpod
|
2023-08-27 11:51:42 -04:00
|
|
|
FutureOr<ThemeService> themeService(ThemeServiceRef ref) async =>
|
|
|
|
await ThemeService.instance;
|