settings: most recent fullscreen actions

This commit is contained in:
Thibault Deckers 2020-03-31 15:13:28 +09:00
parent dd4ac33b6d
commit fd149c30b3
5 changed files with 109 additions and 75 deletions

View file

@ -1,4 +1,5 @@
import 'package:aves/model/collection_lens.dart';
import 'package:aves/widgets/fullscreen/fullscreen_actions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -19,6 +20,7 @@ class Settings {
static const collectionSortFactorKey = 'collection_sort_factor';
static const infoMapZoomKey = 'info_map_zoom';
static const catalogTimeZoneKey = 'catalog_time_zone';
static const mostRecentFullscreenActionsKey = 'most_recent_fullscreen_actions';
Future<void> init() async {
prefs = await SharedPreferences.getInstance();
@ -60,6 +62,17 @@ class Settings {
set collectionSortFactor(SortFactor newValue) => setAndNotify(collectionSortFactorKey, newValue.toString());
List<FullscreenAction> get mostRecentFullscreenActions => getEnumListOrDefault(
mostRecentFullscreenActionsKey,
[
FullscreenAction.toggleFavourite,
FullscreenAction.share,
FullscreenAction.delete,
],
FullscreenAction.values);
set mostRecentFullscreenActions(List<FullscreenAction> newValue) => setAndNotify(mostRecentFullscreenActionsKey, newValue.map((v) => v.toString()).toList());
// convenience methods
bool getBoolOrDefault(String key, bool defaultValue) => prefs.getKeys().contains(key) ? prefs.getBool(key) : defaultValue;
@ -74,6 +87,10 @@ class Settings {
return defaultValue;
}
List<T> getEnumListOrDefault<T>(String key, List<T> defaultValue, Iterable<T> values) {
return prefs.getStringList(key)?.map((s) => values.firstWhere((el) => el.toString() == s, orElse: () => null))?.where((el) => el != null)?.toList() ?? defaultValue;
}
void setAndNotify(String key, dynamic newValue) {
var oldValue = prefs.get(key);
if (newValue == null) {
@ -81,6 +98,9 @@ class Settings {
} else if (newValue is String) {
oldValue = prefs.getString(key);
prefs.setString(key, newValue);
} else if (newValue is List<String>) {
oldValue = prefs.getStringList(key);
prefs.setStringList(key, newValue);
} else if (newValue is int) {
oldValue = prefs.getInt(key);
prefs.setInt(key, newValue);

View file

@ -51,6 +51,7 @@ class DebugPageState extends State<DebugPage> {
Text('collectionGroupFactor: ${settings.collectionGroupFactor}'),
Text('collectionSortFactor: ${settings.collectionSortFactor}'),
Text('infoMapZoom: ${settings.infoMapZoom}'),
Text('mostRecentFullscreenActions: ${settings.mostRecentFullscreenActions}'),
const Divider(),
Text('Entries: ${entries.length}'),
Text('Catalogued: ${catalogued.length}'),

View file

@ -4,14 +4,13 @@ import 'package:aves/model/collection_lens.dart';
import 'package:aves/model/image_entry.dart';
import 'package:aves/utils/android_app_service.dart';
import 'package:aves/widgets/common/image_providers/uri_image_provider.dart';
import 'package:aves/widgets/fullscreen/fullscreen_actions.dart';
import 'package:flushbar/flushbar.dart';
import 'package:flutter/material.dart';
import 'package:pdf/widgets.dart' as pdf;
import 'package:pedantic/pedantic.dart';
import 'package:printing/printing.dart';
enum FullscreenAction { delete, edit, info, open, openMap, print, rename, rotateCCW, rotateCW, setAs, share, toggleFavourite }
class FullscreenActionDelegate {
final CollectionLens collection;
final VoidCallback showInfo;

View file

@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
import 'package:outline_material_icons/outline_material_icons.dart';
import 'package:tuple/tuple.dart';
enum FullscreenAction { delete, edit, info, open, openMap, print, rename, rotateCCW, rotateCW, setAs, share, toggleFavourite }
class FullscreenActions {
static const inApp = [
FullscreenAction.info,
FullscreenAction.toggleFavourite,
FullscreenAction.share,
FullscreenAction.delete,
FullscreenAction.rename,
FullscreenAction.rotateCCW,
FullscreenAction.rotateCW,
FullscreenAction.print,
];
static const externalApp = [
FullscreenAction.edit,
FullscreenAction.open,
FullscreenAction.setAs,
FullscreenAction.openMap,
];
static Tuple2<String, IconData> getTextIcon(FullscreenAction action) {
switch (action) {
// in app actions
case FullscreenAction.delete:
return const Tuple2('Delete', OMIcons.delete);
case FullscreenAction.info:
return const Tuple2('Info', OMIcons.info);
case FullscreenAction.rename:
return const Tuple2('Rename', OMIcons.title);
case FullscreenAction.rotateCCW:
return const Tuple2('Rotate left', OMIcons.rotateLeft);
case FullscreenAction.rotateCW:
return const Tuple2('Rotate right', OMIcons.rotateRight);
case FullscreenAction.print:
return const Tuple2('Print', OMIcons.print);
case FullscreenAction.share:
return const Tuple2('Share', OMIcons.share);
// external app actions
case FullscreenAction.edit:
return const Tuple2('Edit with…', null);
case FullscreenAction.open:
return const Tuple2('Open with…', null);
case FullscreenAction.setAs:
return const Tuple2('Set as…', null);
case FullscreenAction.openMap:
return const Tuple2('Show on map…', null);
}
return null;
}
}

View file

@ -1,9 +1,10 @@
import 'dart:math';
import 'package:aves/model/image_entry.dart';
import 'package:aves/model/settings.dart';
import 'package:aves/widgets/common/fx/sweeper.dart';
import 'package:aves/widgets/common/menu_row.dart';
import 'package:aves/widgets/fullscreen/fullscreen_action_delegate.dart';
import 'package:aves/widgets/fullscreen/fullscreen_actions.dart';
import 'package:aves/widgets/fullscreen/overlay/common.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@ -22,6 +23,12 @@ class FullscreenTopOverlay extends StatelessWidget {
static const double padding = 8;
static const int landscapeActionCount = 3;
static const int portraitActionCount = 2;
static const List<FullscreenAction> possibleOverlayActions = FullscreenActions.inApp;
const FullscreenTopOverlay({
Key key,
@required this.entries,
@ -42,35 +49,15 @@ class FullscreenTopOverlay extends StatelessWidget {
child: Selector<MediaQueryData, Orientation>(
selector: (c, mq) => mq.orientation,
builder: (c, orientation, child) {
final targetCount = orientation == Orientation.landscape ? 3 : 2;
final targetCount = orientation == Orientation.landscape ? landscapeActionCount : portraitActionCount;
return LayoutBuilder(
builder: (context, constraints) {
final availableCount = (constraints.maxWidth / (kMinInteractiveDimension + padding)).floor() - 2;
final recentActionCount = min(targetCount, availableCount);
final recentActions = [
FullscreenAction.toggleFavourite,
FullscreenAction.share,
FullscreenAction.delete,
FullscreenAction.info,
FullscreenAction.rename,
].where(_canDo).take(recentActionCount);
final inAppActions = [
FullscreenAction.info,
FullscreenAction.toggleFavourite,
FullscreenAction.share,
FullscreenAction.delete,
FullscreenAction.rename,
FullscreenAction.rotateCCW,
FullscreenAction.rotateCW,
FullscreenAction.print,
].where((action) => !recentActions.contains(action)).where(_canDo);
final externalAppActions = [
FullscreenAction.edit,
FullscreenAction.open,
FullscreenAction.setAs,
FullscreenAction.openMap,
].where(_canDo);
final recentActions = settings.mostRecentFullscreenActions.where(_canDo).take(recentActionCount);
final inAppActions = FullscreenActions.inApp.where((action) => !recentActions.contains(action)).where(_canDo);
final externalAppActions = FullscreenActions.externalApp.where(_canDo);
return Row(
children: [
@ -88,7 +75,12 @@ class FullscreenTopOverlay extends StatelessWidget {
const PopupMenuDivider(),
...externalAppActions.map(_buildPopupMenuItem),
],
onSelected: onActionSelected,
onSelected: (action) {
if (possibleOverlayActions.contains(action)) {
settings.mostRecentFullscreenActions = [action, ...settings.mostRecentFullscreenActions].take(landscapeActionCount).toList();
}
onActionSelected?.call(action);
},
),
),
],
@ -148,37 +140,20 @@ class FullscreenTopOverlay extends StatelessWidget {
),
);
break;
case FullscreenAction.share:
child = IconButton(
icon: const Icon(OMIcons.share),
onPressed: onPressed,
tooltip: 'Share',
);
break;
case FullscreenAction.delete:
child = IconButton(
icon: const Icon(OMIcons.delete),
onPressed: onPressed,
tooltip: 'Delete',
);
break;
case FullscreenAction.info:
child = IconButton(
icon: const Icon(OMIcons.info),
onPressed: onPressed,
tooltip: 'Info',
);
break;
case FullscreenAction.share:
case FullscreenAction.delete:
case FullscreenAction.rename:
child = IconButton(
icon: const Icon(OMIcons.title),
onPressed: onPressed,
tooltip: 'Rename',
);
break;
case FullscreenAction.rotateCCW:
case FullscreenAction.rotateCW:
case FullscreenAction.print:
final textIcon = FullscreenActions.getTextIcon(action);
child = IconButton(
icon: Icon(textIcon.item2),
onPressed: onPressed,
tooltip: textIcon.item1,
);
break;
case FullscreenAction.openMap:
case FullscreenAction.open:
case FullscreenAction.edit:
@ -200,9 +175,6 @@ class FullscreenTopOverlay extends StatelessWidget {
Widget child;
switch (action) {
// in app actions
case FullscreenAction.info:
child = const MenuRow(text: 'Info', icon: OMIcons.info);
break;
case FullscreenAction.toggleFavourite:
child = entry.isFavouriteNotifier.value
? const MenuRow(
@ -214,36 +186,23 @@ class FullscreenTopOverlay extends StatelessWidget {
icon: OMIcons.favoriteBorder,
);
break;
case FullscreenAction.info:
case FullscreenAction.share:
child = const MenuRow(text: 'Share', icon: OMIcons.share);
break;
case FullscreenAction.delete:
child = const MenuRow(text: 'Delete', icon: OMIcons.delete);
break;
case FullscreenAction.rename:
child = const MenuRow(text: 'Rename', icon: OMIcons.title);
break;
case FullscreenAction.rotateCCW:
child = const MenuRow(text: 'Rotate left', icon: OMIcons.rotateLeft);
break;
case FullscreenAction.rotateCW:
child = const MenuRow(text: 'Rotate right', icon: OMIcons.rotateRight);
break;
case FullscreenAction.print:
child = const MenuRow(text: 'Print', icon: OMIcons.print);
final textIcon = FullscreenActions.getTextIcon(action);
child = MenuRow(text: textIcon.item1, icon: textIcon.item2);
break;
// external app actions
case FullscreenAction.edit:
child = const Text('Edit with…');
break;
case FullscreenAction.open:
child = const Text('Open with…');
break;
case FullscreenAction.setAs:
child = const Text('Set as…');
break;
case FullscreenAction.openMap:
child = const Text('Show on map…');
final textIcon = FullscreenActions.getTextIcon(action);
child = Text(textIcon.item1);
break;
}
return PopupMenuItem(