settings: option to hide videos
This commit is contained in:
parent
6159f5ec25
commit
81c9c8a757
9 changed files with 75 additions and 33 deletions
|
@ -525,6 +525,11 @@
|
||||||
"settingsViewerShowShootingDetails": "Show shooting details",
|
"settingsViewerShowShootingDetails": "Show shooting details",
|
||||||
"@settingsViewerShowShootingDetails": {},
|
"@settingsViewerShowShootingDetails": {},
|
||||||
|
|
||||||
|
"settingsSectionVideo": "Video",
|
||||||
|
"@settingsSectionVideo": {},
|
||||||
|
"settingsVideoShowVideos": "Show videos",
|
||||||
|
"@settingsVideoShowVideos": {},
|
||||||
|
|
||||||
"settingsSectionSearch": "Search",
|
"settingsSectionSearch": "Search",
|
||||||
"@settingsSectionSearch": {},
|
"@settingsSectionSearch": {},
|
||||||
"settingsSaveSearchHistory": "Save search history",
|
"settingsSaveSearchHistory": "Save search history",
|
||||||
|
|
|
@ -245,6 +245,9 @@
|
||||||
"settingsViewerShowInformationSubtitle": "제목, 날짜, 장소 등 표시",
|
"settingsViewerShowInformationSubtitle": "제목, 날짜, 장소 등 표시",
|
||||||
"settingsViewerShowShootingDetails": "촬영 정보 표시",
|
"settingsViewerShowShootingDetails": "촬영 정보 표시",
|
||||||
|
|
||||||
|
"settingsSectionVideo": "동영상",
|
||||||
|
"settingsVideoShowVideos": "미디어에 동영상 표시",
|
||||||
|
|
||||||
"settingsSectionSearch": "검색",
|
"settingsSectionSearch": "검색",
|
||||||
"settingsSaveSearchHistory": "검색기록",
|
"settingsSaveSearchHistory": "검색기록",
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,9 @@ class MimeFilter extends CollectionFilter {
|
||||||
String _label;
|
String _label;
|
||||||
IconData _icon;
|
IconData _icon;
|
||||||
|
|
||||||
|
static final image = MimeFilter(MimeTypes.anyImage);
|
||||||
|
static final video = MimeFilter(MimeTypes.anyVideo);
|
||||||
|
|
||||||
MimeFilter(this.mime) {
|
MimeFilter(this.mime) {
|
||||||
var lowMime = mime.toLowerCase();
|
var lowMime = mime.toLowerCase();
|
||||||
if (lowMime.endsWith('/*')) {
|
if (lowMime.endsWith('/*')) {
|
||||||
|
|
|
@ -7,30 +7,35 @@ import 'package:flutter/widgets.dart';
|
||||||
class TypeFilter extends CollectionFilter {
|
class TypeFilter extends CollectionFilter {
|
||||||
static const type = 'type';
|
static const type = 'type';
|
||||||
|
|
||||||
static const animated = 'animated'; // subset of `image/gif` and `image/webp`
|
static const _animated = 'animated'; // subset of `image/gif` and `image/webp`
|
||||||
static const geotiff = 'geotiff'; // subset of `image/tiff`
|
static const _geotiff = 'geotiff'; // subset of `image/tiff`
|
||||||
static const panorama = 'panorama'; // subset of images
|
static const _panorama = 'panorama'; // subset of images
|
||||||
static const sphericalVideo = 'spherical_video'; // subset of videos
|
static const _sphericalVideo = 'spherical_video'; // subset of videos
|
||||||
|
|
||||||
final String itemType;
|
final String itemType;
|
||||||
EntryFilter _test;
|
EntryFilter _test;
|
||||||
IconData _icon;
|
IconData _icon;
|
||||||
|
|
||||||
TypeFilter(this.itemType) {
|
static final animated = TypeFilter._private(_animated);
|
||||||
|
static final geotiff = TypeFilter._private(_geotiff);
|
||||||
|
static final panorama = TypeFilter._private(_panorama);
|
||||||
|
static final sphericalVideo = TypeFilter._private(_sphericalVideo);
|
||||||
|
|
||||||
|
TypeFilter._private(this.itemType) {
|
||||||
switch (itemType) {
|
switch (itemType) {
|
||||||
case animated:
|
case _animated:
|
||||||
_test = (entry) => entry.isAnimated;
|
_test = (entry) => entry.isAnimated;
|
||||||
_icon = AIcons.animated;
|
_icon = AIcons.animated;
|
||||||
break;
|
break;
|
||||||
case panorama:
|
case _panorama:
|
||||||
_test = (entry) => entry.isImage && entry.is360;
|
_test = (entry) => entry.isImage && entry.is360;
|
||||||
_icon = AIcons.threesixty;
|
_icon = AIcons.threesixty;
|
||||||
break;
|
break;
|
||||||
case sphericalVideo:
|
case _sphericalVideo:
|
||||||
_test = (entry) => entry.isVideo && entry.is360;
|
_test = (entry) => entry.isVideo && entry.is360;
|
||||||
_icon = AIcons.threesixty;
|
_icon = AIcons.threesixty;
|
||||||
break;
|
break;
|
||||||
case geotiff:
|
case _geotiff:
|
||||||
_test = (entry) => entry.isGeotiff;
|
_test = (entry) => entry.isGeotiff;
|
||||||
_icon = AIcons.geo;
|
_icon = AIcons.geo;
|
||||||
break;
|
break;
|
||||||
|
@ -38,7 +43,7 @@ class TypeFilter extends CollectionFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeFilter.fromMap(Map<String, dynamic> json)
|
TypeFilter.fromMap(Map<String, dynamic> json)
|
||||||
: this(
|
: this._private(
|
||||||
json['itemType'],
|
json['itemType'],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -57,13 +62,13 @@ class TypeFilter extends CollectionFilter {
|
||||||
@override
|
@override
|
||||||
String getLabel(BuildContext context) {
|
String getLabel(BuildContext context) {
|
||||||
switch (itemType) {
|
switch (itemType) {
|
||||||
case animated:
|
case _animated:
|
||||||
return context.l10n.filterTypeAnimatedLabel;
|
return context.l10n.filterTypeAnimatedLabel;
|
||||||
case panorama:
|
case _panorama:
|
||||||
return context.l10n.filterTypePanoramaLabel;
|
return context.l10n.filterTypePanoramaLabel;
|
||||||
case sphericalVideo:
|
case _sphericalVideo:
|
||||||
return context.l10n.filterTypeSphericalVideoLabel;
|
return context.l10n.filterTypeSphericalVideoLabel;
|
||||||
case geotiff:
|
case _geotiff:
|
||||||
return context.l10n.filterTypeGeotiffLabel;
|
return context.l10n.filterTypeGeotiffLabel;
|
||||||
default:
|
default:
|
||||||
return itemType;
|
return itemType;
|
||||||
|
|
|
@ -2,11 +2,11 @@ import 'dart:ui';
|
||||||
|
|
||||||
import 'package:aves/model/filters/favourite.dart';
|
import 'package:aves/model/filters/favourite.dart';
|
||||||
import 'package:aves/model/filters/mime.dart';
|
import 'package:aves/model/filters/mime.dart';
|
||||||
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/album.dart';
|
import 'package:aves/model/source/album.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/model/source/location.dart';
|
import 'package:aves/model/source/location.dart';
|
||||||
import 'package:aves/model/source/tag.dart';
|
import 'package:aves/model/source/tag.dart';
|
||||||
import 'package:aves/ref/mime_types.dart';
|
|
||||||
import 'package:aves/services/services.dart';
|
import 'package:aves/services/services.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
|
@ -45,10 +45,12 @@ class _AppDrawerState extends State<AppDrawer> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final hiddenFilters = settings.hiddenFilters;
|
||||||
|
final showVideos = !hiddenFilters.contains(MimeFilter.video);
|
||||||
final drawerItems = <Widget>[
|
final drawerItems = <Widget>[
|
||||||
_buildHeader(context),
|
_buildHeader(context),
|
||||||
allCollectionTile,
|
allCollectionTile,
|
||||||
videoTile,
|
if (showVideos) videoTile,
|
||||||
favouriteTile,
|
favouriteTile,
|
||||||
_buildSpecialAlbumSection(),
|
_buildSpecialAlbumSection(),
|
||||||
Divider(),
|
Divider(),
|
||||||
|
@ -153,7 +155,7 @@ class _AppDrawerState extends State<AppDrawer> {
|
||||||
Widget get videoTile => CollectionNavTile(
|
Widget get videoTile => CollectionNavTile(
|
||||||
leading: Icon(AIcons.video),
|
leading: Icon(AIcons.video),
|
||||||
title: context.l10n.drawerCollectionVideos,
|
title: context.l10n.drawerCollectionVideos,
|
||||||
filter: MimeFilter(MimeTypes.anyVideo),
|
filter: MimeFilter.video,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget get favouriteTile => CollectionNavTile(
|
Widget get favouriteTile => CollectionNavTile(
|
||||||
|
|
|
@ -31,13 +31,13 @@ class CollectionSearchDelegate {
|
||||||
static const searchHistoryCount = 10;
|
static const searchHistoryCount = 10;
|
||||||
static final typeFilters = [
|
static final typeFilters = [
|
||||||
FavouriteFilter(),
|
FavouriteFilter(),
|
||||||
MimeFilter(MimeTypes.anyImage),
|
MimeFilter.image,
|
||||||
MimeFilter(MimeTypes.anyVideo),
|
MimeFilter.video,
|
||||||
|
TypeFilter.animated,
|
||||||
|
TypeFilter.panorama,
|
||||||
|
TypeFilter.sphericalVideo,
|
||||||
|
TypeFilter.geotiff,
|
||||||
MimeFilter(MimeTypes.svg),
|
MimeFilter(MimeTypes.svg),
|
||||||
TypeFilter(TypeFilter.animated),
|
|
||||||
TypeFilter(TypeFilter.panorama),
|
|
||||||
TypeFilter(TypeFilter.sphericalVideo),
|
|
||||||
TypeFilter(TypeFilter.geotiff),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
CollectionSearchDelegate({@required this.source, this.parentCollection});
|
CollectionSearchDelegate({@required this.source, this.parentCollection});
|
||||||
|
@ -87,7 +87,14 @@ class CollectionSearchDelegate {
|
||||||
selector: (context, s) => s.hiddenFilters,
|
selector: (context, s) => s.hiddenFilters,
|
||||||
builder: (context, hiddenFilters, child) {
|
builder: (context, hiddenFilters, child) {
|
||||||
bool notHidden(CollectionFilter filter) => !hiddenFilters.contains(filter);
|
bool notHidden(CollectionFilter filter) => !hiddenFilters.contains(filter);
|
||||||
|
|
||||||
|
final visibleTypeFilters = typeFilters.where(notHidden).toList();
|
||||||
|
if (hiddenFilters.contains(MimeFilter.video)) {
|
||||||
|
[MimeFilter.image, TypeFilter.sphericalVideo].forEach(visibleTypeFilters.remove);
|
||||||
|
}
|
||||||
|
|
||||||
final history = settings.searchHistory.where(notHidden).toList();
|
final history = settings.searchHistory.where(notHidden).toList();
|
||||||
|
|
||||||
return ListView(
|
return ListView(
|
||||||
padding: EdgeInsets.only(top: 8),
|
padding: EdgeInsets.only(top: 8),
|
||||||
children: [
|
children: [
|
||||||
|
@ -95,7 +102,7 @@ class CollectionSearchDelegate {
|
||||||
context: context,
|
context: context,
|
||||||
filters: [
|
filters: [
|
||||||
queryFilter,
|
queryFilter,
|
||||||
...typeFilters.where(notHidden),
|
...visibleTypeFilters,
|
||||||
].where((f) => f != null && containQuery(f.getLabel(context))).toList(),
|
].where((f) => f != null && containQuery(f.getLabel(context))).toList(),
|
||||||
// usually perform hero animation only on tapped chips,
|
// usually perform hero animation only on tapped chips,
|
||||||
// but we also need to animate the query chip when it is selected by submitting the search query
|
// but we also need to animate the query chip when it is selected by submitting the search query
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
import 'package:aves/model/filters/mime.dart';
|
||||||
import 'package:aves/model/settings/coordinate_format.dart';
|
import 'package:aves/model/settings/coordinate_format.dart';
|
||||||
import 'package:aves/model/settings/enums.dart';
|
import 'package:aves/model/settings/enums.dart';
|
||||||
import 'package:aves/model/settings/home_page.dart';
|
import 'package:aves/model/settings/home_page.dart';
|
||||||
import 'package:aves/model/settings/screen_on.dart';
|
import 'package:aves/model/settings/screen_on.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/utils/constants.dart';
|
import 'package:aves/utils/constants.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
@ -61,6 +63,7 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
_buildDisplaySection(context),
|
_buildDisplaySection(context),
|
||||||
_buildThumbnailsSection(context),
|
_buildThumbnailsSection(context),
|
||||||
_buildViewerSection(context),
|
_buildViewerSection(context),
|
||||||
|
_buildVideoSection(context),
|
||||||
_buildSearchSection(context),
|
_buildSearchSection(context),
|
||||||
_buildPrivacySection(context),
|
_buildPrivacySection(context),
|
||||||
],
|
],
|
||||||
|
@ -213,6 +216,22 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildVideoSection(BuildContext context) {
|
||||||
|
final hiddenFilters = settings.hiddenFilters;
|
||||||
|
final showVideos = !hiddenFilters.contains(MimeFilter.video);
|
||||||
|
return AvesExpansionTile(
|
||||||
|
title: context.l10n.settingsSectionVideo,
|
||||||
|
expandedNotifier: _expandedNotifier,
|
||||||
|
children: [
|
||||||
|
SwitchListTile(
|
||||||
|
value: showVideos,
|
||||||
|
onChanged: (v) => context.read<CollectionSource>().changeFilterVisibility(MimeFilter.video, v),
|
||||||
|
title: Text(context.l10n.settingsVideoShowVideos),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildSearchSection(BuildContext context) {
|
Widget _buildSearchSection(BuildContext context) {
|
||||||
return AvesExpansionTile(
|
return AvesExpansionTile(
|
||||||
title: context.l10n.settingsSectionSearch,
|
title: context.l10n.settingsSectionSearch,
|
||||||
|
|
|
@ -7,7 +7,6 @@ import 'package:aves/model/filters/mime.dart';
|
||||||
import 'package:aves/model/filters/tag.dart';
|
import 'package:aves/model/filters/tag.dart';
|
||||||
import 'package:aves/model/filters/type.dart';
|
import 'package:aves/model/filters/type.dart';
|
||||||
import 'package:aves/model/source/collection_lens.dart';
|
import 'package:aves/model/source/collection_lens.dart';
|
||||||
import 'package:aves/ref/mime_types.dart';
|
|
||||||
import 'package:aves/services/services.dart';
|
import 'package:aves/services/services.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
import 'package:aves/utils/file_utils.dart';
|
import 'package:aves/utils/file_utils.dart';
|
||||||
|
@ -78,11 +77,11 @@ class BasicSection extends StatelessWidget {
|
||||||
final album = entry.directory;
|
final album = entry.directory;
|
||||||
final filters = {
|
final filters = {
|
||||||
MimeFilter(entry.mimeType),
|
MimeFilter(entry.mimeType),
|
||||||
if (entry.isAnimated) TypeFilter(TypeFilter.animated),
|
if (entry.isAnimated) TypeFilter.animated,
|
||||||
if (entry.isGeotiff) TypeFilter(TypeFilter.geotiff),
|
if (entry.isGeotiff) TypeFilter.geotiff,
|
||||||
if (entry.isImage && entry.is360) TypeFilter(TypeFilter.panorama),
|
if (entry.isImage && entry.is360) TypeFilter.panorama,
|
||||||
if (entry.isVideo && entry.is360) TypeFilter(TypeFilter.sphericalVideo),
|
if (entry.isVideo && entry.is360) TypeFilter.sphericalVideo,
|
||||||
if (entry.isVideo && !entry.is360) MimeFilter(MimeTypes.anyVideo),
|
if (entry.isVideo && !entry.is360) MimeFilter.video,
|
||||||
if (album != null) AlbumFilter(album, collection?.source?.getUniqueAlbumName(context, album)),
|
if (album != null) AlbumFilter(album, collection?.source?.getUniqueAlbumName(context, album)),
|
||||||
...tags.map((tag) => TagFilter(tag)),
|
...tags.map((tag) => TagFilter(tag)),
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,6 @@ import 'package:aves/model/filters/mime.dart';
|
||||||
import 'package:aves/model/filters/query.dart';
|
import 'package:aves/model/filters/query.dart';
|
||||||
import 'package:aves/model/filters/tag.dart';
|
import 'package:aves/model/filters/tag.dart';
|
||||||
import 'package:aves/model/filters/type.dart';
|
import 'package:aves/model/filters/type.dart';
|
||||||
import 'package:aves/ref/mime_types.dart';
|
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
@ -22,10 +21,10 @@ void main() {
|
||||||
final location = LocationFilter(LocationLevel.country, 'France${LocationFilter.locationSeparator}FR');
|
final location = LocationFilter(LocationLevel.country, 'France${LocationFilter.locationSeparator}FR');
|
||||||
expect(location, jsonRoundTrip(location));
|
expect(location, jsonRoundTrip(location));
|
||||||
|
|
||||||
final type = TypeFilter(TypeFilter.sphericalVideo);
|
final type = TypeFilter.sphericalVideo;
|
||||||
expect(type, jsonRoundTrip(type));
|
expect(type, jsonRoundTrip(type));
|
||||||
|
|
||||||
final mime = MimeFilter(MimeTypes.anyVideo);
|
final mime = MimeFilter.video;
|
||||||
expect(mime, jsonRoundTrip(mime));
|
expect(mime, jsonRoundTrip(mime));
|
||||||
|
|
||||||
final query = QueryFilter('some query');
|
final query = QueryFilter('some query');
|
||||||
|
|
Loading…
Reference in a new issue