locale independent colors for known filters

This commit is contained in:
Thibault Deckers 2022-02-21 12:08:21 +09:00
parent 6ce1d65367
commit 06ab31bae2
22 changed files with 115 additions and 57 deletions

View file

@ -18,6 +18,7 @@ All notable changes to this project will be documented in this file.
- Viewer: allow zooming out small items to actual size
- Collection: improved performance for sort/group by name
- load previous top items on startup
- locale independent colors for known filters
- upgraded Flutter to stable v2.10.1
### Removed

View file

@ -1,5 +1,5 @@
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/theme/themes.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:flutter/widgets.dart';
@ -133,7 +133,7 @@ extension ExtraEntryAction on EntryAction {
switch (this) {
case EntryAction.debug:
return ShaderMask(
shaderCallback: Themes.debugGradient.createShader,
shaderCallback: AColors.debugGradient.createShader,
child: child,
);
default:

View file

@ -1,5 +1,5 @@
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/theme/themes.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:flutter/widgets.dart';
@ -55,7 +55,7 @@ extension ExtraEntryInfoAction on EntryInfoAction {
switch (this) {
case EntryInfoAction.debug:
return ShaderMask(
shaderCallback: Themes.debugGradient.createShader,
shaderCallback: AColors.debugGradient.createShader,
child: child,
);
default:

View file

@ -22,7 +22,7 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
final appliedModifier = await _applyDateModifierToEntry(userModifier);
if (appliedModifier == null) {
await reportService.recordError('failed to get date for modifier=$userModifier, uri=$uri', null);
await reportService.recordError('failed to get date for modifier=$userModifier, entry=$this', null);
return {};
}

View file

@ -1,4 +1,5 @@
import 'package:aves/model/filters/filters.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:flutter/foundation.dart';
@ -32,7 +33,7 @@ class FavouriteFilter extends CollectionFilter {
Widget iconBuilder(BuildContext context, double size, {bool showGenericIcon = true}) => Icon(AIcons.favourite, size: size);
@override
Future<Color> color(BuildContext context) => SynchronousFuture(Colors.red);
Future<Color> color(BuildContext context) => SynchronousFuture(AColors.favourite);
@override
String get category => type;

View file

@ -1,8 +1,11 @@
import 'package:aves/model/filters/filters.dart';
import 'package:aves/ref/mime_types.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/utils/color_utils.dart';
import 'package:aves/utils/mime_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
class MimeFilter extends CollectionFilter {
@ -12,6 +15,7 @@ class MimeFilter extends CollectionFilter {
late final EntryFilter _test;
late final String _label;
late final IconData _icon;
late final Color _color;
static final image = MimeFilter(MimeTypes.anyImage);
static final video = MimeFilter(MimeTypes.anyVideo);
@ -21,6 +25,7 @@ class MimeFilter extends CollectionFilter {
MimeFilter(this.mime) {
IconData? icon;
Color? color;
var lowMime = mime.toLowerCase();
if (lowMime.endsWith('/*')) {
lowMime = lowMime.substring(0, lowMime.length - 2);
@ -28,14 +33,17 @@ class MimeFilter extends CollectionFilter {
_label = lowMime.toUpperCase();
if (mime == MimeTypes.anyImage) {
icon = AIcons.image;
color = AColors.image;
} else if (mime == MimeTypes.anyVideo) {
icon = AIcons.video;
color = AColors.video;
}
} else {
_test = (entry) => entry.mimeType == lowMime;
_label = MimeUtils.displayType(lowMime);
}
_icon = icon ?? AIcons.vector;
_color = color ?? stringToColor(_label);
}
MimeFilter.fromMap(Map<String, dynamic> json)
@ -70,6 +78,9 @@ class MimeFilter extends CollectionFilter {
@override
Widget iconBuilder(BuildContext context, double size, {bool showGenericIcon = true}) => Icon(_icon, size: size);
@override
Future<Color> color(BuildContext context) => SynchronousFuture(_color);
@override
String get category => type;

View file

@ -1,6 +1,8 @@
import 'package:aves/model/filters/filters.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
class TypeFilter extends CollectionFilter {
@ -16,6 +18,7 @@ class TypeFilter extends CollectionFilter {
final String itemType;
late final EntryFilter _test;
late final IconData _icon;
late final Color _color;
static final animated = TypeFilter._private(_animated);
static final geotiff = TypeFilter._private(_geotiff);
@ -32,26 +35,32 @@ class TypeFilter extends CollectionFilter {
case _animated:
_test = (entry) => entry.isAnimated;
_icon = AIcons.animated;
_color = AColors.animated;
break;
case _geotiff:
_test = (entry) => entry.isGeotiff;
_icon = AIcons.geo;
_color = AColors.geotiff;
break;
case _motionPhoto:
_test = (entry) => entry.isMotionPhoto;
_icon = AIcons.motionPhoto;
_color = AColors.motionPhoto;
break;
case _panorama:
_test = (entry) => entry.isImage && entry.is360;
_icon = AIcons.threeSixty;
_color = AColors.panorama;
break;
case _raw:
_test = (entry) => entry.isRaw;
_icon = AIcons.raw;
_color = AColors.raw;
break;
case _sphericalVideo:
_test = (entry) => entry.isVideo && entry.is360;
_icon = AIcons.threeSixty;
_color = AColors.sphericalVideo;
break;
}
}
@ -96,6 +105,9 @@ class TypeFilter extends CollectionFilter {
@override
Widget iconBuilder(BuildContext context, double size, {bool showGenericIcon = true}) => Icon(_icon, size: size);
@override
Future<Color> color(BuildContext context) => SynchronousFuture(_color);
@override
String get category => type;

View file

@ -152,17 +152,18 @@ mixin AlbumMixin on SourceBase {
if (context != null) {
final type = androidFileUtils.getAlbumType(dirPath);
final l10n = context.l10n;
switch (type) {
case AlbumType.camera:
return context.l10n.albumCamera;
return l10n.albumCamera;
case AlbumType.download:
return context.l10n.albumDownload;
return l10n.albumDownload;
case AlbumType.screenshots:
return context.l10n.albumScreenshots;
return l10n.albumScreenshots;
case AlbumType.screenRecordings:
return context.l10n.albumScreenRecordings;
return l10n.albumScreenRecordings;
case AlbumType.videoCaptures:
return context.l10n.albumVideoCaptures;
return l10n.albumVideoCaptures;
case AlbumType.regular:
case AlbumType.app:
break;

36
lib/theme/colors.dart Normal file
View file

@ -0,0 +1,36 @@
import 'package:aves/utils/color_utils.dart';
import 'package:flutter/material.dart';
class AColors {
// mime
static final image = stringToColor('Image');
static final video = stringToColor('Video');
// type
static const favourite = Colors.red;
static final animated = stringToColor('Animated');
static final geotiff = stringToColor('GeoTIFF');
static final motionPhoto = stringToColor('Motion Photo');
static final panorama = stringToColor('Panorama');
static final raw = stringToColor('Raw');
static final sphericalVideo = stringToColor('360° Video');
// info
static final xmp = stringToColor('XMP');
// settings
static final accessibility = stringToColor('Accessibility');
static final language = stringToColor('Language');
static final navigation = stringToColor('Navigation');
static final privacy = stringToColor('Privacy');
static final thumbnails = stringToColor('Thumbnails');
static const debugGradient = LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [
Colors.red,
Colors.amber,
],
);
}

View file

@ -5,15 +5,6 @@ import 'package:flutter/material.dart';
class Themes {
static const _accentColor = Colors.indigoAccent;
static const debugGradient = LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [
Colors.red,
Colors.amber,
],
);
static final darkTheme = ThemeData(
brightness: Brightness.dark,
// canvas color is used as background for the drawer and popups

View file

@ -1,5 +1,6 @@
import 'package:aves/model/entry.dart';
import 'package:aves/model/favourites.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/widgets/common/basic/menu.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
@ -72,7 +73,7 @@ class _FavouriteTogglerState extends State<FavouriteToggler> {
),
Sweeper(
key: ValueKey(entries.length == 1 ? entries.first : entries.length),
builder: (context) => const Icon(AIcons.favourite, color: Colors.redAccent),
builder: (context) => const Icon(AIcons.favourite, color: AColors.favourite),
toggledNotifier: isFavouriteNotifier,
),
],

View file

@ -2,8 +2,8 @@ import 'package:aves/model/filters/favourite.dart';
import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/filters/mime.dart';
import 'package:aves/model/filters/type.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/theme/themes.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/debug/app_debug_page.dart';
import 'package:aves/widgets/filter_grids/albums_page.dart';
@ -77,7 +77,7 @@ class DrawerPageIcon extends StatelessWidget {
return const Icon(AIcons.tag);
case AppDebugPage.routeName:
return ShaderMask(
shaderCallback: Themes.debugGradient.createShader,
shaderCallback: AColors.debugGradient.createShader,
child: const Icon(AIcons.debug),
);
default:

View file

@ -324,7 +324,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
}
AvesEntry? _getRegionEntry(int? index) {
if (index != null && regionCollection != null) {
if (index != null && index >= 0 && regionCollection != null) {
final regionEntries = regionCollection!.sortedEntries;
if (index < regionEntries.length) {
return regionEntries[index];

View file

@ -1,5 +1,5 @@
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/utils/color_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
import 'package:aves/widgets/settings/accessibility/remove_animations.dart';
@ -20,7 +20,7 @@ class AccessibilitySection extends StatelessWidget {
return AvesExpansionTile(
leading: SettingsTileLeading(
icon: AIcons.accessibility,
color: stringToColor('Accessibility'),
color: AColors.accessibility,
),
title: context.l10n.settingsSectionAccessibility,
expandedNotifier: expandedNotifier,

View file

@ -1,9 +1,9 @@
import 'package:aves/model/settings/enums/coordinate_format.dart';
import 'package:aves/model/settings/enums/enums.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/settings/enums/unit_system.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/utils/color_utils.dart';
import 'package:aves/utils/constants.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
@ -35,7 +35,7 @@ class LanguageSection extends StatelessWidget {
value: 'language',
leading: SettingsTileLeading(
icon: AIcons.language,
color: stringToColor('Language'),
color: AColors.language,
),
title: l10n.settingsSectionLanguage,
expandedNotifier: expandedNotifier,

View file

@ -2,8 +2,8 @@ import 'package:aves/model/settings/enums/enums.dart';
import 'package:aves/model/settings/enums/home_page.dart';
import 'package:aves/model/settings/enums/screen_on.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/utils/color_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
import 'package:aves/widgets/dialogs/aves_selection_dialog.dart';
@ -30,7 +30,7 @@ class NavigationSection extends StatelessWidget {
return AvesExpansionTile(
leading: SettingsTileLeading(
icon: AIcons.home,
color: stringToColor('Navigation'),
color: AColors.navigation,
),
title: context.l10n.settingsSectionNavigation,
expandedNotifier: expandedNotifier,

View file

@ -1,8 +1,8 @@
import 'package:aves/app_flavor.dart';
import 'package:aves/model/device.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/utils/color_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
import 'package:aves/widgets/settings/common/tile_leading.dart';
@ -26,7 +26,7 @@ class PrivacySection extends StatelessWidget {
return AvesExpansionTile(
leading: SettingsTileLeading(
icon: AIcons.privacy,
color: stringToColor('Privacy'),
color: AColors.privacy,
),
title: context.l10n.settingsSectionPrivacy,
expandedNotifier: expandedNotifier,

View file

@ -1,7 +1,7 @@
import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/utils/color_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
import 'package:aves/widgets/common/identity/aves_icons.dart';
@ -26,7 +26,7 @@ class ThumbnailsSection extends StatelessWidget {
return AvesExpansionTile(
leading: SettingsTileLeading(
icon: AIcons.grid,
color: stringToColor('Thumbnails'),
color: AColors.thumbnails,
),
title: context.l10n.settingsSectionThumbnails,
expandedNotifier: expandedNotifier,

View file

@ -1,10 +1,10 @@
import 'package:aves/model/filters/mime.dart';
import 'package:aves/model/settings/enums/enums.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/settings/enums/video_loop_mode.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_source.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/utils/color_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
@ -77,7 +77,7 @@ class VideoSection extends StatelessWidget {
: AvesExpansionTile(
leading: SettingsTileLeading(
icon: AIcons.video,
color: stringToColor('Video'),
color: AColors.video,
),
title: context.l10n.settingsSectionVideo,
expandedNotifier: expandedNotifier,

View file

@ -1,8 +1,8 @@
import 'package:aves/model/settings/enums/enums.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/services/common/services.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/utils/color_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
import 'package:aves/widgets/settings/common/tile_leading.dart';
@ -25,7 +25,7 @@ class ViewerSection extends StatelessWidget {
return AvesExpansionTile(
leading: SettingsTileLeading(
icon: AIcons.image,
color: stringToColor('Image'),
color: AColors.image,
),
title: context.l10n.settingsSectionViewer,
expandedNotifier: expandedNotifier,

View file

@ -1,5 +1,4 @@
import 'package:aves/model/filters/filters.dart';
import 'package:aves/utils/color_utils.dart';
import 'package:aves/utils/constants.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/identity/aves_filter_chip.dart';
@ -53,7 +52,6 @@ class FilterTable<T extends Comparable> extends StatelessWidget {
return Table(
children: displayedEntries.map((kv) {
final filter = filterBuilder(kv.key);
final label = filter.getLabel(context);
final count = kv.value;
final percent = count / totalEntryCount;
return TableRow(
@ -76,19 +74,25 @@ class FilterTable<T extends Comparable> extends StatelessWidget {
padding: EdgeInsets.symmetric(horizontal: lineHeight),
child: ClipRRect(
borderRadius: BorderRadius.all(barRadius),
child: LinearPercentIndicator(
percent: percent,
lineHeight: lineHeight,
backgroundColor: Colors.white24,
progressColor: stringToColor(label),
animation: true,
isRTL: isRtl,
barRadius: barRadius,
center: Text(
intl.NumberFormat.percentPattern().format(percent),
style: const TextStyle(shadows: Constants.embossShadows),
),
padding: EdgeInsets.zero,
child: FutureBuilder<Color>(
future: filter.color(context),
builder: (context, snapshot) {
final color = snapshot.data;
return LinearPercentIndicator(
percent: percent,
lineHeight: lineHeight,
backgroundColor: Colors.white24,
progressColor: color,
animation: true,
isRTL: isRtl,
barRadius: barRadius,
center: Text(
intl.NumberFormat.percentPattern().format(percent),
style: const TextStyle(shadows: Constants.embossShadows),
),
padding: EdgeInsets.zero,
);
},
),
),
),

View file

@ -1,7 +1,7 @@
import 'dart:collection';
import 'package:aves/model/entry.dart';
import 'package:aves/utils/color_utils.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/utils/xmp_utils.dart';
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
import 'package:aves/widgets/viewer/info/metadata/xmp_namespaces.dart';
@ -43,7 +43,7 @@ class _XmpDirTileState extends State<XmpDirTile> {
return AvesExpansionTile(
// title may contain parent to distinguish multiple XMP directories
title: widget.title,
color: stringToColor('XMP'),
color: AColors.xmp,
expandedNotifier: widget.expandedNotifier,
initiallyExpanded: widget.initiallyExpanded,
children: [