Merge branch 'develop'
This commit is contained in:
commit
041565b34a
17 changed files with 271 additions and 143 deletions
|
@ -85,6 +85,8 @@ class CollectionLens with ChangeNotifier, CollectionActivityMixin, CollectionSel
|
|||
bool get showHeaders {
|
||||
if (sortFactor == SortFactor.size) return false;
|
||||
|
||||
if (sortFactor == SortFactor.date && groupFactor == GroupFactor.none) return false;
|
||||
|
||||
final albumSections = sortFactor == SortFactor.name || (sortFactor == SortFactor.date && groupFactor == GroupFactor.album);
|
||||
final filterByAlbum = filters.any((f) => f is AlbumFilter);
|
||||
if (albumSections && filterByAlbum) return false;
|
||||
|
@ -160,6 +162,11 @@ class CollectionLens with ChangeNotifier, CollectionActivityMixin, CollectionSel
|
|||
case GroupFactor.day:
|
||||
sections = groupBy<ImageEntry, DateTime>(_filteredEntries, (entry) => entry.dayTaken);
|
||||
break;
|
||||
case GroupFactor.none:
|
||||
sections = Map.fromEntries([
|
||||
MapEntry(null, _filteredEntries),
|
||||
]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SortFactor.size:
|
||||
|
@ -209,7 +216,7 @@ class CollectionLens with ChangeNotifier, CollectionActivityMixin, CollectionSel
|
|||
|
||||
enum SortFactor { date, size, name }
|
||||
|
||||
enum GroupFactor { album, month, day }
|
||||
enum GroupFactor { none, album, month, day }
|
||||
|
||||
enum Activity { browse, select }
|
||||
|
||||
|
|
|
@ -22,6 +22,14 @@ class Constants {
|
|||
static const svgBackground = Colors.white;
|
||||
static const svgColorFilter = ColorFilter.mode(svgBackground, BlendMode.dstOver);
|
||||
|
||||
static const dialogContentHorizontalPadding = EdgeInsets.symmetric(horizontal: 24);
|
||||
static const dialogActionsPadding = EdgeInsets.symmetric(horizontal: 8);
|
||||
static const dialogShape = RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(24),
|
||||
),
|
||||
);
|
||||
|
||||
static const List<Dependency> androidDependencies = [
|
||||
Dependency(
|
||||
name: 'CWAC-Document',
|
||||
|
|
|
@ -11,7 +11,7 @@ class Durations {
|
|||
|
||||
// collection animations
|
||||
static const appBarTitleAnimation = Duration(milliseconds: 300);
|
||||
static const filterBarRemovalAnimation = Duration(milliseconds: 200);
|
||||
static const filterBarRemovalAnimation = Duration(milliseconds: 400);
|
||||
static const collectionOpOverlayAnimation = Duration(milliseconds: 300);
|
||||
static const collectionScalingBackgroundAnimation = Duration(milliseconds: 200);
|
||||
static const sectionHeaderAnimation = Duration(milliseconds: 200);
|
||||
|
|
|
@ -6,7 +6,9 @@ import 'package:aves/model/source/collection_lens.dart';
|
|||
import 'package:aves/utils/durations.dart';
|
||||
import 'package:aves/widgets/album/filter_bar.dart';
|
||||
import 'package:aves/widgets/album/search/search_delegate.dart';
|
||||
import 'package:aves/widgets/common/action_delegates/group_collection_dialog.dart';
|
||||
import 'package:aves/widgets/common/action_delegates/selection_action_delegate.dart';
|
||||
import 'package:aves/widgets/common/action_delegates/sort_collection_dialog.dart';
|
||||
import 'package:aves/widgets/common/app_bar_subtitle.dart';
|
||||
import 'package:aves/widgets/common/data_providers/media_store_collection_provider.dart';
|
||||
import 'package:aves/widgets/common/entry_actions.dart';
|
||||
|
@ -185,8 +187,15 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
itemBuilder: (context) {
|
||||
final hasSelection = collection.selection.isNotEmpty;
|
||||
return [
|
||||
..._buildSortMenuItems(),
|
||||
..._buildGroupMenuItems(),
|
||||
PopupMenuItem(
|
||||
value: CollectionAction.sort,
|
||||
child: MenuRow(text: 'Sort...', icon: AIcons.sort),
|
||||
),
|
||||
if (collection.sortFactor == SortFactor.date)
|
||||
PopupMenuItem(
|
||||
value: CollectionAction.group,
|
||||
child: MenuRow(text: 'Group...', icon: AIcons.group),
|
||||
),
|
||||
if (collection.isBrowsing) ...[
|
||||
if (AvesApp.mode == AppMode.main)
|
||||
if (kDebugMode)
|
||||
|
@ -204,6 +213,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
),
|
||||
],
|
||||
if (collection.isSelecting) ...[
|
||||
PopupMenuDivider(),
|
||||
PopupMenuItem(
|
||||
value: CollectionAction.copy,
|
||||
enabled: hasSelection,
|
||||
|
@ -238,44 +248,6 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
];
|
||||
}
|
||||
|
||||
List<PopupMenuEntry<CollectionAction>> _buildSortMenuItems() {
|
||||
return [
|
||||
PopupMenuItem(
|
||||
value: CollectionAction.sortByDate,
|
||||
child: MenuRow(text: 'Sort by date', checked: collection.sortFactor == SortFactor.date),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: CollectionAction.sortBySize,
|
||||
child: MenuRow(text: 'Sort by size', checked: collection.sortFactor == SortFactor.size),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: CollectionAction.sortByName,
|
||||
child: MenuRow(text: 'Sort by name', checked: collection.sortFactor == SortFactor.name),
|
||||
),
|
||||
PopupMenuDivider(),
|
||||
];
|
||||
}
|
||||
|
||||
List<PopupMenuEntry<CollectionAction>> _buildGroupMenuItems() {
|
||||
return collection.sortFactor == SortFactor.date
|
||||
? [
|
||||
PopupMenuItem(
|
||||
value: CollectionAction.groupByAlbum,
|
||||
child: MenuRow(text: 'Group by album', checked: collection.groupFactor == GroupFactor.album),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: CollectionAction.groupByMonth,
|
||||
child: MenuRow(text: 'Group by month', checked: collection.groupFactor == GroupFactor.month),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: CollectionAction.groupByDay,
|
||||
child: MenuRow(text: 'Group by day', checked: collection.groupFactor == GroupFactor.day),
|
||||
),
|
||||
PopupMenuDivider(),
|
||||
]
|
||||
: [];
|
||||
}
|
||||
|
||||
void _onActivityChange() {
|
||||
if (collection.isSelecting) {
|
||||
_browseToSelectAnimation.forward();
|
||||
|
@ -317,29 +289,25 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
case CollectionAction.stats:
|
||||
unawaited(_goToStats());
|
||||
break;
|
||||
case CollectionAction.groupByAlbum:
|
||||
settings.collectionGroupFactor = GroupFactor.album;
|
||||
collection.group(GroupFactor.album);
|
||||
case CollectionAction.group:
|
||||
final factor = await showDialog<GroupFactor>(
|
||||
context: context,
|
||||
builder: (context) => GroupCollectionDialog(),
|
||||
);
|
||||
if (factor != null) {
|
||||
settings.collectionGroupFactor = factor;
|
||||
collection.group(factor);
|
||||
}
|
||||
break;
|
||||
case CollectionAction.groupByMonth:
|
||||
settings.collectionGroupFactor = GroupFactor.month;
|
||||
collection.group(GroupFactor.month);
|
||||
break;
|
||||
case CollectionAction.groupByDay:
|
||||
settings.collectionGroupFactor = GroupFactor.day;
|
||||
collection.group(GroupFactor.day);
|
||||
break;
|
||||
case CollectionAction.sortByDate:
|
||||
settings.collectionSortFactor = SortFactor.date;
|
||||
collection.sort(SortFactor.date);
|
||||
break;
|
||||
case CollectionAction.sortBySize:
|
||||
settings.collectionSortFactor = SortFactor.size;
|
||||
collection.sort(SortFactor.size);
|
||||
break;
|
||||
case CollectionAction.sortByName:
|
||||
settings.collectionSortFactor = SortFactor.name;
|
||||
collection.sort(SortFactor.name);
|
||||
case CollectionAction.sort:
|
||||
final factor = await showDialog<SortFactor>(
|
||||
context: context,
|
||||
builder: (context) => SortCollectionDialog(),
|
||||
);
|
||||
if (factor != null) {
|
||||
settings.collectionSortFactor = factor;
|
||||
collection.sort(factor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -365,17 +333,13 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
|
||||
enum CollectionAction {
|
||||
copy,
|
||||
group,
|
||||
move,
|
||||
refresh,
|
||||
refreshMetadata,
|
||||
select,
|
||||
selectAll,
|
||||
selectNone,
|
||||
sort,
|
||||
stats,
|
||||
groupByAlbum,
|
||||
groupByMonth,
|
||||
groupByDay,
|
||||
sortByDate,
|
||||
sortBySize,
|
||||
sortByName,
|
||||
}
|
||||
|
|
|
@ -45,7 +45,9 @@ class _FilterBarState extends State<FilterBar> {
|
|||
listState.removeItem(
|
||||
index,
|
||||
animate
|
||||
? (context, animation) => FadeTransition(
|
||||
? (context, animation) {
|
||||
animation = animation.drive(CurveTween(curve: Curves.easeInOutBack));
|
||||
return FadeTransition(
|
||||
opacity: animation,
|
||||
child: SizeTransition(
|
||||
axis: Axis.horizontal,
|
||||
|
@ -55,7 +57,8 @@ class _FilterBarState extends State<FilterBar> {
|
|||
child: _buildChip(filter),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
: (context, animation) => _buildChip(filter),
|
||||
duration: animate ? Durations.filterBarRemovalAnimation : Duration.zero,
|
||||
);
|
||||
|
|
|
@ -29,18 +29,18 @@ class SectionHeader extends StatelessWidget {
|
|||
Widget header;
|
||||
switch (collection.sortFactor) {
|
||||
case SortFactor.date:
|
||||
if (collection.sortFactor == SortFactor.date) {
|
||||
switch (collection.groupFactor) {
|
||||
case GroupFactor.album:
|
||||
header = _buildAlbumSectionHeader();
|
||||
break;
|
||||
case GroupFactor.month:
|
||||
header = MonthSectionHeader(key: ValueKey(sectionKey), date: sectionKey as DateTime);
|
||||
break;
|
||||
case GroupFactor.day:
|
||||
header = DaySectionHeader(key: ValueKey(sectionKey), date: sectionKey as DateTime);
|
||||
break;
|
||||
}
|
||||
switch (collection.groupFactor) {
|
||||
case GroupFactor.album:
|
||||
header = _buildAlbumSectionHeader();
|
||||
break;
|
||||
case GroupFactor.month:
|
||||
header = MonthSectionHeader(key: ValueKey(sectionKey), date: sectionKey as DateTime);
|
||||
break;
|
||||
case GroupFactor.day:
|
||||
header = DaySectionHeader(key: ValueKey(sectionKey), date: sectionKey as DateTime);
|
||||
break;
|
||||
case GroupFactor.none:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SortFactor.size:
|
||||
|
|
|
@ -9,12 +9,14 @@ class ExpandableFilterRow extends StatelessWidget {
|
|||
final String title;
|
||||
final Iterable<CollectionFilter> filters;
|
||||
final ValueNotifier<String> expandedNotifier;
|
||||
final HeroType Function(CollectionFilter filter) heroTypeBuilder;
|
||||
final FilterCallback onPressed;
|
||||
|
||||
const ExpandableFilterRow({
|
||||
this.title,
|
||||
@required this.filters,
|
||||
this.expandedNotifier,
|
||||
this.heroTypeBuilder,
|
||||
@required this.onPressed,
|
||||
});
|
||||
|
||||
|
@ -59,12 +61,7 @@ class ExpandableFilterRow extends StatelessWidget {
|
|||
child: Wrap(
|
||||
spacing: horizontalPadding,
|
||||
runSpacing: verticalPadding,
|
||||
children: filtersList
|
||||
.map((filter) => AvesFilterChip(
|
||||
filter: filter,
|
||||
onPressed: onPressed,
|
||||
))
|
||||
.toList(),
|
||||
children: filtersList.map(_buildFilterChip).toList(),
|
||||
),
|
||||
);
|
||||
final list = Container(
|
||||
|
@ -78,12 +75,7 @@ class ExpandableFilterRow extends StatelessWidget {
|
|||
physics: BouncingScrollPhysics(),
|
||||
padding: EdgeInsets.symmetric(horizontal: horizontalPadding),
|
||||
itemBuilder: (context, index) {
|
||||
if (index >= filtersList.length) return null;
|
||||
final filter = filtersList[index];
|
||||
return AvesFilterChip(
|
||||
filter: filter,
|
||||
onPressed: onPressed,
|
||||
);
|
||||
return index < filtersList.length ? _buildFilterChip(filtersList[index]) : null;
|
||||
},
|
||||
separatorBuilder: (context, index) => SizedBox(width: 8),
|
||||
itemCount: filtersList.length,
|
||||
|
@ -109,4 +101,12 @@ class ExpandableFilterRow extends StatelessWidget {
|
|||
)
|
||||
: filterChips;
|
||||
}
|
||||
|
||||
Widget _buildFilterChip(CollectionFilter filter) {
|
||||
return AvesFilterChip(
|
||||
filter: filter,
|
||||
heroType: heroTypeBuilder?.call(filter) ?? HeroType.onTap,
|
||||
onPressed: onPressed,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,19 +62,23 @@ class ImageSearchDelegate extends SearchDelegate<CollectionFilter> {
|
|||
child: ValueListenableBuilder<String>(
|
||||
valueListenable: expandedSectionNotifier,
|
||||
builder: (context, expandedSection, child) {
|
||||
var queryFilter = _buildQueryFilter(false);
|
||||
return ListView(
|
||||
padding: EdgeInsets.only(top: 8),
|
||||
children: [
|
||||
_buildFilterRow(
|
||||
context: context,
|
||||
filters: [
|
||||
_buildQueryFilter(false),
|
||||
queryFilter,
|
||||
FavouriteFilter(),
|
||||
MimeFilter(MimeTypes.anyImage),
|
||||
MimeFilter(MimeTypes.anyVideo),
|
||||
MimeFilter(MimeFilter.animated),
|
||||
MimeFilter(MimeTypes.svg),
|
||||
].where((f) => f != null && containQuery(f.label)),
|
||||
// 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
|
||||
heroTypeBuilder: (filter) => filter == queryFilter ? HeroType.always : HeroType.onTap,
|
||||
),
|
||||
StreamBuilder(
|
||||
stream: source.eventBus.on<AlbumsChangedEvent>(),
|
||||
|
@ -118,11 +122,17 @@ class ImageSearchDelegate extends SearchDelegate<CollectionFilter> {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildFilterRow({@required BuildContext context, String title, @required Iterable<CollectionFilter> filters}) {
|
||||
Widget _buildFilterRow({
|
||||
@required BuildContext context,
|
||||
String title,
|
||||
@required Iterable<CollectionFilter> filters,
|
||||
HeroType Function(CollectionFilter filter) heroTypeBuilder,
|
||||
}) {
|
||||
return ExpandableFilterRow(
|
||||
title: title,
|
||||
filters: filters,
|
||||
expandedNotifier: expandedSectionNotifier,
|
||||
heroTypeBuilder: heroTypeBuilder,
|
||||
onPressed: (filter) => _select(context, filter is QueryFilter ? QueryFilter(filter.query) : filter),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:aves/utils/android_file_utils.dart';
|
||||
import 'package:aves/utils/constants.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:path/path.dart';
|
||||
|
@ -35,56 +36,55 @@ class _CreateAlbumDialogState extends State<CreateAlbumDialog> {
|
|||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('New Album'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
content: ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
if (_allVolumes.length > 1) ...[
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('Storage:'),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: DropdownButton<StorageVolume>(
|
||||
isExpanded: true,
|
||||
items: _allVolumes
|
||||
.map((volume) => DropdownMenuItem(
|
||||
value: volume,
|
||||
child: Text(
|
||||
volume.description,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
),
|
||||
))
|
||||
.toList(),
|
||||
value: _selectedVolume,
|
||||
onChanged: (volume) {
|
||||
_selectedVolume = volume;
|
||||
_checkAlbumExists();
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
Padding(
|
||||
padding: Constants.dialogContentHorizontalPadding,
|
||||
child: Text('Storage:'),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
ValueListenableBuilder<bool>(
|
||||
valueListenable: _existsNotifier,
|
||||
builder: (context, exists, child) {
|
||||
return TextField(
|
||||
controller: _nameController,
|
||||
decoration: InputDecoration(
|
||||
helperText: exists ? 'Album already exists' : '',
|
||||
..._allVolumes.map((volume) => RadioListTile<StorageVolume>(
|
||||
value: volume,
|
||||
groupValue: _selectedVolume,
|
||||
onChanged: (volume) {
|
||||
_selectedVolume = volume;
|
||||
_checkAlbumExists();
|
||||
setState(() {});
|
||||
},
|
||||
title: Text(
|
||||
volume.description,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
),
|
||||
onChanged: (_) => _checkAlbumExists(),
|
||||
onSubmitted: (_) => _submit(context),
|
||||
);
|
||||
}),
|
||||
subtitle: Text(
|
||||
volume.path,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
),
|
||||
)),
|
||||
SizedBox(height: 8),
|
||||
],
|
||||
Padding(
|
||||
padding: Constants.dialogContentHorizontalPadding,
|
||||
child: ValueListenableBuilder<bool>(
|
||||
valueListenable: _existsNotifier,
|
||||
builder: (context, exists, child) {
|
||||
return TextField(
|
||||
controller: _nameController,
|
||||
decoration: InputDecoration(
|
||||
helperText: exists ? 'Album already exists' : '',
|
||||
),
|
||||
onChanged: (_) => _checkAlbumExists(),
|
||||
onSubmitted: (_) => _submit(context),
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
contentPadding: EdgeInsets.fromLTRB(24, 20, 24, 0),
|
||||
contentPadding: EdgeInsets.only(top: 20),
|
||||
actions: [
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
|
@ -95,6 +95,8 @@ class _CreateAlbumDialogState extends State<CreateAlbumDialog> {
|
|||
child: Text('Create'.toUpperCase()),
|
||||
),
|
||||
],
|
||||
actionsPadding: Constants.dialogActionsPadding,
|
||||
shape: Constants.dialogShape,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'package:aves/model/image_entry.dart';
|
|||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/services/android_app_service.dart';
|
||||
import 'package:aves/services/image_file_service.dart';
|
||||
import 'package:aves/utils/constants.dart';
|
||||
import 'package:aves/widgets/common/action_delegates/feedback.dart';
|
||||
import 'package:aves/widgets/common/action_delegates/permission_aware.dart';
|
||||
import 'package:aves/widgets/common/action_delegates/rename_entry_dialog.dart';
|
||||
|
@ -131,6 +132,8 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin {
|
|||
child: Text('Delete'.toUpperCase()),
|
||||
),
|
||||
],
|
||||
actionsPadding: Constants.dialogActionsPadding,
|
||||
shape: Constants.dialogShape,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
import 'package:aves/model/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/utils/constants.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class GroupCollectionDialog extends StatefulWidget {
|
||||
@override
|
||||
_GroupCollectionDialogState createState() => _GroupCollectionDialogState();
|
||||
}
|
||||
|
||||
class _GroupCollectionDialogState extends State<GroupCollectionDialog> {
|
||||
GroupFactor _selectedGroup;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_selectedGroup = settings.collectionGroupFactor;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('Group'),
|
||||
content: ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
_buildRadioListTile(GroupFactor.album, 'By album'),
|
||||
_buildRadioListTile(GroupFactor.month, 'By month'),
|
||||
_buildRadioListTile(GroupFactor.day, 'By day'),
|
||||
_buildRadioListTile(GroupFactor.none, 'Do not group'),
|
||||
],
|
||||
),
|
||||
contentPadding: EdgeInsets.only(top: 20),
|
||||
actions: [
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text('Cancel'.toUpperCase()),
|
||||
),
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.pop(context, _selectedGroup),
|
||||
child: Text('Apply'.toUpperCase()),
|
||||
),
|
||||
],
|
||||
actionsPadding: Constants.dialogActionsPadding,
|
||||
shape: Constants.dialogShape,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRadioListTile(GroupFactor group, String title) => RadioListTile<GroupFactor>(
|
||||
value: group,
|
||||
groupValue: _selectedGroup,
|
||||
onChanged: (group) => setState(() => _selectedGroup = group),
|
||||
title: Text(
|
||||
title,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
),
|
||||
);
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:aves/model/image_entry.dart';
|
||||
import 'package:aves/services/android_file_service.dart';
|
||||
import 'package:aves/utils/constants.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
mixin PermissionAwareMixin {
|
||||
|
@ -35,6 +36,8 @@ mixin PermissionAwareMixin {
|
|||
child: Text('OK'.toUpperCase()),
|
||||
),
|
||||
],
|
||||
actionsPadding: Constants.dialogActionsPadding,
|
||||
shape: Constants.dialogShape,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:aves/model/image_entry.dart';
|
||||
import 'package:aves/utils/constants.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class RenameEntryDialog extends StatefulWidget {
|
||||
|
@ -43,6 +44,8 @@ class _RenameEntryDialogState extends State<RenameEntryDialog> {
|
|||
child: Text('Apply'.toUpperCase()),
|
||||
),
|
||||
],
|
||||
actionsPadding: Constants.dialogActionsPadding,
|
||||
shape: Constants.dialogShape,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'package:aves/model/source/collection_lens.dart';
|
|||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/services/android_app_service.dart';
|
||||
import 'package:aves/services/image_file_service.dart';
|
||||
import 'package:aves/utils/constants.dart';
|
||||
import 'package:aves/utils/durations.dart';
|
||||
import 'package:aves/widgets/album/app_bar.dart';
|
||||
import 'package:aves/widgets/album/empty.dart';
|
||||
|
@ -200,6 +201,8 @@ class SelectionActionDelegate with FeedbackMixin, PermissionAwareMixin {
|
|||
child: Text('Delete'.toUpperCase()),
|
||||
),
|
||||
],
|
||||
actionsPadding: Constants.dialogActionsPadding,
|
||||
shape: Constants.dialogShape,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import 'package:aves/model/settings.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/utils/constants.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class SortCollectionDialog extends StatefulWidget {
|
||||
@override
|
||||
_SortCollectionDialogState createState() => _SortCollectionDialogState();
|
||||
}
|
||||
|
||||
class _SortCollectionDialogState extends State<SortCollectionDialog> {
|
||||
SortFactor _selectedSort;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_selectedSort = settings.collectionSortFactor;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('Sort'),
|
||||
content: ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
_buildRadioListTile(SortFactor.date, 'By date'),
|
||||
_buildRadioListTile(SortFactor.size, 'By size'),
|
||||
_buildRadioListTile(SortFactor.name, 'By album & file name'),
|
||||
],
|
||||
),
|
||||
contentPadding: EdgeInsets.only(top: 20),
|
||||
actions: [
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text('Cancel'.toUpperCase()),
|
||||
),
|
||||
FlatButton(
|
||||
onPressed: () => Navigator.pop(context, _selectedSort),
|
||||
child: Text('Apply'.toUpperCase()),
|
||||
),
|
||||
],
|
||||
actionsPadding: Constants.dialogActionsPadding,
|
||||
shape: Constants.dialogShape,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRadioListTile(SortFactor sort, String title) => RadioListTile<SortFactor>(
|
||||
value: sort,
|
||||
groupValue: _selectedSort,
|
||||
onChanged: (sort) => setState(() => _selectedSort = sort),
|
||||
title: Text(
|
||||
title,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
),
|
||||
);
|
||||
}
|
|
@ -32,6 +32,7 @@ class AIcons {
|
|||
static const IconData favourite = OMIcons.favoriteBorder;
|
||||
static const IconData favouriteActive = OMIcons.favorite;
|
||||
static const IconData goUp = OMIcons.arrowUpward;
|
||||
static const IconData group = OMIcons.groupWork;
|
||||
static const IconData info = OMIcons.info;
|
||||
static const IconData openInNew = OMIcons.openInNew;
|
||||
static const IconData print = OMIcons.print;
|
||||
|
|
|
@ -11,7 +11,7 @@ description: A new Flutter application.
|
|||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 1.1.1+13
|
||||
version: 1.1.2+14
|
||||
|
||||
# video_player (as of v0.10.8+2, backed by ExoPlayer):
|
||||
# - does not support content URIs (by default, but trivial by fork)
|
||||
|
|
Loading…
Reference in a new issue