Files
FlClash/lib/common/color.dart
T
chen08209 ee6a49713a feat(ui): draw the app's own glyphs and redraw the theme page
Drops the Material compatibility bridge and the icon font.

Changelog: New app glyphs, empty states and theme page
2026-10-02 02:51:32 +08:00

137 lines
3.4 KiB
Dart

import 'dart:math';
import 'package:dynamic_color/dynamic_color.dart';
import 'package:material_color_utilities/hct/hct.dart';
import 'package:material_ui/material_ui.dart';
extension ColorExtension on Color {
Color get opacity80 {
return withValues(alpha: 0.8);
}
Color get opacity60 {
return withValues(alpha: 0.6);
}
Color get opacity50 {
return withValues(alpha: 0.5);
}
Color get opacity38 {
return withValues(alpha: 0.38);
}
Color get opacity30 {
return withValues(alpha: 0.3);
}
Color get opacity12 {
return withValues(alpha: 0.12);
}
Color get opacity15 {
return withValues(alpha: 0.15);
}
Color get opacity10 {
return withValues(alpha: 0.1);
}
Color get opacity3 {
return withValues(alpha: 0.03);
}
Color get opacity0 {
return withValues(alpha: 0);
}
int get value32bit {
return _floatToInt8(a) << 24 |
_floatToInt8(r) << 16 |
_floatToInt8(g) << 8 |
_floatToInt8(b) << 0;
}
int get alpha8bit => (0xff000000 & value32bit) >> 24;
int get red8bit => (0x00ff0000 & value32bit) >> 16;
int get green8bit => (0x0000ff00 & value32bit) >> 8;
int get blue8bit => (0x000000ff & value32bit) >> 0;
int _floatToInt8(double x) {
return (x * 255.0).round() & 0xff;
}
Color lighten([double amount = 10]) {
if (amount <= 0) return this;
if (amount > 100) return Colors.white;
final HSLColor hsl = this == const Color(0xFF000000)
? HSLColor.fromColor(this).withSaturation(0)
: HSLColor.fromColor(this);
return hsl
.withLightness(min(1, max(0, hsl.lightness + amount / 100)))
.toColor();
}
String get hex {
final value = toARGB32();
final red = (value >> 16) & 0xFF;
final green = (value >> 8) & 0xFF;
final blue = value & 0xFF;
return '#${red.toRadixString(16).padLeft(2, '0')}'
'${green.toRadixString(16).padLeft(2, '0')}'
'${blue.toRadixString(16).padLeft(2, '0')}'
.toUpperCase();
}
Color blendDarken(BuildContext context, {double factor = 0.1}) {
final brightness = Theme.of(context).brightness;
return Color.lerp(
this,
brightness == Brightness.dark ? Colors.white : Colors.black,
factor,
)!;
}
}
extension ColorSchemeExtension on ColorScheme {
ColorScheme toPureBlack(bool isPureBlack) {
if (!isPureBlack || brightness != Brightness.dark) {
return this;
}
final shift = Hct.fromInt(surface.toARGB32()).tone;
Color lower(Color color) {
final hct = Hct.fromInt(color.toARGB32());
return Color(
Hct.from(hct.hue, hct.chroma, max(0, hct.tone - shift)).toInt(),
);
}
return copyWith(
surface: Colors.black,
surfaceDim: Colors.black,
surfaceContainerLowest: Colors.black,
surfaceContainerLow: lower(surfaceContainerLow),
surfaceContainer: lower(surfaceContainer),
surfaceContainerHigh: lower(surfaceContainerHigh),
surfaceContainerHighest: lower(surfaceContainerHighest),
surfaceBright: lower(surfaceBright),
);
}
Color get modalScrim => scrim.withValues(alpha: 0.32);
Color get success => Colors.green.harmonizeWith(primary);
Color get warning => Colors.orange.harmonizeWith(primary);
Color? delayColor(int? delay) {
if (delay == null) return null;
if (delay < 0) return error;
if (delay < 600) return success;
return warning;
}
}