break everything

This commit is contained in:
Christien Rioux 2023-12-26 20:26:54 -05:00
parent e898074387
commit 29210c89d2
121 changed files with 2892 additions and 2608 deletions

View file

@ -0,0 +1,51 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import '../../tools/tools.dart';
import '../../veilid_init.dart';
import '../../veilid_support/veilid_support.dart';
abstract class AsyncTableDBBackedCubit<State> extends Cubit<AsyncValue<State>>
with TableDBBacked<State> {
AsyncTableDBBackedCubit() : super(const AsyncValue.loading()) {
unawaited(Future.delayed(Duration.zero, _build));
}
Future<void> _build() async {
try {
await eventualVeilid.future;
emit(AsyncValue.data(await load()));
} on Exception catch (e, stackTrace) {
emit(AsyncValue.error(e, stackTrace));
}
}
Future<State> readyData() async {
final stateStream = stream.distinct();
await for (final AsyncValue<State> av in stateStream) {
final d = av.when(
data: (value) => value, loading: () => null, error: (e, s) => null);
if (d != null) {
return d;
}
final ef = av.when(
data: (value) => null,
loading: () => null,
error: Future<State>.error);
if (ef != null) {
return ef;
}
}
return Future<State>.error(
StateError("data never became ready in cubit '$runtimeType'"));
}
Future<void> setState(State newState) async {
try {
emit(AsyncValue.data(await store(newState)));
} on Exception catch (e, stackTrace) {
emit(AsyncValue.error(e, stackTrace));
}
}
}

172
lib/tools/async_value.dart Normal file
View file

@ -0,0 +1,172 @@
// ignore_for_file: avoid_catches_without_on_clauses
import 'package:freezed_annotation/freezed_annotation.dart';
part 'async_value.freezed.dart';
/// An utility for safely manipulating asynchronous data.
///
/// By using [AsyncValue], you are guaranteed that you cannot forget to
/// handle the loading/error state of an asynchronous operation.
///
/// It also expose some utilities to nicely convert an [AsyncValue] to
/// a different object.
/// For example, a Flutter Widget may use [when] to convert an [AsyncValue]
/// into either a progress indicator, an error screen, or to show the data:
///
/// ```dart
/// /// A provider that asynchronously expose the current user
/// final userProvider = StreamProvider<User>((_) async* {
/// // fetch the user
/// });
///
/// class Example extends ConsumerWidget {
/// @override
/// Widget build(BuildContext context, ScopedReader watch) {
/// final AsyncValue<User> user = watch(userProvider);
///
/// return user.when(
/// loading: () => CircularProgressIndicator(),
/// error: (error, stack) => Text('Oops, something unexpected happened'),
/// data: (value) => Text('Hello ${user.name}'),
/// );
/// }
/// }
/// ```
///
/// If a consumer of an [AsyncValue] does not care about the loading/error
/// state, consider using [data] to read the state:
///
/// ```dart
/// Widget build(BuildContext context, ScopedReader watch) {
/// // reads the data state directly will be null during loading/error states
/// final User user = watch(userProvider).data?.value;
///
/// return Text('Hello ${user?.name}');
/// }
/// ```
///
/// See also:
///
/// - [AsyncValue.guard], to simplify transforming a [Future] into an
/// [AsyncValue].
/// - The package Freezed (https://github.com/rrousselgit/freezed), which have
/// generated this [AsyncValue] class and explains how [map]/[when] works.
@freezed
@sealed
abstract class AsyncValue<T> with _$AsyncValue<T> {
const AsyncValue._();
/// Creates an [AsyncValue] with a data.
///
/// The data can be `null`.
const factory AsyncValue.data(T value) = AsyncData<T>;
/// Creates an [AsyncValue] in loading state.
///
/// Prefer always using this constructor with the `const` keyword.
const factory AsyncValue.loading() = AsyncLoading<T>;
/// Creates an [AsyncValue] in error state.
///
/// The parameter [error] cannot be `null`.
factory AsyncValue.error(Object error, [StackTrace? stackTrace]) =
AsyncError<T>;
/// Transforms a [Future] that may fail into something that is safe to read.
///
/// This is useful to avoid having to do a tedious `try/catch`. Instead of:
///
/// ```dart
/// class MyNotifier extends StateNotifier<AsyncValue<MyData> {
/// MyNotifier(): super(const AsyncValue.loading()) {
/// _fetchData();
/// }
///
/// Future<void> _fetchData() async {
/// state = const AsyncValue.loading();
/// try {
/// final response = await dio.get('my_api/data');
/// final data = MyData.fromJson(response);
/// state = AsyncValue.data(data);
/// } catch (err, stack) {
/// state = AsyncValue.error(err, stack);
/// }
/// }
/// }
/// ```
///
/// which is redundant as the application grows and we need more and more of
/// this pattern we can use [guard] to simplify it:
///
///
/// ```dart
/// class MyNotifier extends StateNotifier<AsyncValue<MyData>> {
/// MyNotifier(): super(const AsyncValue.loading()) {
/// _fetchData();
/// }
///
/// Future<void> _fetchData() async {
/// state = const AsyncValue.loading();
/// // does the try/catch for us like previously
/// state = await AsyncValue.guard(() async {
/// final response = await dio.get('my_api/data');
/// return Data.fromJson(response);
/// });
/// }
/// }
/// ```
static Future<AsyncValue<T>> guard<T>(Future<T> Function() future) async {
try {
return AsyncValue.data(await future());
} catch (err, stack) {
return AsyncValue.error(err, stack);
}
}
/// The current data, or null if in loading/error.
///
/// This is safe to use, as Dart (will) have non-nullable types.
/// As such reading [data] still forces to handle the loading/error cases
/// by having to check `data != null`.
///
/// ## Why does [AsyncValue<T>.data] return [AsyncData<T>] instead of [T]?
///
/// The motivation behind this decision is to allow differentiating between:
///
/// - There is a data, and it is `null`.
/// ```dart
/// // There is a data, and it is "null"
/// AsyncValue<Configuration> configs = AsyncValue.data(null);
///
/// print(configs.data); // AsyncValue(value: null)
/// print(configs.data.value); // null
/// ```
///
/// - There is no data. [AsyncValue] is currently in loading/error state.
/// ```dart
/// // No data, currently loading
/// AsyncValue<Configuration> configs = AsyncValue.loading();
///
/// print(configs.data); // null, currently loading
/// print(configs.data.value); // throws null exception
/// ```
AsyncData<T>? get data => map(
data: (data) => data,
loading: (_) => null,
error: (_) => null,
);
/// Shorthand for [when] to handle only the `data` case.
AsyncValue<R> whenData<R>(R Function(T value) cb) => when(
data: (value) {
try {
return AsyncValue.data(cb(value));
} catch (err, stack) {
return AsyncValue.error(err, stack);
}
},
loading: () => const AsyncValue.loading(),
error: AsyncValue.error,
);
}

View file

@ -0,0 +1,480 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'async_value.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
/// @nodoc
mixin _$AsyncValue<T> {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(T value) data,
required TResult Function() loading,
required TResult Function(Object error, StackTrace? stackTrace) error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(T value)? data,
TResult? Function()? loading,
TResult? Function(Object error, StackTrace? stackTrace)? error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(T value)? data,
TResult Function()? loading,
TResult Function(Object error, StackTrace? stackTrace)? error,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(AsyncData<T> value) data,
required TResult Function(AsyncLoading<T> value) loading,
required TResult Function(AsyncError<T> value) error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(AsyncData<T> value)? data,
TResult? Function(AsyncLoading<T> value)? loading,
TResult? Function(AsyncError<T> value)? error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(AsyncData<T> value)? data,
TResult Function(AsyncLoading<T> value)? loading,
TResult Function(AsyncError<T> value)? error,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $AsyncValueCopyWith<T, $Res> {
factory $AsyncValueCopyWith(
AsyncValue<T> value, $Res Function(AsyncValue<T>) then) =
_$AsyncValueCopyWithImpl<T, $Res, AsyncValue<T>>;
}
/// @nodoc
class _$AsyncValueCopyWithImpl<T, $Res, $Val extends AsyncValue<T>>
implements $AsyncValueCopyWith<T, $Res> {
_$AsyncValueCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
}
/// @nodoc
abstract class _$$AsyncDataImplCopyWith<T, $Res> {
factory _$$AsyncDataImplCopyWith(
_$AsyncDataImpl<T> value, $Res Function(_$AsyncDataImpl<T>) then) =
__$$AsyncDataImplCopyWithImpl<T, $Res>;
@useResult
$Res call({T value});
}
/// @nodoc
class __$$AsyncDataImplCopyWithImpl<T, $Res>
extends _$AsyncValueCopyWithImpl<T, $Res, _$AsyncDataImpl<T>>
implements _$$AsyncDataImplCopyWith<T, $Res> {
__$$AsyncDataImplCopyWithImpl(
_$AsyncDataImpl<T> _value, $Res Function(_$AsyncDataImpl<T>) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? value = freezed,
}) {
return _then(_$AsyncDataImpl<T>(
freezed == value
? _value.value
: value // ignore: cast_nullable_to_non_nullable
as T,
));
}
}
/// @nodoc
class _$AsyncDataImpl<T> extends AsyncData<T> {
const _$AsyncDataImpl(this.value) : super._();
@override
final T value;
@override
String toString() {
return 'AsyncValue<$T>.data(value: $value)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$AsyncDataImpl<T> &&
const DeepCollectionEquality().equals(other.value, value));
}
@override
int get hashCode =>
Object.hash(runtimeType, const DeepCollectionEquality().hash(value));
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$AsyncDataImplCopyWith<T, _$AsyncDataImpl<T>> get copyWith =>
__$$AsyncDataImplCopyWithImpl<T, _$AsyncDataImpl<T>>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(T value) data,
required TResult Function() loading,
required TResult Function(Object error, StackTrace? stackTrace) error,
}) {
return data(value);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(T value)? data,
TResult? Function()? loading,
TResult? Function(Object error, StackTrace? stackTrace)? error,
}) {
return data?.call(value);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(T value)? data,
TResult Function()? loading,
TResult Function(Object error, StackTrace? stackTrace)? error,
required TResult orElse(),
}) {
if (data != null) {
return data(value);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(AsyncData<T> value) data,
required TResult Function(AsyncLoading<T> value) loading,
required TResult Function(AsyncError<T> value) error,
}) {
return data(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(AsyncData<T> value)? data,
TResult? Function(AsyncLoading<T> value)? loading,
TResult? Function(AsyncError<T> value)? error,
}) {
return data?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(AsyncData<T> value)? data,
TResult Function(AsyncLoading<T> value)? loading,
TResult Function(AsyncError<T> value)? error,
required TResult orElse(),
}) {
if (data != null) {
return data(this);
}
return orElse();
}
}
abstract class AsyncData<T> extends AsyncValue<T> {
const factory AsyncData(final T value) = _$AsyncDataImpl<T>;
const AsyncData._() : super._();
T get value;
@JsonKey(ignore: true)
_$$AsyncDataImplCopyWith<T, _$AsyncDataImpl<T>> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$$AsyncLoadingImplCopyWith<T, $Res> {
factory _$$AsyncLoadingImplCopyWith(_$AsyncLoadingImpl<T> value,
$Res Function(_$AsyncLoadingImpl<T>) then) =
__$$AsyncLoadingImplCopyWithImpl<T, $Res>;
}
/// @nodoc
class __$$AsyncLoadingImplCopyWithImpl<T, $Res>
extends _$AsyncValueCopyWithImpl<T, $Res, _$AsyncLoadingImpl<T>>
implements _$$AsyncLoadingImplCopyWith<T, $Res> {
__$$AsyncLoadingImplCopyWithImpl(
_$AsyncLoadingImpl<T> _value, $Res Function(_$AsyncLoadingImpl<T>) _then)
: super(_value, _then);
}
/// @nodoc
class _$AsyncLoadingImpl<T> extends AsyncLoading<T> {
const _$AsyncLoadingImpl() : super._();
@override
String toString() {
return 'AsyncValue<$T>.loading()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$AsyncLoadingImpl<T>);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(T value) data,
required TResult Function() loading,
required TResult Function(Object error, StackTrace? stackTrace) error,
}) {
return loading();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(T value)? data,
TResult? Function()? loading,
TResult? Function(Object error, StackTrace? stackTrace)? error,
}) {
return loading?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(T value)? data,
TResult Function()? loading,
TResult Function(Object error, StackTrace? stackTrace)? error,
required TResult orElse(),
}) {
if (loading != null) {
return loading();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(AsyncData<T> value) data,
required TResult Function(AsyncLoading<T> value) loading,
required TResult Function(AsyncError<T> value) error,
}) {
return loading(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(AsyncData<T> value)? data,
TResult? Function(AsyncLoading<T> value)? loading,
TResult? Function(AsyncError<T> value)? error,
}) {
return loading?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(AsyncData<T> value)? data,
TResult Function(AsyncLoading<T> value)? loading,
TResult Function(AsyncError<T> value)? error,
required TResult orElse(),
}) {
if (loading != null) {
return loading(this);
}
return orElse();
}
}
abstract class AsyncLoading<T> extends AsyncValue<T> {
const factory AsyncLoading() = _$AsyncLoadingImpl<T>;
const AsyncLoading._() : super._();
}
/// @nodoc
abstract class _$$AsyncErrorImplCopyWith<T, $Res> {
factory _$$AsyncErrorImplCopyWith(
_$AsyncErrorImpl<T> value, $Res Function(_$AsyncErrorImpl<T>) then) =
__$$AsyncErrorImplCopyWithImpl<T, $Res>;
@useResult
$Res call({Object error, StackTrace? stackTrace});
}
/// @nodoc
class __$$AsyncErrorImplCopyWithImpl<T, $Res>
extends _$AsyncValueCopyWithImpl<T, $Res, _$AsyncErrorImpl<T>>
implements _$$AsyncErrorImplCopyWith<T, $Res> {
__$$AsyncErrorImplCopyWithImpl(
_$AsyncErrorImpl<T> _value, $Res Function(_$AsyncErrorImpl<T>) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? error = null,
Object? stackTrace = freezed,
}) {
return _then(_$AsyncErrorImpl<T>(
null == error ? _value.error : error,
freezed == stackTrace
? _value.stackTrace
: stackTrace // ignore: cast_nullable_to_non_nullable
as StackTrace?,
));
}
}
/// @nodoc
class _$AsyncErrorImpl<T> extends AsyncError<T> {
_$AsyncErrorImpl(this.error, [this.stackTrace]) : super._();
@override
final Object error;
@override
final StackTrace? stackTrace;
@override
String toString() {
return 'AsyncValue<$T>.error(error: $error, stackTrace: $stackTrace)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$AsyncErrorImpl<T> &&
const DeepCollectionEquality().equals(other.error, error) &&
(identical(other.stackTrace, stackTrace) ||
other.stackTrace == stackTrace));
}
@override
int get hashCode => Object.hash(
runtimeType, const DeepCollectionEquality().hash(error), stackTrace);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$AsyncErrorImplCopyWith<T, _$AsyncErrorImpl<T>> get copyWith =>
__$$AsyncErrorImplCopyWithImpl<T, _$AsyncErrorImpl<T>>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(T value) data,
required TResult Function() loading,
required TResult Function(Object error, StackTrace? stackTrace) error,
}) {
return error(this.error, stackTrace);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(T value)? data,
TResult? Function()? loading,
TResult? Function(Object error, StackTrace? stackTrace)? error,
}) {
return error?.call(this.error, stackTrace);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(T value)? data,
TResult Function()? loading,
TResult Function(Object error, StackTrace? stackTrace)? error,
required TResult orElse(),
}) {
if (error != null) {
return error(this.error, stackTrace);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(AsyncData<T> value) data,
required TResult Function(AsyncLoading<T> value) loading,
required TResult Function(AsyncError<T> value) error,
}) {
return error(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(AsyncData<T> value)? data,
TResult? Function(AsyncLoading<T> value)? loading,
TResult? Function(AsyncError<T> value)? error,
}) {
return error?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(AsyncData<T> value)? data,
TResult Function(AsyncLoading<T> value)? loading,
TResult Function(AsyncError<T> value)? error,
required TResult orElse(),
}) {
if (error != null) {
return error(this);
}
return orElse();
}
}
abstract class AsyncError<T> extends AsyncValue<T> {
factory AsyncError(final Object error, [final StackTrace? stackTrace]) =
_$AsyncErrorImpl<T>;
AsyncError._() : super._();
Object get error;
StackTrace? get stackTrace;
@JsonKey(ignore: true)
_$$AsyncErrorImplCopyWith<T, _$AsyncErrorImpl<T>> get copyWith =>
throw _privateConstructorUsedError;
}

View file

@ -1,13 +1,15 @@
import 'dart:io' show Platform;
import 'package:ansicolor/ansicolor.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:intl/intl.dart';
import 'package:loggy/loggy.dart';
import '../pages/developer.dart';
import '../old_to_refactor/pages/developer.dart';
import '../veilid_support/veilid_support.dart';
import 'state_logger.dart';
String wrapWithLogColor(LogLevel? level, String text) {
// XXX: https://github.com/flutter/flutter/issues/64491
@ -149,4 +151,7 @@ void initLoggy() {
}
Loggy('').level = getLogOptions(logLevel);
// Create state logger
Bloc.observer = const StateLogger();
}

View file

@ -1,551 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_chat_ui/flutter_chat_ui.dart';
import 'package:radix_colors/radix_colors.dart';
import 'theme_service.dart';
enum RadixThemeColor {
scarlet, // tomato + red + violet
babydoll, // crimson + purple + pink
vapor, // pink + cyan + plum
gold, // yellow + amber + orange
garden, // grass + orange + brown
forest, // green + brown + amber
arctic, // sky + teal + violet
lapis, // blue + indigo + mint
eggplant, // violet + purple + indigo
lime, // lime + yellow + orange
grim, // mauve + slate + sage
}
enum _RadixBaseColor {
tomato,
red,
crimson,
pink,
plum,
purple,
violet,
indigo,
blue,
sky,
cyan,
teal,
mint,
green,
grass,
lime,
yellow,
amber,
orange,
brown,
}
RadixColor _radixGraySteps(
Brightness brightness, bool alpha, _RadixBaseColor baseColor) {
switch (baseColor) {
case _RadixBaseColor.tomato:
case _RadixBaseColor.red:
case _RadixBaseColor.crimson:
case _RadixBaseColor.pink:
case _RadixBaseColor.plum:
case _RadixBaseColor.purple:
case _RadixBaseColor.violet:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.mauveA
: RadixColors.mauveA)
: (brightness == Brightness.dark
? RadixColors.dark.mauve
: RadixColors.mauve);
case _RadixBaseColor.indigo:
case _RadixBaseColor.blue:
case _RadixBaseColor.sky:
case _RadixBaseColor.cyan:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.slateA
: RadixColors.slateA)
: (brightness == Brightness.dark
? RadixColors.dark.slate
: RadixColors.slate);
case _RadixBaseColor.teal:
case _RadixBaseColor.mint:
case _RadixBaseColor.green:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.sageA
: RadixColors.sageA)
: (brightness == Brightness.dark
? RadixColors.dark.sage
: RadixColors.sage);
case _RadixBaseColor.lime:
case _RadixBaseColor.grass:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.oliveA
: RadixColors.oliveA)
: (brightness == Brightness.dark
? RadixColors.dark.olive
: RadixColors.olive);
case _RadixBaseColor.yellow:
case _RadixBaseColor.amber:
case _RadixBaseColor.orange:
case _RadixBaseColor.brown:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.sandA
: RadixColors.sandA)
: (brightness == Brightness.dark
? RadixColors.dark.sand
: RadixColors.sand);
}
}
RadixColor _radixColorSteps(
Brightness brightness, bool alpha, _RadixBaseColor baseColor) {
switch (baseColor) {
case _RadixBaseColor.tomato:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.tomatoA
: RadixColors.tomatoA)
: (brightness == Brightness.dark
? RadixColors.dark.tomato
: RadixColors.tomato);
case _RadixBaseColor.red:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.redA
: RadixColors.redA)
: (brightness == Brightness.dark
? RadixColors.dark.red
: RadixColors.red);
case _RadixBaseColor.crimson:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.crimsonA
: RadixColors.crimsonA)
: (brightness == Brightness.dark
? RadixColors.dark.crimson
: RadixColors.crimson);
case _RadixBaseColor.pink:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.pinkA
: RadixColors.pinkA)
: (brightness == Brightness.dark
? RadixColors.dark.pink
: RadixColors.pink);
case _RadixBaseColor.plum:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.plumA
: RadixColors.plumA)
: (brightness == Brightness.dark
? RadixColors.dark.plum
: RadixColors.plum);
case _RadixBaseColor.purple:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.purpleA
: RadixColors.purpleA)
: (brightness == Brightness.dark
? RadixColors.dark.purple
: RadixColors.purple);
case _RadixBaseColor.violet:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.violetA
: RadixColors.violetA)
: (brightness == Brightness.dark
? RadixColors.dark.violet
: RadixColors.violet);
case _RadixBaseColor.indigo:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.indigoA
: RadixColors.indigoA)
: (brightness == Brightness.dark
? RadixColors.dark.indigo
: RadixColors.indigo);
case _RadixBaseColor.blue:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.blueA
: RadixColors.blueA)
: (brightness == Brightness.dark
? RadixColors.dark.blue
: RadixColors.blue);
case _RadixBaseColor.sky:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.skyA
: RadixColors.skyA)
: (brightness == Brightness.dark
? RadixColors.dark.sky
: RadixColors.sky);
case _RadixBaseColor.cyan:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.cyanA
: RadixColors.cyanA)
: (brightness == Brightness.dark
? RadixColors.dark.cyan
: RadixColors.cyan);
case _RadixBaseColor.teal:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.tealA
: RadixColors.tealA)
: (brightness == Brightness.dark
? RadixColors.dark.teal
: RadixColors.teal);
case _RadixBaseColor.mint:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.mintA
: RadixColors.mintA)
: (brightness == Brightness.dark
? RadixColors.dark.mint
: RadixColors.mint);
case _RadixBaseColor.green:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.greenA
: RadixColors.greenA)
: (brightness == Brightness.dark
? RadixColors.dark.green
: RadixColors.green);
case _RadixBaseColor.grass:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.grassA
: RadixColors.grassA)
: (brightness == Brightness.dark
? RadixColors.dark.grass
: RadixColors.grass);
case _RadixBaseColor.lime:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.limeA
: RadixColors.limeA)
: (brightness == Brightness.dark
? RadixColors.dark.lime
: RadixColors.lime);
case _RadixBaseColor.yellow:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.yellowA
: RadixColors.yellowA)
: (brightness == Brightness.dark
? RadixColors.dark.yellow
: RadixColors.yellow);
case _RadixBaseColor.amber:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.amberA
: RadixColors.amberA)
: (brightness == Brightness.dark
? RadixColors.dark.amber
: RadixColors.amber);
case _RadixBaseColor.orange:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.orangeA
: RadixColors.orangeA)
: (brightness == Brightness.dark
? RadixColors.dark.orange
: RadixColors.orange);
case _RadixBaseColor.brown:
return alpha
? (brightness == Brightness.dark
? RadixColors.dark.brownA
: RadixColors.brownA)
: (brightness == Brightness.dark
? RadixColors.dark.brown
: RadixColors.brown);
}
}
extension ToScaleColor on RadixColor {
ScaleColor toScale() => ScaleColor(
appBackground: step1,
subtleBackground: step2,
elementBackground: step3,
hoverElementBackground: step4,
activeElementBackground: step5,
subtleBorder: step6,
border: step7,
hoverBorder: step8,
background: step9,
hoverBackground: step10,
subtleText: step11,
text: step12,
);
}
class RadixScheme {
RadixScheme(
{required this.primaryScale,
required this.primaryAlphaScale,
required this.secondaryScale,
required this.tertiaryScale,
required this.grayScale,
required this.errorScale});
RadixColor primaryScale;
RadixColor primaryAlphaScale;
RadixColor secondaryScale;
RadixColor tertiaryScale;
RadixColor grayScale;
RadixColor errorScale;
ScaleScheme toScale() => ScaleScheme(
primaryScale: primaryScale.toScale(),
primaryAlphaScale: primaryAlphaScale.toScale(),
secondaryScale: secondaryScale.toScale(),
tertiaryScale: tertiaryScale.toScale(),
grayScale: grayScale.toScale(),
errorScale: errorScale.toScale(),
);
}
RadixScheme _radixScheme(Brightness brightness, RadixThemeColor themeColor) {
late RadixScheme radixScheme;
switch (themeColor) {
// tomato + red + violet
case RadixThemeColor.scarlet:
radixScheme = RadixScheme(
primaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.tomato),
primaryAlphaScale:
_radixColorSteps(brightness, true, _RadixBaseColor.tomato),
secondaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.red),
tertiaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.violet),
grayScale: _radixGraySteps(brightness, false, _RadixBaseColor.tomato),
errorScale:
_radixColorSteps(brightness, false, _RadixBaseColor.yellow));
// crimson + purple + pink
case RadixThemeColor.babydoll:
radixScheme = RadixScheme(
primaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.crimson),
primaryAlphaScale:
_radixColorSteps(brightness, true, _RadixBaseColor.crimson),
secondaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.purple),
tertiaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.pink),
grayScale:
_radixGraySteps(brightness, false, _RadixBaseColor.crimson),
errorScale:
_radixColorSteps(brightness, false, _RadixBaseColor.orange));
// pink + cyan + plum
case RadixThemeColor.vapor:
radixScheme = RadixScheme(
primaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.pink),
primaryAlphaScale:
_radixColorSteps(brightness, true, _RadixBaseColor.pink),
secondaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.cyan),
tertiaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.plum),
grayScale: _radixGraySteps(brightness, false, _RadixBaseColor.pink),
errorScale: _radixColorSteps(brightness, false, _RadixBaseColor.red));
// yellow + amber + orange
case RadixThemeColor.gold:
radixScheme = RadixScheme(
primaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.yellow),
primaryAlphaScale:
_radixColorSteps(brightness, true, _RadixBaseColor.yellow),
secondaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.amber),
tertiaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.orange),
grayScale: _radixGraySteps(brightness, false, _RadixBaseColor.yellow),
errorScale: _radixColorSteps(brightness, false, _RadixBaseColor.red));
// grass + orange + brown
case RadixThemeColor.garden:
radixScheme = RadixScheme(
primaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.grass),
primaryAlphaScale:
_radixColorSteps(brightness, true, _RadixBaseColor.grass),
secondaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.orange),
tertiaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.brown),
grayScale: _radixGraySteps(brightness, false, _RadixBaseColor.grass),
errorScale:
_radixColorSteps(brightness, false, _RadixBaseColor.tomato));
// green + brown + amber
case RadixThemeColor.forest:
radixScheme = RadixScheme(
primaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.green),
primaryAlphaScale:
_radixColorSteps(brightness, true, _RadixBaseColor.green),
secondaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.brown),
tertiaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.amber),
grayScale: _radixGraySteps(brightness, false, _RadixBaseColor.green),
errorScale:
_radixColorSteps(brightness, false, _RadixBaseColor.tomato));
// sky + teal + violet
case RadixThemeColor.arctic:
radixScheme = RadixScheme(
primaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.sky),
primaryAlphaScale:
_radixColorSteps(brightness, true, _RadixBaseColor.sky),
secondaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.teal),
tertiaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.violet),
grayScale: _radixGraySteps(brightness, false, _RadixBaseColor.sky),
errorScale:
_radixColorSteps(brightness, false, _RadixBaseColor.crimson));
// blue + indigo + mint
case RadixThemeColor.lapis:
radixScheme = RadixScheme(
primaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.blue),
primaryAlphaScale:
_radixColorSteps(brightness, true, _RadixBaseColor.blue),
secondaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.indigo),
tertiaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.mint),
grayScale: _radixGraySteps(brightness, false, _RadixBaseColor.blue),
errorScale:
_radixColorSteps(brightness, false, _RadixBaseColor.crimson));
// violet + purple + indigo
case RadixThemeColor.eggplant:
radixScheme = RadixScheme(
primaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.violet),
primaryAlphaScale:
_radixColorSteps(brightness, true, _RadixBaseColor.violet),
secondaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.purple),
tertiaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.indigo),
grayScale: _radixGraySteps(brightness, false, _RadixBaseColor.violet),
errorScale:
_radixColorSteps(brightness, false, _RadixBaseColor.crimson));
// lime + yellow + orange
case RadixThemeColor.lime:
radixScheme = RadixScheme(
primaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.lime),
primaryAlphaScale:
_radixColorSteps(brightness, true, _RadixBaseColor.lime),
secondaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.yellow),
tertiaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.orange),
grayScale: _radixGraySteps(brightness, false, _RadixBaseColor.lime),
errorScale: _radixColorSteps(brightness, false, _RadixBaseColor.red));
// mauve + slate + sage
case RadixThemeColor.grim:
radixScheme = RadixScheme(
primaryScale:
_radixGraySteps(brightness, false, _RadixBaseColor.tomato),
primaryAlphaScale:
_radixColorSteps(brightness, true, _RadixBaseColor.tomato),
secondaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.indigo),
tertiaryScale:
_radixColorSteps(brightness, false, _RadixBaseColor.teal),
grayScale: brightness == Brightness.dark
? RadixColors.dark.gray
: RadixColors.gray,
errorScale: _radixColorSteps(brightness, false, _RadixBaseColor.red));
}
return radixScheme;
}
ColorScheme _radixColorScheme(Brightness brightness, RadixScheme radix) =>
ColorScheme(
brightness: brightness,
primary: radix.primaryScale.step9,
onPrimary: radix.primaryScale.step12,
primaryContainer: radix.primaryScale.step4,
onPrimaryContainer: radix.primaryScale.step11,
secondary: radix.secondaryScale.step9,
onSecondary: radix.secondaryScale.step12,
secondaryContainer: radix.secondaryScale.step3,
onSecondaryContainer: radix.secondaryScale.step11,
tertiary: radix.tertiaryScale.step9,
onTertiary: radix.tertiaryScale.step12,
tertiaryContainer: radix.tertiaryScale.step3,
onTertiaryContainer: radix.tertiaryScale.step11,
error: radix.errorScale.step9,
onError: radix.errorScale.step12,
errorContainer: radix.errorScale.step3,
onErrorContainer: radix.errorScale.step11,
background: radix.grayScale.step1,
onBackground: radix.grayScale.step11,
surface: radix.primaryScale.step1,
onSurface: radix.primaryScale.step12,
surfaceVariant: radix.secondaryScale.step2,
onSurfaceVariant: radix.secondaryScale.step11,
outline: radix.primaryScale.step7,
outlineVariant: radix.primaryScale.step6,
shadow: RadixColors.dark.gray.step1,
scrim: radix.primaryScale.step9,
inverseSurface: radix.primaryScale.step11,
onInverseSurface: radix.primaryScale.step2,
inversePrimary: radix.primaryScale.step10,
surfaceTint: radix.primaryAlphaScale.step4,
);
ChatTheme makeChatTheme(ScaleScheme scale, TextTheme textTheme) =>
DefaultChatTheme(
primaryColor: scale.primaryScale.background,
secondaryColor: scale.secondaryScale.background,
backgroundColor: scale.grayScale.subtleBackground,
inputBackgroundColor: Colors.blue,
inputBorderRadius: BorderRadius.zero,
inputTextDecoration: InputDecoration(
filled: true,
fillColor: scale.primaryScale.elementBackground,
isDense: true,
contentPadding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
border: const OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.all(Radius.circular(16))),
),
inputContainerDecoration: BoxDecoration(color: scale.primaryScale.border),
inputPadding: const EdgeInsets.all(9),
inputTextColor: scale.primaryScale.text,
attachmentButtonIcon: const Icon(Icons.attach_file),
);
ThemeData radixGenerator(Brightness brightness, RadixThemeColor themeColor) {
final textTheme = (brightness == Brightness.light)
? Typography.blackCupertino
: Typography.whiteCupertino;
final radix = _radixScheme(brightness, themeColor);
final colorScheme = _radixColorScheme(brightness, radix);
final scaleScheme = radix.toScale();
final themeData = ThemeData.from(
colorScheme: colorScheme, textTheme: textTheme, useMaterial3: true);
return themeData.copyWith(
bottomSheetTheme: themeData.bottomSheetTheme.copyWith(
elevation: 0,
modalElevation: 0,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16))),
extensions: <ThemeExtension<dynamic>>[
scaleScheme,
]);
}

View file

@ -1,5 +1,5 @@
import 'dart:typed_data';
import '../entities/local_account.dart';
import '../local_accounts/local_account.dart';
import '../veilid_init.dart';
import '../veilid_support/veilid_support.dart';

View file

@ -0,0 +1,12 @@
import 'package:stack_trace/stack_trace.dart';
/// Rethrows [error] with a stacktrace that is the combination of [stackTrace]
/// and [StackTrace.current].
Never throwErrorWithCombinedStackTrace(Object error, StackTrace stackTrace) {
final chain = Chain([
Trace.current(),
...Chain.forTrace(stackTrace).traces,
]); // .foldFrames((frame) => frame.package == 'riverpod');
Error.throwWithStackTrace(error, chain.toTrace().vmTrace);
}

View file

@ -1,22 +1,33 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:bloc/bloc.dart';
import 'loggy.dart';
class StateLogger extends ProviderObserver {
/// [BlocObserver] for the VeilidChat application that
/// observes all state changes.
class StateLogger extends BlocObserver {
/// {@macro counter_observer}
const StateLogger();
@override
void didUpdateProvider(
ProviderBase<Object?> provider,
Object? previousValue,
Object? newValue,
ProviderContainer container,
) {
log.debug('''
{
provider: ${provider.name ?? provider.runtimeType},
oldValue: $previousValue,
newValue: $newValue
}
''');
super.didUpdateProvider(provider, previousValue, newValue, container);
void onChange(BlocBase<dynamic> bloc, Change<dynamic> change) {
super.onChange(bloc, change);
log.debug('Change: ${bloc.runtimeType} $change');
}
@override
void onCreate(BlocBase<dynamic> bloc) {
super.onCreate(bloc);
log.debug('Create: ${bloc.runtimeType}');
}
@override
void onClose(BlocBase<dynamic> bloc) {
super.onClose(bloc);
log.debug('Close: ${bloc.runtimeType}');
}
@override
void onError(BlocBase<dynamic> bloc, Object error, StackTrace stackTrace) {
super.onError(bloc, error, stackTrace);
log.error('Error: ${bloc.runtimeType} $error\n$stackTrace');
}
}

View file

@ -0,0 +1,34 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'loggy.dart';
/// Converts a [Stream] into a [Listenable]
///
/// {@tool snippet}
/// Typical usage is as follows:
///
/// ```dart
/// StreamListenable(stream)
/// ```
/// {@end-tool}
class StreamListenable extends ChangeNotifier {
/// Creates a [StreamListenable].
///
/// Every time the [Stream] receives an event this [ChangeNotifier] will
/// notify its listeners.
StreamListenable(Stream<dynamic> stream) {
notifyListeners();
_subscription = stream.asBroadcastStream().listen((_) => notifyListeners());
}
late final StreamSubscription<dynamic> _subscription;
@override
void dispose() {
unawaited(_subscription.cancel().onError((error, stackTrace) =>
log.error('StreamListenable cancel error: $error\n$stackTrace')));
super.dispose();
}
}

View file

@ -1,255 +0,0 @@
// ignore_for_file: always_put_required_named_parameters_first
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../entities/preferences.dart';
import 'radix_generator.dart';
part 'theme_service.g.dart';
class ScaleColor {
ScaleColor({
required this.appBackground,
required this.subtleBackground,
required this.elementBackground,
required this.hoverElementBackground,
required this.activeElementBackground,
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;
Color activeElementBackground;
Color subtleBorder;
Color border;
Color hoverBorder;
Color background;
Color hoverBackground;
Color subtleText;
Color text;
ScaleColor copyWith(
{Color? appBackground,
Color? subtleBackground,
Color? elementBackground,
Color? hoverElementBackground,
Color? activeElementBackground,
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,
activeElementBackground:
activeElementBackground ?? this.activeElementBackground,
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),
activeElementBackground: Color.lerp(
a.activeElementBackground, b.activeElementBackground, t) ??
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),
);
}
class ScaleScheme extends ThemeExtension<ScaleScheme> {
ScaleScheme(
{required this.primaryScale,
required this.primaryAlphaScale,
required this.secondaryScale,
required this.tertiaryScale,
required this.grayScale,
required this.errorScale});
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),
);
}
}
////////////////////////////////////////////////////////////////////////
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 {
final themePreferences = load();
return get(themePreferences);
}
ThemePreferences load() {
final themePreferencesJson = prefs.getString('themePreferences');
ThemePreferences? themePreferences;
if (themePreferencesJson != null) {
try {
themePreferences =
ThemePreferences.fromJson(jsonDecode(themePreferencesJson));
// ignore: avoid_catches_without_on_clauses
} catch (_) {
// ignore
}
}
return themePreferences ??
const ThemePreferences(
colorPreference: ColorPreference.vapor,
brightnessPreference: BrightnessPreference.system,
displayScale: 1,
);
}
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;
}
}
@riverpod
FutureOr<ThemeService> themeService(ThemeServiceRef ref) async =>
await ThemeService.instance;

View file

@ -1,24 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'theme_service.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$themeServiceHash() => r'87dbacb9df4923f507fb01e486b91d73a3fcef9c';
/// See also [themeService].
@ProviderFor(themeService)
final themeServiceProvider = AutoDisposeFutureProvider<ThemeService>.internal(
themeService,
name: r'themeServiceProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$themeServiceHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef ThemeServiceRef = AutoDisposeFutureProviderRef<ThemeService>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View file

@ -1,10 +1,10 @@
export 'animations.dart';
export 'async_table_db_backed_cubit.dart';
export 'async_value.dart';
export 'loggy.dart';
export 'phono_byte.dart';
export 'radix_generator.dart';
export 'responsive.dart';
export 'scanner_error_widget.dart';
export 'secret_crypto.dart';
export 'state_logger.dart';
export 'theme_service.dart';
export 'widget_helpers.dart';

View file

@ -6,7 +6,7 @@ import 'package:flutter_translate/flutter_translate.dart';
import 'package:motion_toast/motion_toast.dart';
import 'package:quickalert/quickalert.dart';
import 'theme_service.dart';
import '../theme/theme.dart';
extension BorderExt on Widget {
DecoratedBox debugBorder() => DecoratedBox(