Fix: dark icon hard to see (#407)
## Type of Change - [x] ✨ New feature (non-breaking change which adds functionality) ## Description Fall-back to theme's icon-color when the icon-color is too light or dark. Fixes #403 Logic 1. If RGB values are almost equal (`#000000`, `#0F0F11`, `#212121`, `#27272A`, `#464949`, `#FFFFFF`) 2. Compute its luminance/brightness (cache this value as it is an expensive task) 3. If its too bright or dark, return theme's icon-color I've manually set the threshold values for brightness in light-theme to be `0.7` and in dark-theme to be `0.05` https://github.com/ente-io/auth/assets/53324291/aa1e8413-631d-4039-8c08-f8c4d1856fdb Co-authored-by: aadarsh-patel <aadarsh@zuzu.in>
This commit is contained in:
parent
8b9592c06e
commit
6b4e4b6822
1 changed files with 32 additions and 2 deletions
|
@ -1,5 +1,6 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:ente_auth/ente_theme_data.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -14,6 +15,8 @@ class IconUtils {
|
|||
// Map of icon-title to the color code in HEX
|
||||
final Map<String, String> _simpleIcons = {};
|
||||
final Map<String, CustomIconData> _customIcons = {};
|
||||
// Map of icon-color to its luminance
|
||||
final Map<Color, double> _colorLuminance = {};
|
||||
|
||||
Future<void> init() async {
|
||||
await _loadJson();
|
||||
|
@ -31,6 +34,7 @@ class IconUtils {
|
|||
title,
|
||||
_customIcons[title]!.color,
|
||||
width,
|
||||
context,
|
||||
);
|
||||
} else if (_simpleIcons.containsKey(title)) {
|
||||
return _getSVGIcon(
|
||||
|
@ -38,6 +42,7 @@ class IconUtils {
|
|||
title,
|
||||
_simpleIcons[title],
|
||||
width,
|
||||
context,
|
||||
);
|
||||
} else if (title.isNotEmpty) {
|
||||
bool showLargeIcon = width > 24;
|
||||
|
@ -63,20 +68,45 @@ class IconUtils {
|
|||
String title,
|
||||
String? color,
|
||||
double width,
|
||||
BuildContext context,
|
||||
) {
|
||||
final iconColor = _getAdaptiveColor(color, context);
|
||||
return SvgPicture.asset(
|
||||
path,
|
||||
width: width,
|
||||
semanticsLabel: title,
|
||||
colorFilter: color != null
|
||||
colorFilter: iconColor != null
|
||||
? ColorFilter.mode(
|
||||
Color(int.parse("0xFF" + color)),
|
||||
iconColor,
|
||||
BlendMode.srcIn,
|
||||
)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Color? _getAdaptiveColor(String? hexColor, BuildContext context) {
|
||||
if (hexColor == null) return null;
|
||||
final theme = Theme.of(context).brightness;
|
||||
final color = Color(int.parse("0xFF" + hexColor));
|
||||
// Color is close to neutral-grey and it's too light or dark for theme
|
||||
if (_isCloseToNeutralGrey(color) &&
|
||||
((theme == Brightness.light && _getColorLuminance(color) > 0.70) ||
|
||||
(theme == Brightness.dark && _getColorLuminance(color) < 0.05))) {
|
||||
return Theme.of(context).colorScheme.iconColor;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
double _getColorLuminance(Color color) {
|
||||
return _colorLuminance.putIfAbsent(color, () => color.computeLuminance());
|
||||
}
|
||||
|
||||
bool _isCloseToNeutralGrey(Color color, {double tolerance = 3}) {
|
||||
return (color.red - color.green).abs() <= tolerance &&
|
||||
(color.green - color.blue).abs() <= tolerance &&
|
||||
(color.blue - color.red).abs() <= tolerance;
|
||||
}
|
||||
|
||||
Future<void> _loadJson() async {
|
||||
try {
|
||||
final simpleIconData = await rootBundle
|
||||
|
|
Loading…
Add table
Reference in a new issue