ente/lib/ui/collection_action_sheet.dart

282 lines
9.8 KiB
Dart
Raw Normal View History

import "dart:async";
import 'dart:math';
import 'package:collection/collection.dart';
2020-10-28 12:03:28 +00:00
import 'package:flutter/material.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
import "package:photos/core/configuration.dart";
2020-10-28 12:03:28 +00:00
import 'package:photos/models/collection.dart';
import 'package:photos/models/collection_items.dart';
import 'package:photos/models/selected_files.dart';
2020-10-28 12:03:28 +00:00
import 'package:photos/services/collections_service.dart';
import 'package:photos/theme/colors.dart';
import 'package:photos/theme/ente_theme.dart';
import "package:photos/ui/collections_list_widget.dart";
import 'package:photos/ui/common/loading_widget.dart';
import 'package:photos/ui/components/bottom_of_title_bar_widget.dart';
import 'package:photos/ui/components/button_widget.dart';
import 'package:photos/ui/components/models/button_type.dart';
2023-03-07 11:56:21 +00:00
import "package:photos/ui/components/text_input_widget.dart";
import 'package:photos/ui/components/title_bar_title_widget.dart';
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
2020-10-28 12:03:28 +00:00
enum CollectionActionType {
addFiles,
moveFiles,
restoreFiles,
unHide,
shareCollection,
collectPhotos,
}
String _actionName(CollectionActionType type, bool plural) {
bool addTitleSuffix = false;
final titleSuffix = (plural ? "s" : "");
String text = "";
switch (type) {
case CollectionActionType.addFiles:
text = "Add item";
addTitleSuffix = true;
break;
case CollectionActionType.moveFiles:
text = "Move item";
addTitleSuffix = true;
break;
case CollectionActionType.restoreFiles:
text = "Restore to album";
break;
2022-10-27 07:23:45 +00:00
case CollectionActionType.unHide:
text = "Unhide to album";
2022-10-27 07:23:45 +00:00
break;
case CollectionActionType.shareCollection:
text = "Share";
break;
case CollectionActionType.collectPhotos:
text = "Share";
break;
}
return addTitleSuffix ? text + titleSuffix : text;
}
2023-02-14 10:13:34 +00:00
void showCollectionActionSheet(
BuildContext context, {
SelectedFiles? selectedFiles,
List<SharedMediaFile>? sharedFiles,
CollectionActionType actionType = CollectionActionType.addFiles,
bool showOptionToCreateNewAlbum = true,
}) {
showBarModalBottomSheet(
context: context,
builder: (context) {
2023-02-14 10:13:34 +00:00
return CollectionActionSheet(
selectedFiles: selectedFiles,
sharedFiles: sharedFiles,
actionType: actionType,
showOptionToCreateNewAlbum: showOptionToCreateNewAlbum,
);
},
shape: const RoundedRectangleBorder(
side: BorderSide(width: 0),
2023-01-20 11:54:14 +00:00
borderRadius: BorderRadius.vertical(
top: Radius.circular(5),
),
),
topControl: const SizedBox.shrink(),
backgroundColor: getEnteColorScheme(context).backgroundElevated,
barrierColor: backdropFaintDark,
enableDrag: false,
);
}
2023-02-14 10:13:34 +00:00
class CollectionActionSheet extends StatefulWidget {
final SelectedFiles? selectedFiles;
final List<SharedMediaFile>? sharedFiles;
final CollectionActionType actionType;
final bool showOptionToCreateNewAlbum;
2023-02-14 10:13:34 +00:00
const CollectionActionSheet({
required this.selectedFiles,
required this.sharedFiles,
required this.actionType,
required this.showOptionToCreateNewAlbum,
super.key,
});
2020-10-28 12:03:28 +00:00
@override
2023-02-14 10:13:34 +00:00
State<CollectionActionSheet> createState() => _CollectionActionSheetState();
2020-10-28 12:03:28 +00:00
}
2023-02-14 10:13:34 +00:00
class _CollectionActionSheetState extends State<CollectionActionSheet> {
static const int cancelButtonSize = 80;
2023-03-07 11:56:21 +00:00
String _searchQuery = "";
2020-10-28 12:03:28 +00:00
@override
Widget build(BuildContext context) {
final filesCount = widget.sharedFiles != null
? widget.sharedFiles!.length
: widget.selectedFiles?.files.length ?? 0;
final bottomInset = MediaQuery.of(context).viewInsets.bottom;
final isKeyboardUp = bottomInset > 100;
return Padding(
padding: EdgeInsets.only(
bottom: isKeyboardUp ? bottomInset - cancelButtonSize : 0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ConstrainedBox(
constraints: BoxConstraints(
maxWidth: min(428, MediaQuery.of(context).size.width),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 32, 0, 8),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: Column(
children: [
BottomOfTitleBarWidget(
title: TitleBarTitleWidget(
title:
_actionName(widget.actionType, filesCount > 1),
),
caption: widget.showOptionToCreateNewAlbum
? "Create or select album"
: "Select album",
2023-03-07 11:56:21 +00:00
),
Padding(
padding: const EdgeInsets.only(
2023-03-07 12:43:41 +00:00
top: 16,
left: 16,
right: 16,
),
child: TextInputWidget(
hintText: "Album name",
prefixIcon: Icons.search_rounded,
autoFocus: true,
onChange: (value) {
2023-03-10 07:40:22 +00:00
value != _searchQuery
? setState(() {
_searchQuery = value;
})
: null;
},
cancellable: true,
shouldUnfocusOnCancelOrSubmit: true,
),
2023-03-07 11:56:21 +00:00
),
_getCollectionItems(filesCount),
],
),
),
SafeArea(
child: Container(
//inner stroke of 1pt + 15 pts of top padding = 16 pts
padding: const EdgeInsets.fromLTRB(16, 15, 16, 8),
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: getEnteColorScheme(context).strokeFaint,
),
2023-03-07 11:56:21 +00:00
),
),
child: const ButtonWidget(
buttonType: ButtonType.secondary,
buttonAction: ButtonAction.cancel,
isInAlert: true,
labelText: "Cancel",
),
2023-03-07 11:56:21 +00:00
),
)
],
),
),
),
],
),
);
}
Flexible _getCollectionItems(int filesCount) {
return Flexible(
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 24, 4, 0),
child: FutureBuilder(
future: _getCollectionsWithThumbnail(),
builder: (context, snapshot) {
if (snapshot.hasError) {
//Need to show an error on the UI here
return const SizedBox.shrink();
} else if (snapshot.hasData) {
final collectionsWithThumbnail =
snapshot.data as List<CollectionWithThumbnail>;
_removeIncomingCollections(collectionsWithThumbnail);
final shouldShowCreateAlbum =
widget.showOptionToCreateNewAlbum && _searchQuery.isEmpty;
final searchResults = _searchQuery.isNotEmpty
? collectionsWithThumbnail
.where(
(element) => element.collection.name!
.toLowerCase()
.contains(_searchQuery),
)
.toList()
: collectionsWithThumbnail;
return Scrollbar(
thumbVisibility: true,
radius: const Radius.circular(2),
child: Padding(
padding: const EdgeInsets.only(right: 12),
child: CollectionsListWidget(
searchResults,
widget.actionType,
widget.showOptionToCreateNewAlbum,
widget.selectedFiles,
widget.sharedFiles,
_searchQuery,
shouldShowCreateAlbum,
),
),
);
} else {
return const EnteLoadingWidget();
}
},
),
),
);
}
Future<List<CollectionWithThumbnail>> _getCollectionsWithThumbnail() async {
final List<CollectionWithThumbnail> collectionsWithThumbnail =
await CollectionsService.instance.getCollectionsWithThumbnails(
// in collections where user is a collaborator, only addTo and remove
// action can to be performed
includeCollabCollections:
widget.actionType == CollectionActionType.addFiles,
);
collectionsWithThumbnail.removeWhere(
(element) => (element.collection.type == CollectionType.favorites ||
element.collection.type == CollectionType.uncategorized ||
element.collection.isSharedFilesCollection()),
);
collectionsWithThumbnail.sort((first, second) {
return compareAsciiLowerCaseNatural(
first.collection.name ?? "",
second.collection.name ?? "",
);
});
return collectionsWithThumbnail;
}
void _removeIncomingCollections(List<CollectionWithThumbnail> items) {
if (widget.actionType == CollectionActionType.shareCollection ||
widget.actionType == CollectionActionType.collectPhotos) {
final ownerID = Configuration.instance.getUserID();
items.removeWhere(
(e) => !e.collection.isOwner(ownerID!),
);
}
}
2020-10-28 12:03:28 +00:00
}