tv: changed section header focus/highlight
This commit is contained in:
parent
8b4f6e45f8
commit
10756f5156
7 changed files with 71 additions and 51 deletions
|
@ -18,6 +18,7 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
- upgraded Flutter to stable v3.7.11
|
- upgraded Flutter to stable v3.7.11
|
||||||
- when an album becomes empty, the folder will be deleted only if it is a non-app/common album
|
- when an album becomes empty, the folder will be deleted only if it is a non-app/common album
|
||||||
|
- TV: section header focus/highlight
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,8 @@ class TitledExpandableFilterRow extends StatelessWidget {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
header,
|
header,
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Icon(isExpanded ? AIcons.collapse : AIcons.expand),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -32,27 +32,13 @@ class SectionHeader<T> extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget child = _buildContent(context);
|
final onTap = selectable ? () => _toggleSectionSelection(context) : null;
|
||||||
if (settings.useTvLayout) {
|
|
||||||
child = InkWell(
|
|
||||||
onTap: _onTap(context),
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(123)),
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return Container(
|
|
||||||
alignment: AlignmentDirectional.centerStart,
|
|
||||||
margin: margin,
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildContent(BuildContext context) {
|
Widget child = Container(
|
||||||
return Container(
|
|
||||||
padding: padding,
|
padding: padding,
|
||||||
constraints: BoxConstraints(minHeight: leadingSize.height),
|
constraints: BoxConstraints(minHeight: leadingSize.height),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: _onTap(context),
|
onTap: onTap,
|
||||||
onLongPress: selectable
|
onLongPress: selectable
|
||||||
? () {
|
? () {
|
||||||
final selection = context.read<Selection<T>>();
|
final selection = context.read<Selection<T>>();
|
||||||
|
@ -80,7 +66,7 @@ class SectionHeader<T> extends StatelessWidget {
|
||||||
child: leading,
|
child: leading,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
onPressed: _onTap(context),
|
onPressed: onTap,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
|
@ -100,10 +86,24 @@ class SectionHeader<T> extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
if (settings.useTvLayout) {
|
||||||
|
// prevent ink response when tapping the header does nothing,
|
||||||
|
// because otherwise Play Store reviewers think it is broken navigation
|
||||||
|
child = context.select<Selection<T>, bool>((v) => v.isSelecting)
|
||||||
|
? InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(123)),
|
||||||
|
child: child,
|
||||||
|
)
|
||||||
|
: Focus(child: child);
|
||||||
|
}
|
||||||
|
return Container(
|
||||||
|
alignment: AlignmentDirectional.centerStart,
|
||||||
|
margin: margin,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
VoidCallback? _onTap(BuildContext context) => selectable ? () => _toggleSectionSelection(context) : null;
|
|
||||||
|
|
||||||
List<T> _getSectionEntries(BuildContext context) => context.read<SectionedListLayout<T>>().sections[sectionKey] ?? [];
|
List<T> _getSectionEntries(BuildContext context) => context.read<SectionedListLayout<T>>().sections[sectionKey] ?? [];
|
||||||
|
|
||||||
void _toggleSectionSelection(BuildContext context) {
|
void _toggleSectionSelection(BuildContext context) {
|
||||||
|
|
|
@ -39,17 +39,17 @@ class _DrawerAlbumTabState extends State<DrawerAlbumTab> {
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final album = items[index];
|
final album = items[index];
|
||||||
final filter = AlbumFilter(album, source.getAlbumDisplayName(context, album));
|
final filter = AlbumFilter(album, source.getAlbumDisplayName(context, album));
|
||||||
|
void onPressed() => setState(() => items.remove(album));
|
||||||
return ListTile(
|
return ListTile(
|
||||||
key: ValueKey(album),
|
key: ValueKey(album),
|
||||||
leading: DrawerFilterIcon(filter: filter),
|
leading: DrawerFilterIcon(filter: filter),
|
||||||
title: DrawerFilterTitle(filter: filter),
|
title: DrawerFilterTitle(filter: filter),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
icon: const Icon(AIcons.clear),
|
icon: const Icon(AIcons.clear),
|
||||||
onPressed: () {
|
onPressed: onPressed,
|
||||||
setState(() => items.remove(album));
|
|
||||||
},
|
|
||||||
tooltip: context.l10n.actionRemove,
|
tooltip: context.l10n.actionRemove,
|
||||||
),
|
),
|
||||||
|
onTap: settings.useTvLayout ? onPressed : null,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
itemCount: items.length,
|
itemCount: items.length,
|
||||||
|
|
|
@ -40,6 +40,16 @@ class _DrawerFixedListTabState<T> extends State<DrawerFixedListTab<T>> {
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final filter = widget.items[index];
|
final filter = widget.items[index];
|
||||||
final visible = visibleItems.contains(filter);
|
final visible = visibleItems.contains(filter);
|
||||||
|
void onPressed() {
|
||||||
|
setState(() {
|
||||||
|
if (visible) {
|
||||||
|
visibleItems.remove(filter);
|
||||||
|
} else {
|
||||||
|
visibleItems.add(filter);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return Opacity(
|
return Opacity(
|
||||||
key: ValueKey(filter),
|
key: ValueKey(filter),
|
||||||
opacity: visible ? 1 : .4,
|
opacity: visible ? 1 : .4,
|
||||||
|
@ -48,17 +58,10 @@ class _DrawerFixedListTabState<T> extends State<DrawerFixedListTab<T>> {
|
||||||
title: widget.title(filter),
|
title: widget.title(filter),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
icon: Icon(visible ? AIcons.hide : AIcons.show),
|
icon: Icon(visible ? AIcons.hide : AIcons.show),
|
||||||
onPressed: () {
|
onPressed: onPressed,
|
||||||
setState(() {
|
|
||||||
if (visible) {
|
|
||||||
visibleItems.remove(filter);
|
|
||||||
} else {
|
|
||||||
visibleItems.add(filter);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
tooltip: visible ? context.l10n.hideTooltip : context.l10n.showTooltip,
|
tooltip: visible ? context.l10n.hideTooltip : context.l10n.showTooltip,
|
||||||
),
|
),
|
||||||
|
onTap: settings.useTvLayout ? onPressed : null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -126,17 +126,19 @@ class _HiddenPaths extends StatelessWidget {
|
||||||
child: ListView(
|
child: ListView(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
children: [
|
children: [
|
||||||
...pathList.map((pathFilter) => ListTile(
|
...pathList.map((pathFilter) {
|
||||||
title: Text(pathFilter.path),
|
void onPressed() => settings.changeFilterVisibility({pathFilter}, true);
|
||||||
dense: true,
|
return ListTile(
|
||||||
trailing: IconButton(
|
title: Text(pathFilter.path),
|
||||||
icon: const Icon(AIcons.clear),
|
dense: true,
|
||||||
onPressed: () {
|
trailing: IconButton(
|
||||||
settings.changeFilterVisibility({pathFilter}, true);
|
icon: const Icon(AIcons.clear),
|
||||||
},
|
onPressed: onPressed,
|
||||||
tooltip: context.l10n.actionRemove,
|
tooltip: context.l10n.actionRemove,
|
||||||
),
|
),
|
||||||
)),
|
onTap: settings.useTvLayout ? onPressed : null,
|
||||||
|
);
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -286,17 +286,29 @@ class _StatsPageState extends State<StatsPage> with FeedbackMixin, VaultAwareMix
|
||||||
style: AStyles.knownTitleText,
|
style: AStyles.knownTitleText,
|
||||||
);
|
);
|
||||||
if (settings.useTvLayout) {
|
if (settings.useTvLayout) {
|
||||||
|
header = Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
header,
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Icon(AIcons.next, color: hasMore ? null : Theme.of(context).disabledColor),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
header = Container(
|
header = Container(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
alignment: AlignmentDirectional.centerStart,
|
alignment: AlignmentDirectional.centerStart,
|
||||||
child: InkWell(
|
// prevent ink response when tapping the header does nothing,
|
||||||
onTap: onHeaderPressed,
|
// because otherwise Play Store reviewers think it is broken navigation
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(123)),
|
child: onHeaderPressed != null
|
||||||
child: Padding(
|
? InkWell(
|
||||||
padding: const EdgeInsets.all(16),
|
onTap: onHeaderPressed,
|
||||||
child: header,
|
borderRadius: const BorderRadius.all(Radius.circular(123)),
|
||||||
),
|
child: header,
|
||||||
),
|
)
|
||||||
|
: Focus(child: header),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
header = Padding(
|
header = Padding(
|
||||||
|
|
Loading…
Reference in a new issue