#420 tag editor review

This commit is contained in:
Thibault Deckers 2022-12-03 20:28:47 +01:00
parent 83f1ca9e7f
commit f607cf6c52
5 changed files with 56 additions and 32 deletions

View file

@ -109,6 +109,10 @@ class SettingsDefaults {
static const coordinateFormat = CoordinateFormat.dms; static const coordinateFormat = CoordinateFormat.dms;
static const unitSystem = UnitSystem.metric; static const unitSystem = UnitSystem.metric;
// tag editor
static const tagEditorCurrentFilterSectionExpanded = true;
// rendering // rendering
static const imageBackground = EntryBackground.white; static const imageBackground = EntryBackground.white;

View file

@ -139,6 +139,10 @@ class Settings extends ChangeNotifier {
static const coordinateFormatKey = 'coordinates_format'; static const coordinateFormatKey = 'coordinates_format';
static const unitSystemKey = 'unit_system'; static const unitSystemKey = 'unit_system';
// tag editor
static const tagEditorCurrentFilterSectionExpandedKey = 'tag_editor_current_filter_section_expanded';
// map // map
static const mapStyleKey = 'info_map_style'; static const mapStyleKey = 'info_map_style';
static const mapDefaultCenterKey = 'map_default_center'; static const mapDefaultCenterKey = 'map_default_center';
@ -623,6 +627,12 @@ class Settings extends ChangeNotifier {
set unitSystem(UnitSystem newValue) => setAndNotify(unitSystemKey, newValue.toString()); set unitSystem(UnitSystem newValue) => setAndNotify(unitSystemKey, newValue.toString());
// tag editor
bool get tagEditorCurrentFilterSectionExpanded => getBool(tagEditorCurrentFilterSectionExpandedKey) ?? SettingsDefaults.tagEditorCurrentFilterSectionExpanded;
set tagEditorCurrentFilterSectionExpanded(bool newValue) => setAndNotify(tagEditorCurrentFilterSectionExpandedKey, newValue);
// map // map
EntryMapStyle? get mapStyle { EntryMapStyle? get mapStyle {
@ -961,6 +971,7 @@ class Settings extends ChangeNotifier {
case videoGestureDoubleTapTogglePlayKey: case videoGestureDoubleTapTogglePlayKey:
case videoGestureSideDoubleTapSeekKey: case videoGestureSideDoubleTapSeekKey:
case subtitleShowOutlineKey: case subtitleShowOutlineKey:
case tagEditorCurrentFilterSectionExpandedKey:
case saveSearchHistoryKey: case saveSearchHistoryKey:
case filePickerShowHiddenFilesKey: case filePickerShowHiddenFilesKey:
case screenSaverFillScreenKey: case screenSaverFillScreenKey:

View file

@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
class TitledExpandableFilterRow extends StatelessWidget { class TitledExpandableFilterRow extends StatelessWidget {
final String title; final String title;
final Iterable<CollectionFilter> filters; final List<CollectionFilter> filters;
final ValueNotifier<String?> expandedNotifier; final ValueNotifier<String?> expandedNotifier;
final bool showGenericIcon; final bool showGenericIcon;
final HeroType Function(CollectionFilter filter)? heroTypeBuilder; final HeroType Function(CollectionFilter filter)? heroTypeBuilder;
@ -65,9 +65,10 @@ class TitledExpandableFilterRow extends StatelessWidget {
} }
class ExpandableFilterRow extends StatelessWidget { class ExpandableFilterRow extends StatelessWidget {
final Iterable<CollectionFilter> filters; final List<CollectionFilter> filters;
final bool isExpanded; final bool isExpanded;
final bool showGenericIcon; final bool removable, showGenericIcon;
final Widget? Function(CollectionFilter)? leadingBuilder;
final HeroType Function(CollectionFilter filter)? heroTypeBuilder; final HeroType Function(CollectionFilter filter)? heroTypeBuilder;
final FilterCallback onTap; final FilterCallback onTap;
final OffsetFilterCallback? onLongPress; final OffsetFilterCallback? onLongPress;
@ -79,7 +80,9 @@ class ExpandableFilterRow extends StatelessWidget {
super.key, super.key,
required this.filters, required this.filters,
required this.isExpanded, required this.isExpanded,
this.removable = false,
this.showGenericIcon = true, this.showGenericIcon = true,
this.leadingBuilder,
this.heroTypeBuilder, this.heroTypeBuilder,
required this.onTap, required this.onTap,
required this.onLongPress, required this.onLongPress,
@ -101,7 +104,6 @@ class ExpandableFilterRow extends StatelessWidget {
} }
Widget _buildExpanded() { Widget _buildExpanded() {
final filterList = filters.toList();
return Container( return Container(
key: const Key('wrap'), key: const Key('wrap'),
padding: const EdgeInsets.symmetric(horizontal: horizontalPadding), padding: const EdgeInsets.symmetric(horizontal: horizontalPadding),
@ -111,13 +113,12 @@ class ExpandableFilterRow extends StatelessWidget {
child: Wrap( child: Wrap(
spacing: horizontalPadding, spacing: horizontalPadding,
runSpacing: verticalPadding, runSpacing: verticalPadding,
children: filterList.map(_buildChip).toList(), children: filters.map(_buildChip).toList(),
), ),
); );
} }
Widget _buildCollapsed() { Widget _buildCollapsed() {
final filterList = filters.toList();
final list = Container( final list = Container(
key: const Key('list'), key: const Key('list'),
// specify transparent as a workaround to prevent // specify transparent as a workaround to prevent
@ -128,10 +129,10 @@ class ExpandableFilterRow extends StatelessWidget {
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: horizontalPadding), padding: const EdgeInsets.symmetric(horizontal: horizontalPadding),
itemBuilder: (context, index) { itemBuilder: (context, index) {
return index < filterList.length ? _buildChip(filterList[index]) : const SizedBox(); return index < filters.length ? _buildChip(filters[index]) : const SizedBox();
}, },
separatorBuilder: (context, index) => const SizedBox(width: 8), separatorBuilder: (context, index) => const SizedBox(width: 8),
itemCount: filterList.length, itemCount: filters.length,
), ),
); );
return list; return list;
@ -142,7 +143,9 @@ class ExpandableFilterRow extends StatelessWidget {
// key `album-{path}` is expected by test driver // key `album-{path}` is expected by test driver
key: Key(filter.key), key: Key(filter.key),
filter: filter, filter: filter,
removable: removable,
showGenericIcon: showGenericIcon, showGenericIcon: showGenericIcon,
leadingOverride: leadingBuilder?.call(filter),
heroType: heroTypeBuilder?.call(filter) ?? HeroType.onTap, heroType: heroTypeBuilder?.call(filter) ?? HeroType.onTap,
onTap: onTap, onTap: onTap,
onLongPress: onLongPress, onLongPress: onLongPress,

View file

@ -81,7 +81,7 @@ class _TagEditorPageState extends State<TagEditorPage> {
return ListView( return ListView(
children: [ children: [
Padding( Padding(
padding: const EdgeInsetsDirectional.only(start: 8), padding: const EdgeInsetsDirectional.only(start: 8, end: 16),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
@ -108,7 +108,17 @@ class _TagEditorPageState extends State<TagEditorPage> {
tooltip: l10n.tagEditorPageAddTagTooltip, tooltip: l10n.tagEditorPageAddTagTooltip,
); );
}, },
) ),
Selector<Settings, bool>(
selector: (context, s) => s.tagEditorCurrentFilterSectionExpanded,
builder: (context, isExpanded, child) {
return IconButton(
icon: Icon(isExpanded ? AIcons.collapse : AIcons.expand),
onPressed: sortedTags.isEmpty ? null : () => settings.tagEditorCurrentFilterSectionExpanded = !isExpanded,
tooltip: isExpanded ? MaterialLocalizations.of(context).expandedIconTapHint : MaterialLocalizations.of(context).collapsedIconTapHint,
);
},
),
], ],
), ),
), ),
@ -131,22 +141,18 @@ class _TagEditorPageState extends State<TagEditorPage> {
), ),
), ),
), ),
secondChild: Padding( secondChild: ExpandableFilterRow(
padding: const EdgeInsets.symmetric(horizontal: 8), filters: sortedTags.map((kv) => kv.key).toList(),
child: Wrap( isExpanded: context.select<Settings, bool>((v) => v.tagEditorCurrentFilterSectionExpanded),
spacing: 8, removable: true,
runSpacing: 8, showGenericIcon: false,
children: sortedTags.map((kv) { leadingBuilder: showCount
return AvesFilterChip( ? (filter) => _TagCount(
filter: kv.key, count: sortedTags.firstWhere((kv) => kv.key == filter).value,
removable: true, )
showGenericIcon: false, : null,
leadingOverride: showCount ? _TagCount(count: kv.value) : null, onTap: _removeTag,
onTap: _removeTag, onLongPress: null,
onLongPress: null,
);
}).toList(),
),
), ),
crossFadeState: sortedTags.isEmpty ? CrossFadeState.showFirst : CrossFadeState.showSecond, crossFadeState: sortedTags.isEmpty ? CrossFadeState.showFirst : CrossFadeState.showSecond,
duration: Durations.tagEditorTransition, duration: Durations.tagEditorTransition,
@ -154,14 +160,14 @@ class _TagEditorPageState extends State<TagEditorPage> {
), ),
const Divider(height: 0), const Divider(height: 0),
_FilterRow( _FilterRow(
title: l10n.tagEditorSectionRecent, title: l10n.statsTopTagsSectionTitle,
filters: recentFilters, filters: topTagFilters,
expandedNotifier: _expandedSectionNotifier, expandedNotifier: _expandedSectionNotifier,
onTap: _addTag, onTap: _addTag,
), ),
_FilterRow( _FilterRow(
title: l10n.statsTopTagsSectionTitle, title: l10n.tagEditorSectionRecent,
filters: topTagFilters, filters: recentFilters,
expandedNotifier: _expandedSectionNotifier, expandedNotifier: _expandedSectionNotifier,
onTap: _addTag, onTap: _addTag,
), ),

View file

@ -36,13 +36,13 @@ class OverlayRatingTagsRow extends AnimatedWidget {
return Row( return Row(
children: [ children: [
if (ratingString.isNotEmpty) ...[ if (ratingString.isNotEmpty) ...[
Text(ratingString), Text(ratingString, strutStyle: Constants.overflowStrutStyle),
if (hasTags) const Text(Constants.separator), if (hasTags) const Text(Constants.separator),
], ],
if (hasTags) ...[ if (hasTags) ...[
DecoratedIcon(AIcons.tag, size: ViewerDetailOverlayContent.iconSize, shadows: ViewerDetailOverlayContent.shadows(context)), DecoratedIcon(AIcons.tag, size: ViewerDetailOverlayContent.iconSize, shadows: ViewerDetailOverlayContent.shadows(context)),
const SizedBox(width: ViewerDetailOverlayContent.iconPadding), const SizedBox(width: ViewerDetailOverlayContent.iconPadding),
Expanded(child: Text(tags)), Expanded(child: Text(tags, strutStyle: Constants.overflowStrutStyle)),
], ],
], ],
); );