settings: changed layout for hidden filters and access grants

This commit is contained in:
Thibault Deckers 2021-02-17 11:44:59 +09:00
parent cadd2b4d1c
commit f16d98ba2b
4 changed files with 151 additions and 94 deletions

View file

@ -6,7 +6,7 @@ class EmptyContent extends StatelessWidget {
final AlignmentGeometry alignment; final AlignmentGeometry alignment;
const EmptyContent({ const EmptyContent({
@required this.icon, this.icon,
@required this.text, @required this.text,
this.alignment = const FractionalOffset(.5, .35), this.alignment = const FractionalOffset(.5, .35),
}); });
@ -19,12 +19,14 @@ class EmptyContent extends StatelessWidget {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
if (icon != null) ...[
Icon( Icon(
icon, icon,
size: 64, size: 64,
color: color, color: color,
), ),
SizedBox(height: 16), SizedBox(height: 16)
],
Text( Text(
text, text,
style: TextStyle( style: TextStyle(

View file

@ -1,13 +1,34 @@
import 'package:aves/services/android_file_service.dart'; 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:flutter/material.dart';
import 'package:intl/intl.dart';
class GrantedDirectories extends StatefulWidget { class StorageAccessTile extends StatelessWidget {
@override @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<GrantedDirectories> { class StorageAccessPage extends StatefulWidget {
static const routeName = '/settings/storage_access';
@override
_StorageAccessPageState createState() => _StorageAccessPageState();
}
class _StorageAccessPageState extends State<StorageAccessPage> {
Future<List<String>> _pathLoader; Future<List<String>> _pathLoader;
List<String> _lastPaths; List<String> _lastPaths;
@ -21,9 +42,26 @@ class _GrantedDirectoriesState extends State<GrantedDirectories> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme; return Scaffold(
return Padding( appBar: AppBar(
padding: EdgeInsets.symmetric(horizontal: 16), 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.')),
],
),
),
Divider(),
Expanded(
child: FutureBuilder<List<String>>( child: FutureBuilder<List<String>>(
future: _pathLoader, future: _pathLoader,
builder: (context, snapshot) { builder: (context, snapshot) {
@ -34,32 +72,35 @@ class _GrantedDirectoriesState extends State<GrantedDirectories> {
return SizedBox.shrink(); return SizedBox.shrink();
} }
_lastPaths = snapshot.data..sort(); _lastPaths = snapshot.data..sort();
final count = _lastPaths.length; if (_lastPaths.isEmpty) {
return EmptyContent(
text: 'No access grants',
);
}
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: _lastPaths
Text( .map((path) => ListTile(
'Aves has access to ${Intl.plural(count, zero: 'no directories.', one: 'one directory:', other: '$count directories:')}', title: Text(path),
style: textTheme.subtitle1, dense: true,
), trailing: IconButton(
..._lastPaths.map((path) => Row( icon: Icon(AIcons.clear),
children: [
Expanded(child: Text(path, style: textTheme.caption)),
SizedBox(width: 8),
OutlinedButton(
onPressed: () async { onPressed: () async {
await AndroidFileService.revokeDirectoryAccess(path); await AndroidFileService.revokeDirectoryAccess(path);
_load(); _load();
setState(() {}); setState(() {});
}, },
child: Text('Revoke'.toUpperCase()), tooltip: 'Revoke',
), ),
], ))
)), .toList(),
],
); );
}, },
), ),
),
],
),
),
); );
} }
} }

View file

@ -1,22 +1,17 @@
import 'package:aves/model/filters/filters.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/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:aves/widgets/common/identity/aves_filter_chip.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class HiddenFilters extends StatelessWidget { class HiddenFilterTile extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Selector<Settings, Set<CollectionFilter>>(
selector: (context, s) => s.hiddenFilters,
builder: (context, hiddenFilters, child) {
return ListTile( return ListTile(
title: hiddenFilters.isEmpty ? Text('There are no hidden filters') : Text('Hidden filters'), title: Text('Hidden filters'),
trailing: hiddenFilters.isEmpty onTap: () {
? null
: OutlinedButton(
onPressed: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
@ -25,10 +20,7 @@ class HiddenFilters extends StatelessWidget {
), ),
); );
}, },
child: Text('Edit'.toUpperCase()),
),
); );
});
} }
} }
@ -42,11 +34,33 @@ class HiddenFilterPage extends StatelessWidget {
title: Text('Hidden Filters'), title: Text('Hidden Filters'),
), ),
body: SafeArea( 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('Photos and videos matching hidden filters will not appear in your collection.')),
],
),
),
Divider(),
Expanded(
child: Padding( child: Padding(
padding: EdgeInsets.all(8), padding: EdgeInsets.all(8),
child: Consumer<Settings>( child: Consumer<Settings>(
builder: (context, settings, child) { builder: (context, settings, child) {
final filterList = settings.hiddenFilters.toList()..sort(); final hiddenFilters = settings.hiddenFilters;
final filterList = hiddenFilters.toList()..sort();
if (hiddenFilters.isEmpty) {
return EmptyContent(
icon: AIcons.hide,
text: 'No hidden filters',
);
}
return Wrap( return Wrap(
spacing: 8, spacing: 8,
runSpacing: 8, runSpacing: 8,
@ -62,6 +76,9 @@ class HiddenFilterPage extends StatelessWidget {
), ),
), ),
), ),
],
),
),
); );
} }
} }

View file

@ -242,11 +242,8 @@ class _SettingsPageState extends State<SettingsPage> {
onChanged: (v) => settings.isCrashlyticsEnabled = v, onChanged: (v) => settings.isCrashlyticsEnabled = v,
title: Text('Allow anonymous analytics and crash reporting'), title: Text('Allow anonymous analytics and crash reporting'),
), ),
HiddenFilters(), HiddenFilterTile(),
Padding( StorageAccessTile(),
padding: EdgeInsets.only(top: 8, bottom: 16),
child: GrantedDirectories(),
),
], ],
); );
} }