From f16d98ba2b74f43870eb6e5f3373af5c15f2b244 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Wed, 17 Feb 2021 11:44:59 +0900 Subject: [PATCH] settings: changed layout for hidden filters and access grants --- lib/widgets/collection/empty.dart | 16 +-- lib/widgets/settings/access_grants.dart | 123 +++++++++++++++-------- lib/widgets/settings/hidden_filters.dart | 99 ++++++++++-------- lib/widgets/settings/settings_page.dart | 7 +- 4 files changed, 151 insertions(+), 94 deletions(-) diff --git a/lib/widgets/collection/empty.dart b/lib/widgets/collection/empty.dart index ea79572db..522459e96 100644 --- a/lib/widgets/collection/empty.dart +++ b/lib/widgets/collection/empty.dart @@ -6,7 +6,7 @@ class EmptyContent extends StatelessWidget { final AlignmentGeometry alignment; const EmptyContent({ - @required this.icon, + this.icon, @required this.text, this.alignment = const FractionalOffset(.5, .35), }); @@ -19,12 +19,14 @@ class EmptyContent extends StatelessWidget { child: Column( mainAxisSize: MainAxisSize.min, children: [ - Icon( - icon, - size: 64, - color: color, - ), - SizedBox(height: 16), + if (icon != null) ...[ + Icon( + icon, + size: 64, + color: color, + ), + SizedBox(height: 16) + ], Text( text, style: TextStyle( diff --git a/lib/widgets/settings/access_grants.dart b/lib/widgets/settings/access_grants.dart index a58a588c7..ef9bb7808 100644 --- a/lib/widgets/settings/access_grants.dart +++ b/lib/widgets/settings/access_grants.dart @@ -1,13 +1,34 @@ import 'package:aves/services/android_file_service.dart'; +import 'package:aves/theme/icons.dart'; +import 'package:aves/widgets/collection/empty.dart'; import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -class GrantedDirectories extends StatefulWidget { +class StorageAccessTile extends StatelessWidget { @override - _GrantedDirectoriesState createState() => _GrantedDirectoriesState(); + Widget build(BuildContext context) { + return ListTile( + title: Text('Storage Access'), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + settings: RouteSettings(name: StorageAccessPage.routeName), + builder: (context) => StorageAccessPage(), + ), + ); + }, + ); + } } -class _GrantedDirectoriesState extends State { +class StorageAccessPage extends StatefulWidget { + static const routeName = '/settings/storage_access'; + + @override + _StorageAccessPageState createState() => _StorageAccessPageState(); +} + +class _StorageAccessPageState extends State { Future> _pathLoader; List _lastPaths; @@ -21,44 +42,64 @@ class _GrantedDirectoriesState extends State { @override Widget build(BuildContext context) { - final textTheme = Theme.of(context).textTheme; - return Padding( - padding: EdgeInsets.symmetric(horizontal: 16), - child: FutureBuilder>( - future: _pathLoader, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Text(snapshot.error.toString()); - } - if (snapshot.connectionState != ConnectionState.done && _lastPaths == null) { - return SizedBox.shrink(); - } - _lastPaths = snapshot.data..sort(); - final count = _lastPaths.length; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Aves has access to ${Intl.plural(count, zero: 'no directories.', one: 'one directory:', other: '$count directories:')}', - style: textTheme.subtitle1, + return Scaffold( + appBar: AppBar( + title: Text('Storage Access'), + ), + body: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.symmetric(vertical: 8, horizontal: 16), + child: Row( + children: [ + Icon(AIcons.info), + SizedBox(width: 16), + Expanded(child: Text('Some directories require an explicit access grant to modify files in them. You can review here directories to which you previously gave access.')), + ], ), - ..._lastPaths.map((path) => Row( - children: [ - Expanded(child: Text(path, style: textTheme.caption)), - SizedBox(width: 8), - OutlinedButton( - onPressed: () async { - await AndroidFileService.revokeDirectoryAccess(path); - _load(); - setState(() {}); - }, - child: Text('Revoke'.toUpperCase()), - ), - ], - )), - ], - ); - }, + ), + Divider(), + Expanded( + child: FutureBuilder>( + future: _pathLoader, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Text(snapshot.error.toString()); + } + if (snapshot.connectionState != ConnectionState.done && _lastPaths == null) { + return SizedBox.shrink(); + } + _lastPaths = snapshot.data..sort(); + if (_lastPaths.isEmpty) { + return EmptyContent( + text: 'No access grants', + ); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: _lastPaths + .map((path) => ListTile( + title: Text(path), + dense: true, + trailing: IconButton( + icon: Icon(AIcons.clear), + onPressed: () async { + await AndroidFileService.revokeDirectoryAccess(path); + _load(); + setState(() {}); + }, + tooltip: 'Revoke', + ), + )) + .toList(), + ); + }, + ), + ), + ], + ), ), ); } diff --git a/lib/widgets/settings/hidden_filters.dart b/lib/widgets/settings/hidden_filters.dart index ccbde9d95..bfc39372f 100644 --- a/lib/widgets/settings/hidden_filters.dart +++ b/lib/widgets/settings/hidden_filters.dart @@ -1,34 +1,26 @@ -import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_source.dart'; +import 'package:aves/theme/icons.dart'; +import 'package:aves/widgets/collection/empty.dart'; import 'package:aves/widgets/common/identity/aves_filter_chip.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -class HiddenFilters extends StatelessWidget { +class HiddenFilterTile extends StatelessWidget { @override Widget build(BuildContext context) { - return Selector>( - selector: (context, s) => s.hiddenFilters, - builder: (context, hiddenFilters, child) { - return ListTile( - title: hiddenFilters.isEmpty ? Text('There are no hidden filters') : Text('Hidden filters'), - trailing: hiddenFilters.isEmpty - ? null - : OutlinedButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - settings: RouteSettings(name: HiddenFilterPage.routeName), - builder: (context) => HiddenFilterPage(), - ), - ); - }, - child: Text('Edit'.toUpperCase()), - ), - ); - }); + return ListTile( + title: Text('Hidden filters'), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + settings: RouteSettings(name: HiddenFilterPage.routeName), + builder: (context) => HiddenFilterPage(), + ), + ); + }, + ); } } @@ -42,24 +34,49 @@ class HiddenFilterPage extends StatelessWidget { title: Text('Hidden Filters'), ), body: SafeArea( - child: Padding( - padding: EdgeInsets.all(8), - child: Consumer( - builder: (context, settings, child) { - final filterList = settings.hiddenFilters.toList()..sort(); - return Wrap( - spacing: 8, - runSpacing: 8, - children: filterList - .map((filter) => AvesFilterChip( - filter: filter, - removable: true, - onTap: (filter) => context.read().changeFilterVisibility(filter, true), - )) - .toList(), - ); - }, - ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.symmetric(vertical: 8, horizontal: 16), + child: Row( + children: [ + Icon(AIcons.info), + SizedBox(width: 16), + Expanded(child: Text('Photos and videos matching hidden filters will not appear in your collection.')), + ], + ), + ), + Divider(), + Expanded( + child: Padding( + padding: EdgeInsets.all(8), + child: Consumer( + builder: (context, settings, child) { + final hiddenFilters = settings.hiddenFilters; + final filterList = hiddenFilters.toList()..sort(); + if (hiddenFilters.isEmpty) { + return EmptyContent( + icon: AIcons.hide, + text: 'No hidden filters', + ); + } + return Wrap( + spacing: 8, + runSpacing: 8, + children: filterList + .map((filter) => AvesFilterChip( + filter: filter, + removable: true, + onTap: (filter) => context.read().changeFilterVisibility(filter, true), + )) + .toList(), + ); + }, + ), + ), + ), + ], ), ), ); diff --git a/lib/widgets/settings/settings_page.dart b/lib/widgets/settings/settings_page.dart index 5da66e45e..695854bc6 100644 --- a/lib/widgets/settings/settings_page.dart +++ b/lib/widgets/settings/settings_page.dart @@ -242,11 +242,8 @@ class _SettingsPageState extends State { onChanged: (v) => settings.isCrashlyticsEnabled = v, title: Text('Allow anonymous analytics and crash reporting'), ), - HiddenFilters(), - Padding( - padding: EdgeInsets.only(top: 8, bottom: 16), - child: GrantedDirectories(), - ), + HiddenFilterTile(), + StorageAccessTile(), ], ); }