Compare commits
1 Commits
remote_db
...
selection-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83bd3d5e76 |
@@ -5,6 +5,7 @@ import 'package:photos/models/selected_files.dart';
|
||||
import 'package:photos/theme/ente_theme.dart';
|
||||
|
||||
class ActionBarWidget extends StatefulWidget {
|
||||
final Color? backgroundColor;
|
||||
final SelectedFiles? selectedFiles;
|
||||
final VoidCallback? onCancel;
|
||||
|
||||
@@ -12,6 +13,7 @@ class ActionBarWidget extends StatefulWidget {
|
||||
required this.onCancel,
|
||||
this.selectedFiles,
|
||||
super.key,
|
||||
required this.backgroundColor,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -42,53 +44,57 @@ class _ActionBarWidgetState extends State<ActionBarWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final textTheme = getEnteTextTheme(context);
|
||||
return SizedBox(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 8, 20, 8),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: ValueListenableBuilder(
|
||||
valueListenable: _selectedFilesNotifier,
|
||||
builder: (context, value, child) {
|
||||
return Text(
|
||||
_selectedOwnedFilesNotifier.value !=
|
||||
_selectedFilesNotifier.value
|
||||
? S.of(context).selectedPhotosWithYours(
|
||||
_selectedFilesNotifier.value,
|
||||
_selectedOwnedFilesNotifier.value,
|
||||
)
|
||||
: S.of(context).selectedPhotos(
|
||||
_selectedFilesNotifier.value,
|
||||
),
|
||||
style: textTheme.miniMuted,
|
||||
);
|
||||
},
|
||||
final colorScheme = getEnteColorScheme(context);
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: widget.backgroundColor ?? colorScheme.backgroundElevated2,
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, -1),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ValueListenableBuilder(
|
||||
valueListenable: _selectedFilesNotifier,
|
||||
builder: (context, value, child) {
|
||||
return Text(
|
||||
_selectedOwnedFilesNotifier.value !=
|
||||
_selectedFilesNotifier.value
|
||||
? S.of(context).selectedPhotosWithYours(
|
||||
_selectedFilesNotifier.value,
|
||||
_selectedOwnedFilesNotifier.value,
|
||||
)
|
||||
: S.of(context).selectedPhotos(
|
||||
_selectedFilesNotifier.value,
|
||||
),
|
||||
style: textTheme.mini,
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () {
|
||||
widget.onCancel?.call();
|
||||
},
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Icon(
|
||||
Icons.close,
|
||||
size: 16,
|
||||
color: textTheme.mini.color,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () {
|
||||
widget.onCancel?.call();
|
||||
},
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Text(
|
||||
S.of(context).cancel,
|
||||
style: textTheme.mini,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import "package:photos/models/gallery_type.dart";
|
||||
import "package:photos/models/ml/face/person.dart";
|
||||
import 'package:photos/models/selected_files.dart';
|
||||
import 'package:photos/theme/ente_theme.dart';
|
||||
import 'package:photos/ui/components/bottom_action_bar/action_bar_widget.dart';
|
||||
import "package:photos/ui/components/divider_widget.dart";
|
||||
import "package:photos/ui/viewer/actions/file_selection_actions_widget.dart";
|
||||
|
||||
class BottomActionBarWidget extends StatelessWidget {
|
||||
@@ -16,7 +14,6 @@ class BottomActionBarWidget extends StatelessWidget {
|
||||
final String? clusterID;
|
||||
final SelectedFiles selectedFiles;
|
||||
final VoidCallback? onCancel;
|
||||
final Color? backgroundColor;
|
||||
|
||||
const BottomActionBarWidget({
|
||||
required this.galleryType,
|
||||
@@ -25,7 +22,6 @@ class BottomActionBarWidget extends StatelessWidget {
|
||||
this.person,
|
||||
this.clusterID,
|
||||
this.onCancel,
|
||||
this.backgroundColor,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@@ -39,10 +35,10 @@ class BottomActionBarWidget extends StatelessWidget {
|
||||
: 0;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor ?? colorScheme.backgroundElevated2,
|
||||
color: colorScheme.backgroundElevated,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(8),
|
||||
topRight: Radius.circular(8),
|
||||
topLeft: Radius.circular(24),
|
||||
topRight: Radius.circular(24),
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.only(
|
||||
@@ -62,12 +58,7 @@ class BottomActionBarWidget extends StatelessWidget {
|
||||
person: person,
|
||||
clusterID: clusterID,
|
||||
),
|
||||
const DividerWidget(dividerType: DividerType.bottomBar),
|
||||
ActionBarWidget(
|
||||
selectedFiles: selectedFiles,
|
||||
onCancel: onCancel,
|
||||
),
|
||||
// const SizedBox(height: 2)
|
||||
const SizedBox(height: 2),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import "package:auto_size_text/auto_size_text.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter_svg/svg.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
@@ -106,7 +107,7 @@ class __BodyState extends State<_Body> {
|
||||
children: [
|
||||
if (widget.icon == Icons.navigation_rounded)
|
||||
Transform.rotate(
|
||||
angle: math.pi / 2,
|
||||
angle: math.pi * 2,
|
||||
child: Icon(
|
||||
widget.icon,
|
||||
size: 24,
|
||||
@@ -137,7 +138,7 @@ class __BodyState extends State<_Body> {
|
||||
SvgPicture.asset(
|
||||
widget.svgAssetPath!,
|
||||
colorFilter: ColorFilter.mode(
|
||||
getEnteColorScheme(context).textMuted,
|
||||
getEnteColorScheme(context).textBase,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
width: 24,
|
||||
@@ -149,14 +150,16 @@ class __BodyState extends State<_Body> {
|
||||
Icon(
|
||||
widget.icon,
|
||||
size: 24,
|
||||
color: getEnteColorScheme(context).textMuted,
|
||||
color: getEnteColorScheme(context).textBase,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
widget.labelText,
|
||||
textAlign: TextAlign.center,
|
||||
//textTheme in [getWidthOfLongestWord] should be same as this
|
||||
style: getEnteTextTheme(context).miniMuted,
|
||||
Flexible(
|
||||
child: AutoSizeText(
|
||||
widget.labelText,
|
||||
textAlign: TextAlign.center,
|
||||
//textTheme in [getWidthOfLongestWord] should be same as this
|
||||
style: getEnteTextTheme(context).mini,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -180,8 +183,7 @@ class __BodyState extends State<_Body> {
|
||||
|
||||
double maxWidth = 0.0;
|
||||
for (String word in words) {
|
||||
final width =
|
||||
computeWidthOfWord(word, getEnteTextTheme(context).miniMuted);
|
||||
final width = computeWidthOfWord(word, getEnteTextTheme(context).mini);
|
||||
if (width > maxWidth) {
|
||||
maxWidth = width;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import 'package:photos/utils/navigation_util.dart';
|
||||
import "package:photos/utils/share_util.dart";
|
||||
import "package:photos/utils/standalone/simple_task_queue.dart";
|
||||
import "package:screenshot/screenshot.dart";
|
||||
import "package:smooth_page_indicator/smooth_page_indicator.dart";
|
||||
|
||||
class FileSelectionActionsWidget extends StatefulWidget {
|
||||
final GalleryType type;
|
||||
@@ -89,6 +90,7 @@ class _FileSelectionActionsWidgetState
|
||||
Collection? _cachedCollectionForSharedLink;
|
||||
final GlobalKey shareButtonKey = GlobalKey();
|
||||
final GlobalKey sendLinkButtonKey = GlobalKey();
|
||||
final PageController _pageController = PageController();
|
||||
final StreamController<double> _progressController =
|
||||
StreamController<double>();
|
||||
|
||||
@@ -153,6 +155,31 @@ class _FileSelectionActionsWidgetState
|
||||
//for items that should be shown.
|
||||
final List<SelectionActionButton> items = [];
|
||||
|
||||
final showUploadIcon = widget.type == GalleryType.localFolder &&
|
||||
split.ownedByCurrentUser.isEmpty;
|
||||
|
||||
//add to album
|
||||
if (widget.type.showAddToAlbum()) {
|
||||
if (showUploadIcon) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.cloud_upload_outlined,
|
||||
labelText: S.of(context).addToEnte,
|
||||
onTap: _addToAlbum,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.add_outlined,
|
||||
labelText: S.of(context).addToAlbum,
|
||||
onTap: _addToAlbum,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//share link
|
||||
if (widget.type.showCreateLink()) {
|
||||
if (_cachedCollectionForSharedLink != null && anyUploadedFiles) {
|
||||
items.add(
|
||||
@@ -166,7 +193,7 @@ class _FileSelectionActionsWidgetState
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.navigation_rounded,
|
||||
labelText: S.of(context).sendLink,
|
||||
labelText: S.of(context).share,
|
||||
onTap: anyUploadedFiles ? _onSendLinkTapped : null,
|
||||
shouldShow: ownedFilesCount > 0,
|
||||
key: sendLinkButtonKey,
|
||||
@@ -174,6 +201,150 @@ class _FileSelectionActionsWidgetState
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//Favorite
|
||||
if (widget.type.showFavoriteOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.favorite_border_rounded,
|
||||
labelText: S.of(context).favorite,
|
||||
onTap: anyUploadedFiles ? _onFavoriteClick : null,
|
||||
shouldShow: ownedFilesCount > 0,
|
||||
),
|
||||
);
|
||||
} else if (widget.type.showUnFavoriteOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.favorite,
|
||||
labelText: S.of(context).removeFromFavorite,
|
||||
onTap: _onUnFavoriteClick,
|
||||
shouldShow: ownedFilesCount > 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
//Download
|
||||
if (showDownloadOption) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
labelText: S.of(context).download,
|
||||
icon: Icons.cloud_download_outlined,
|
||||
onTap: () => _download(widget.selectedFiles.files.toList()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
//Delete (for owned photos only)
|
||||
if (widget.type.showDeleteOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.delete_outline,
|
||||
labelText: S.of(context).delete,
|
||||
onTap: anyOwnedFiles ? _onDeleteClick : null,
|
||||
shouldShow: allOwnedFiles,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
//Hide (for owned photos only)
|
||||
if (widget.type.showHideOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.visibility_off_outlined,
|
||||
labelText: S.of(context).hide,
|
||||
onTap: anyUploadedFiles ? _onHideClick : null,
|
||||
shouldShow: ownedFilesCount > 0,
|
||||
),
|
||||
);
|
||||
} else if (widget.type.showUnHideOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.visibility_outlined,
|
||||
labelText: S.of(context).unhide,
|
||||
onTap: _onUnhideClick,
|
||||
shouldShow: ownedFilesCount > 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
//Archive (for owned photos only)
|
||||
if (widget.type.showArchiveOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.archive_outlined,
|
||||
labelText: S.of(context).archive,
|
||||
onTap: anyUploadedFiles ? _onArchiveClick : null,
|
||||
shouldShow: ownedFilesCount > 0,
|
||||
),
|
||||
);
|
||||
} else if (widget.type.showUnArchiveOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.unarchive,
|
||||
labelText: S.of(context).unarchive,
|
||||
onTap: _onUnArchiveClick,
|
||||
shouldShow: ownedFilesCount > 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
//Guest view
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
svgAssetPath: "assets/icons/guest_view_icon.svg",
|
||||
labelText: S.of(context).guestView,
|
||||
onTap: _onGuestViewClick,
|
||||
),
|
||||
);
|
||||
|
||||
//Create collage
|
||||
if (widget.type != GalleryType.sharedPublicCollection) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.grid_view_outlined,
|
||||
labelText: S.of(context).createCollage,
|
||||
onTap: _onCreateCollageClicked,
|
||||
shouldShow: showCollageOption,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
//Edit (only if single photo is selected)
|
||||
if (widget.type.showBulkEditTime()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
shouldShow: widget.selectedFiles.files.every(
|
||||
(element) => (element.ownerID == currentUserID),
|
||||
),
|
||||
labelText: S.of(context).editTime,
|
||||
icon: Icons.edit_calendar_outlined,
|
||||
onTap: () async {
|
||||
final newDate = await showEditDateSheet(
|
||||
context,
|
||||
widget.selectedFiles.files,
|
||||
);
|
||||
if (newDate != null) {
|
||||
widget.selectedFiles.clearAll();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
//Edit location (for owned photos only)
|
||||
if (widget.type.showEditLocation()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
shouldShow: widget.selectedFiles.files.any(
|
||||
(element) => (element.ownerID == currentUserID),
|
||||
),
|
||||
labelText: S.of(context).editLocation,
|
||||
icon: Icons.edit_location_alt_outlined,
|
||||
onTap: _editLocation,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.type == GalleryType.peopleTag && widget.person != null) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
@@ -203,28 +374,6 @@ class _FileSelectionActionsWidgetState
|
||||
);
|
||||
}
|
||||
|
||||
final showUploadIcon = widget.type == GalleryType.localFolder &&
|
||||
split.ownedByCurrentUser.isEmpty;
|
||||
if (widget.type.showAddToAlbum()) {
|
||||
if (showUploadIcon) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.cloud_upload_outlined,
|
||||
labelText: S.of(context).addToEnte,
|
||||
onTap: _addToAlbum,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.add_outlined,
|
||||
labelText: S.of(context).addToAlbum,
|
||||
onTap: _addToAlbum,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (widget.type.showAddtoHiddenAlbum()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
@@ -256,17 +405,6 @@ class _FileSelectionActionsWidgetState
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.type.showDeleteOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.delete_outline,
|
||||
labelText: S.of(context).delete,
|
||||
onTap: anyOwnedFiles ? _onDeleteClick : null,
|
||||
shouldShow: allOwnedFiles,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.type.showRemoveFromAlbum()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
@@ -288,42 +426,6 @@ class _FileSelectionActionsWidgetState
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.type.showFavoriteOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.favorite_border_rounded,
|
||||
labelText: S.of(context).favorite,
|
||||
onTap: anyUploadedFiles ? _onFavoriteClick : null,
|
||||
shouldShow: ownedFilesCount > 0,
|
||||
),
|
||||
);
|
||||
} else if (widget.type.showUnFavoriteOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.favorite,
|
||||
labelText: S.of(context).removeFromFavorite,
|
||||
onTap: _onUnFavoriteClick,
|
||||
shouldShow: ownedFilesCount > 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
svgAssetPath: "assets/icons/guest_view_icon.svg",
|
||||
labelText: S.of(context).guestView,
|
||||
onTap: _onGuestViewClick,
|
||||
),
|
||||
);
|
||||
if (widget.type != GalleryType.sharedPublicCollection) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.grid_view_outlined,
|
||||
labelText: S.of(context).createCollage,
|
||||
onTap: _onCreateCollageClicked,
|
||||
shouldShow: showCollageOption,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (flagService.internalUser &&
|
||||
widget.type != GalleryType.sharedPublicCollection) {
|
||||
items.add(
|
||||
@@ -335,45 +437,6 @@ class _FileSelectionActionsWidgetState
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.type.showHideOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.visibility_off_outlined,
|
||||
labelText: S.of(context).hide,
|
||||
onTap: anyUploadedFiles ? _onHideClick : null,
|
||||
shouldShow: ownedFilesCount > 0,
|
||||
),
|
||||
);
|
||||
} else if (widget.type.showUnHideOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.visibility_outlined,
|
||||
labelText: S.of(context).unhide,
|
||||
onTap: _onUnhideClick,
|
||||
shouldShow: ownedFilesCount > 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (widget.type.showArchiveOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.archive_outlined,
|
||||
labelText: S.of(context).archive,
|
||||
onTap: anyUploadedFiles ? _onArchiveClick : null,
|
||||
shouldShow: ownedFilesCount > 0,
|
||||
),
|
||||
);
|
||||
} else if (widget.type.showUnArchiveOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
icon: Icons.unarchive,
|
||||
labelText: S.of(context).unarchive,
|
||||
onTap: _onUnArchiveClick,
|
||||
shouldShow: ownedFilesCount > 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.type.showRestoreOption()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
@@ -394,49 +457,6 @@ class _FileSelectionActionsWidgetState
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.type.showBulkEditTime()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
shouldShow: widget.selectedFiles.files.every(
|
||||
(element) => (element.ownerID == currentUserID),
|
||||
),
|
||||
labelText: S.of(context).editTime,
|
||||
icon: Icons.edit_calendar_outlined,
|
||||
onTap: () async {
|
||||
final newDate = await showEditDateSheet(
|
||||
context,
|
||||
widget.selectedFiles.files,
|
||||
);
|
||||
if (newDate != null) {
|
||||
widget.selectedFiles.clearAll();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.type.showEditLocation()) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
shouldShow: widget.selectedFiles.files.any(
|
||||
(element) => (element.ownerID == currentUserID),
|
||||
),
|
||||
labelText: S.of(context).editLocation,
|
||||
icon: Icons.edit_location_alt_outlined,
|
||||
onTap: _editLocation,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (showDownloadOption) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
labelText: S.of(context).download,
|
||||
icon: Icons.cloud_download_outlined,
|
||||
onTap: () => _download(widget.selectedFiles.files.toList()),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (widget.type != GalleryType.sharedPublicCollection) {
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
@@ -448,38 +468,147 @@ class _FileSelectionActionsWidgetState
|
||||
);
|
||||
}
|
||||
|
||||
if (items.isNotEmpty) {
|
||||
final scrollController = ScrollController();
|
||||
// h4ck: https://github.com/flutter/flutter/issues/57920#issuecomment-893970066
|
||||
// Filter items that should be shown first
|
||||
final List<SelectionActionButton> visibleItems = items
|
||||
.where((item) => item.shouldShow == null || item.shouldShow == true)
|
||||
.toList();
|
||||
|
||||
final List<SelectionActionButton> firstThreeItems =
|
||||
visibleItems.length > 3 ? visibleItems.take(3).toList() : visibleItems;
|
||||
|
||||
final List<SelectionActionButton> otherItems =
|
||||
visibleItems.length > 3 ? visibleItems.sublist(3) : [];
|
||||
|
||||
final List<List<SelectionActionButton>> groupedOtherItems = [];
|
||||
for (int i = 0; i < otherItems.length; i += 4) {
|
||||
int end = (i + 4 < otherItems.length) ? i + 4 : otherItems.length;
|
||||
groupedOtherItems.add(otherItems.sublist(i, end));
|
||||
}
|
||||
|
||||
if (visibleItems.isNotEmpty) {
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).removePadding(removeBottom: true),
|
||||
child: SafeArea(
|
||||
child: Scrollbar(
|
||||
radius: const Radius.circular(1),
|
||||
thickness: 2,
|
||||
controller: scrollController,
|
||||
thumbVisibility: true,
|
||||
child: SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(
|
||||
decelerationRate: ScrollDecelerationRate.fast,
|
||||
),
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(bottom: 24),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(width: 4),
|
||||
...items,
|
||||
const SizedBox(width: 4),
|
||||
],
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(bottom: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
// First Row
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
),
|
||||
child: Row(
|
||||
children: firstThreeItems
|
||||
.map(
|
||||
(item) => Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height *
|
||||
0.10,
|
||||
decoration: BoxDecoration(
|
||||
color: getEnteColorScheme(context)
|
||||
.backgroundElevated2,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
),
|
||||
item,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
|
||||
// Second Row
|
||||
if (groupedOtherItems.isNotEmpty) ...[
|
||||
const SizedBox(height: 24),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 74,
|
||||
decoration: BoxDecoration(
|
||||
color: getEnteColorScheme(context).backgroundElevated2,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: PageView.builder(
|
||||
controller: _pageController,
|
||||
itemCount: groupedOtherItems.length,
|
||||
onPageChanged: (index) {
|
||||
if (index >= groupedOtherItems.length &&
|
||||
groupedOtherItems.isNotEmpty) {
|
||||
_pageController.animateToPage(
|
||||
groupedOtherItems.length - 1,
|
||||
duration: const Duration(seconds: 5),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
}
|
||||
},
|
||||
itemBuilder: (context, pageIndex) {
|
||||
if (pageIndex >= groupedOtherItems.length) {
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
final currentGroup = groupedOtherItems[pageIndex];
|
||||
|
||||
return Row(
|
||||
children: currentGroup.map((item) {
|
||||
return Expanded(
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(seconds: 5),
|
||||
transitionBuilder: (
|
||||
Widget child,
|
||||
Animation<double> animation,
|
||||
) {
|
||||
return FadeTransition(
|
||||
opacity: animation,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: item is Widget
|
||||
? KeyedSubtree(
|
||||
key: ValueKey(item.hashCode),
|
||||
child: item,
|
||||
)
|
||||
: const SizedBox(),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (groupedOtherItems.length > 1)
|
||||
SmoothPageIndicator(
|
||||
controller: _pageController,
|
||||
count: groupedOtherItems.length,
|
||||
effect: const WormEffect(
|
||||
dotHeight: 6,
|
||||
dotWidth: 6,
|
||||
spacing: 6,
|
||||
activeDotColor: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
@@ -495,7 +624,6 @@ class _FileSelectionActionsWidgetState
|
||||
topControl: Stack(
|
||||
alignment: Alignment.bottomCenter,
|
||||
children: [
|
||||
// This container is for increasing the tap area
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 36,
|
||||
|
||||
@@ -11,6 +11,7 @@ import "package:photos/models/search/hierarchical/only_them_filter.dart";
|
||||
import 'package:photos/models/selected_files.dart';
|
||||
import "package:photos/theme/effects.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/components/bottom_action_bar/action_bar_widget.dart";
|
||||
import 'package:photos/ui/components/bottom_action_bar/bottom_action_bar_widget.dart';
|
||||
import "package:photos/ui/viewer/gallery/state/gallery_files_inherited_widget.dart";
|
||||
import "package:photos/ui/viewer/gallery/state/inherited_search_filter_data.dart";
|
||||
@@ -25,6 +26,7 @@ class FileSelectionOverlayBar extends StatefulWidget {
|
||||
final Color? backgroundColor;
|
||||
final PersonEntity? person;
|
||||
final String? clusterID;
|
||||
final VoidCallback? onCancel;
|
||||
|
||||
const FileSelectionOverlayBar(
|
||||
this.galleryType,
|
||||
@@ -33,6 +35,7 @@ class FileSelectionOverlayBar extends StatefulWidget {
|
||||
this.backgroundColor,
|
||||
this.person,
|
||||
this.clusterID,
|
||||
this.onCancel,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@@ -127,13 +130,30 @@ class _FileSelectionOverlayBarState extends State<FileSelectionOverlayBar> {
|
||||
duration: const Duration(milliseconds: 400),
|
||||
firstChild: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 4),
|
||||
child: SelectAllButton(
|
||||
backgroundColor: widget.backgroundColor,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
child: SelectAllButton(
|
||||
backgroundColor: widget.backgroundColor,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
child: ActionBarWidget(
|
||||
selectedFiles: widget.selectedFiles,
|
||||
onCancel: () {
|
||||
if (widget.selectedFiles.files.isNotEmpty) {
|
||||
widget.selectedFiles.clearAll();
|
||||
}
|
||||
},
|
||||
backgroundColor: widget.backgroundColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
@@ -151,7 +171,6 @@ class _FileSelectionOverlayBarState extends State<FileSelectionOverlayBar> {
|
||||
widget.selectedFiles.clearAll();
|
||||
}
|
||||
},
|
||||
backgroundColor: widget.backgroundColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -247,50 +266,47 @@ class _SelectAllButtonState extends State<SelectAllButton> {
|
||||
_allSelected = !_allSelected;
|
||||
});
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: widget.backgroundColor ?? colorScheme.backgroundElevated2,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, -1),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
S.of(context).selectAllShort,
|
||||
style: getEnteTextTheme(context).miniMuted,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
ListenableBuilder(
|
||||
listenable: selectionState!.selectedFiles,
|
||||
builder: (context, _) {
|
||||
if (selectionState.selectedFiles.files.length ==
|
||||
allGalleryFiles.length) {
|
||||
_allSelected = true;
|
||||
} else {
|
||||
_allSelected = false;
|
||||
}
|
||||
return Icon(
|
||||
_allSelected
|
||||
? Icons.check_circle
|
||||
: Icons.check_circle_outline,
|
||||
color: _allSelected ? null : colorScheme.strokeMuted,
|
||||
size: 18,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: widget.backgroundColor ?? colorScheme.backgroundElevated2,
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, -1),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
S.of(context).selectAll,
|
||||
style: getEnteTextTheme(context).mini,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
ListenableBuilder(
|
||||
listenable: selectionState!.selectedFiles,
|
||||
builder: (context, _) {
|
||||
if (selectionState.selectedFiles.files.length ==
|
||||
allGalleryFiles.length) {
|
||||
_allSelected = true;
|
||||
} else {
|
||||
_allSelected = false;
|
||||
}
|
||||
return Icon(
|
||||
_allSelected
|
||||
? Icons.check_circle
|
||||
: Icons.check_circle_outline,
|
||||
color: _allSelected ? null : colorScheme.strokeBase,
|
||||
size: 16,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -5,10 +5,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
|
||||
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "76.0.0"
|
||||
version: "72.0.0"
|
||||
_flutterfire_internals:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -21,7 +21,7 @@ packages:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
source: sdk
|
||||
version: "0.3.3"
|
||||
version: "0.3.2"
|
||||
adaptive_theme:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -34,10 +34,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
|
||||
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.11.0"
|
||||
version: "6.7.0"
|
||||
android_intent_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -134,6 +134,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
auto_size_text:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: auto_size_text
|
||||
sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
battery_info:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -317,10 +325,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: collection
|
||||
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
|
||||
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.19.0"
|
||||
version: "1.18.0"
|
||||
computer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1392,18 +1400,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
|
||||
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.7"
|
||||
version: "10.0.5"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
|
||||
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.8"
|
||||
version: "3.0.5"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1512,10 +1520,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: macros
|
||||
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
|
||||
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.3-main.0"
|
||||
version: "0.1.2-main.4"
|
||||
maps_launcher:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2293,7 +2301,15 @@ packages:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
version: "0.0.99"
|
||||
smooth_page_indicator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: smooth_page_indicator
|
||||
sha256: b21ebb8bc39cf72d11c7cfd809162a48c3800668ced1c9da3aade13a32cf6c1c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2418,10 +2434,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
|
||||
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.12.0"
|
||||
version: "1.11.1"
|
||||
step_progress_indicator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2450,10 +2466,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
|
||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.2.0"
|
||||
styled_text:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2514,26 +2530,26 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: test
|
||||
sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f"
|
||||
sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.25.8"
|
||||
version: "1.25.7"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
|
||||
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.3"
|
||||
version: "0.7.2"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d"
|
||||
sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.5"
|
||||
version: "0.6.4"
|
||||
thermal:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2813,10 +2829,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
|
||||
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.3.0"
|
||||
version: "14.2.5"
|
||||
volume_controller:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2877,10 +2893,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webdriver
|
||||
sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8"
|
||||
sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.4"
|
||||
version: "3.0.3"
|
||||
webkit_inspection_protocol:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -25,6 +25,7 @@ dependencies:
|
||||
app_links: ^6.4.0
|
||||
archive: ^3.6.1
|
||||
async: ^2.11.0
|
||||
auto_size_text: ^3.0.0
|
||||
battery_info: # replace with battery_plus
|
||||
git:
|
||||
url: https://github.com/ente-io/battery_info
|
||||
@@ -184,6 +185,7 @@ dependencies:
|
||||
sentry_flutter: ^8.14.1
|
||||
share_plus: ^10.0.2
|
||||
shared_preferences: ^2.0.5
|
||||
smooth_page_indicator: ^1.2.1
|
||||
sqflite: ^2.3.0
|
||||
sqflite_migration: ^0.3.0
|
||||
sqlite3_flutter_libs: ^0.5.20
|
||||
|
||||
Reference in New Issue
Block a user