Merge branch 'album_UI_revamp' of https://github.com/ente-io/auth into album_UI_revamp
This commit is contained in:
@@ -390,6 +390,7 @@ class CollectionsService {
|
||||
|
||||
Future<SharedCollections> getSharedCollections() async {
|
||||
final AlbumSortKey sortKey = localSettings.albumSortKey();
|
||||
final AlbumSortDirection sortDirection = localSettings.albumSortDirection();
|
||||
final List<Collection> outgoing = [];
|
||||
final List<Collection> incoming = [];
|
||||
final List<Collection> quickLinks = [];
|
||||
@@ -406,9 +407,6 @@ class CollectionsService {
|
||||
incoming.add(c);
|
||||
}
|
||||
}
|
||||
incoming.sort((first, second) {
|
||||
return second.updationTime.compareTo(first.updationTime);
|
||||
});
|
||||
|
||||
late Map<int, int> collectionIDToNewestPhotoTime;
|
||||
if (sortKey == AlbumSortKey.newestPhoto) {
|
||||
@@ -418,37 +416,47 @@ class CollectionsService {
|
||||
|
||||
incoming.sort(
|
||||
(first, second) {
|
||||
int comparison;
|
||||
if (sortKey == AlbumSortKey.albumName) {
|
||||
return compareAsciiLowerCaseNatural(
|
||||
comparison = compareAsciiLowerCaseNatural(
|
||||
first.displayName,
|
||||
second.displayName,
|
||||
);
|
||||
} else if (sortKey == AlbumSortKey.newestPhoto) {
|
||||
return (collectionIDToNewestPhotoTime[second.id] ?? -1 * intMaxValue)
|
||||
.compareTo(
|
||||
comparison =
|
||||
(collectionIDToNewestPhotoTime[second.id] ?? -1 * intMaxValue)
|
||||
.compareTo(
|
||||
collectionIDToNewestPhotoTime[first.id] ?? -1 * intMaxValue,
|
||||
);
|
||||
} else {
|
||||
return second.updationTime.compareTo(first.updationTime);
|
||||
comparison = second.updationTime.compareTo(first.updationTime);
|
||||
}
|
||||
return sortDirection == AlbumSortDirection.ascending
|
||||
? comparison
|
||||
: -comparison;
|
||||
},
|
||||
);
|
||||
|
||||
outgoing.sort(
|
||||
(first, second) {
|
||||
int comparison;
|
||||
if (sortKey == AlbumSortKey.albumName) {
|
||||
return compareAsciiLowerCaseNatural(
|
||||
comparison = compareAsciiLowerCaseNatural(
|
||||
first.displayName,
|
||||
second.displayName,
|
||||
);
|
||||
} else if (sortKey == AlbumSortKey.newestPhoto) {
|
||||
return (collectionIDToNewestPhotoTime[second.id] ?? -1 * intMaxValue)
|
||||
.compareTo(
|
||||
comparison =
|
||||
(collectionIDToNewestPhotoTime[second.id] ?? -1 * intMaxValue)
|
||||
.compareTo(
|
||||
collectionIDToNewestPhotoTime[first.id] ?? -1 * intMaxValue,
|
||||
);
|
||||
} else {
|
||||
return second.updationTime.compareTo(first.updationTime);
|
||||
comparison = second.updationTime.compareTo(first.updationTime);
|
||||
}
|
||||
return sortDirection == AlbumSortDirection.ascending
|
||||
? comparison
|
||||
: -comparison;
|
||||
},
|
||||
);
|
||||
|
||||
@@ -457,6 +465,7 @@ class CollectionsService {
|
||||
|
||||
Future<List<Collection>> getCollectionForOnEnteSection() async {
|
||||
final AlbumSortKey sortKey = localSettings.albumSortKey();
|
||||
final AlbumSortDirection sortDirection = localSettings.albumSortDirection();
|
||||
final List<Collection> collections =
|
||||
CollectionsService.instance.getCollectionsForUI();
|
||||
final bool hasFavorites = FavoritesService.instance.hasFavorites();
|
||||
@@ -467,19 +476,24 @@ class CollectionsService {
|
||||
}
|
||||
collections.sort(
|
||||
(first, second) {
|
||||
int comparison;
|
||||
if (sortKey == AlbumSortKey.albumName) {
|
||||
return compareAsciiLowerCaseNatural(
|
||||
comparison = compareAsciiLowerCaseNatural(
|
||||
first.displayName,
|
||||
second.displayName,
|
||||
);
|
||||
} else if (sortKey == AlbumSortKey.newestPhoto) {
|
||||
return (collectionIDToNewestPhotoTime[second.id] ?? -1 * intMaxValue)
|
||||
.compareTo(
|
||||
comparison =
|
||||
(collectionIDToNewestPhotoTime[second.id] ?? -1 * intMaxValue)
|
||||
.compareTo(
|
||||
collectionIDToNewestPhotoTime[first.id] ?? -1 * intMaxValue,
|
||||
);
|
||||
} else {
|
||||
return second.updationTime.compareTo(first.updationTime);
|
||||
comparison = second.updationTime.compareTo(first.updationTime);
|
||||
}
|
||||
return sortDirection == AlbumSortDirection.ascending
|
||||
? comparison
|
||||
: -comparison;
|
||||
},
|
||||
);
|
||||
final List<Collection> favorites = [];
|
||||
|
||||
@@ -27,10 +27,8 @@ import 'package:photos/ui/components/dialog_widget.dart';
|
||||
import 'package:photos/ui/components/models/button_type.dart';
|
||||
import 'package:photos/ui/notification/toast.dart';
|
||||
import 'package:photos/ui/payment/subscription.dart';
|
||||
import "package:photos/ui/sharing/add_participant_page.dart";
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/email_util.dart';
|
||||
import "package:photos/utils/navigation_util.dart";
|
||||
import 'package:photos/utils/share_util.dart';
|
||||
import 'package:photos/utils/standalone/date_time.dart';
|
||||
import "package:styled_text/styled_text.dart";
|
||||
@@ -335,72 +333,6 @@ class CollectionActions {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> shareMultipleCollectionSheet(
|
||||
BuildContext bContext,
|
||||
List<Collection> collection,
|
||||
) async {
|
||||
final textTheme = getEnteTextTheme(bContext);
|
||||
final actionResult = await showActionSheet(
|
||||
context: bContext,
|
||||
buttons: [
|
||||
ButtonWidget(
|
||||
labelText: S.of(bContext).addViewer,
|
||||
buttonType: ButtonType.primary,
|
||||
buttonSize: ButtonSize.large,
|
||||
buttonAction: ButtonAction.first,
|
||||
shouldStickToDarkTheme: true,
|
||||
isInAlert: true,
|
||||
onTap: () async {
|
||||
await routeToPage(
|
||||
bContext,
|
||||
AddParticipantPage(collection[0], true),
|
||||
);
|
||||
},
|
||||
),
|
||||
ButtonWidget(
|
||||
labelText: S.of(bContext).addCollaborator,
|
||||
buttonType: ButtonType.neutral,
|
||||
buttonSize: ButtonSize.large,
|
||||
buttonAction: ButtonAction.second,
|
||||
shouldStickToDarkTheme: true,
|
||||
isInAlert: true,
|
||||
onTap: () async {
|
||||
await routeToPage(
|
||||
bContext,
|
||||
AddParticipantPage(collection[0], false),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
bodyWidget: StyledText(
|
||||
text:
|
||||
"<bold>Share ${collection.length} ${collection.length == 1 ? 'album' : 'albums'}</bold>",
|
||||
style: textTheme.body.copyWith(color: textMutedDark),
|
||||
tags: {
|
||||
'bold': StyledTextTag(
|
||||
style: textTheme.body.copyWith(color: textBaseDark),
|
||||
),
|
||||
},
|
||||
),
|
||||
actionSheetType: ActionSheetType.defaultActionSheet,
|
||||
);
|
||||
|
||||
if (actionResult?.action != null &&
|
||||
actionResult!.action == ButtonAction.error) {
|
||||
await showGenericErrorDialog(
|
||||
context: bContext,
|
||||
error: actionResult.exception,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if ((actionResult?.action != null) &&
|
||||
(actionResult!.action == ButtonAction.first ||
|
||||
actionResult.action == ButtonAction.second)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<bool> deleteMultipleCollectionSheet(
|
||||
BuildContext bContext,
|
||||
List<Collection> collections,
|
||||
|
||||
@@ -30,7 +30,6 @@ class AlbumListItemWidget extends StatelessWidget {
|
||||
final textTheme = getEnteTextTheme(context);
|
||||
final colorScheme = getEnteColorScheme(context);
|
||||
const sideOfThumbnail = 60.0;
|
||||
final bool isFavCollection = collection.type == CollectionType.favorites;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
@@ -54,7 +53,7 @@ class AlbumListItemWidget extends StatelessWidget {
|
||||
duration: const Duration(milliseconds: 200),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: isSelected & !isFavCollection
|
||||
color: isSelected
|
||||
? colorScheme.strokeMuted
|
||||
: colorScheme.strokeFainter,
|
||||
),
|
||||
@@ -153,17 +152,18 @@ class AlbumListItemWidget extends StatelessWidget {
|
||||
duration: const Duration(milliseconds: 200),
|
||||
switchInCurve: Curves.easeOut,
|
||||
switchOutCurve: Curves.easeIn,
|
||||
child: isSelected & !isFavCollection
|
||||
child: isSelected
|
||||
? IconButtonWidget(
|
||||
key: const ValueKey("selected"),
|
||||
icon: Icons.check_circle_rounded,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
iconColor: colorScheme.blurStrokeBase,
|
||||
)
|
||||
: const IconButtonWidget(
|
||||
key: ValueKey("unselected"),
|
||||
: IconButtonWidget(
|
||||
key: const ValueKey("unselected"),
|
||||
icon: Icons.chevron_right_outlined,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
iconColor: colorScheme.blurStrokePressed,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -73,13 +73,13 @@ class NewAlbumRowItemWidget extends StatelessWidget {
|
||||
dashPattern: const [3.75, 3.75],
|
||||
radius: const Radius.circular(2.35),
|
||||
padding: EdgeInsets.zero,
|
||||
color: enteColorScheme.strokeFaint,
|
||||
color: enteColorScheme.blurStrokePressed,
|
||||
child: SizedBox(
|
||||
height: height,
|
||||
width: width,
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: enteColorScheme.strokeFaint,
|
||||
color: enteColorScheme.blurStrokePressed,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -8,7 +8,6 @@ import "package:photos/models/selected_albums.dart";
|
||||
import "package:photos/services/collections_service.dart";
|
||||
import "package:photos/theme/colors.dart";
|
||||
import 'package:photos/theme/ente_theme.dart';
|
||||
import "package:photos/ui/components/buttons/icon_button_widget.dart";
|
||||
import "package:photos/ui/sharing/album_share_info_widget.dart";
|
||||
import "package:photos/ui/sharing/user_avator_widget.dart";
|
||||
import 'package:photos/ui/viewer/file/no_thumbnail_widget.dart';
|
||||
@@ -40,7 +39,6 @@ class AlbumRowItemWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = getEnteColorScheme(context);
|
||||
final bool isOwner = c.isOwner(Configuration.instance.getUserID()!);
|
||||
final String tagPrefix = (isOwner ? "collection" : "shared_collection") +
|
||||
tag +
|
||||
@@ -53,7 +51,6 @@ class AlbumRowItemWidget extends StatelessWidget {
|
||||
color: c.publicURLs.first.isExpired ? warning500 : strokeBaseDark,
|
||||
)
|
||||
: null;
|
||||
final bool isFavCollection = c.type == CollectionType.favorites;
|
||||
|
||||
return GestureDetector(
|
||||
child: Column(
|
||||
@@ -81,20 +78,33 @@ class AlbumRowItemWidget extends StatelessWidget {
|
||||
CollectionsService.instance.getCoverCache(c);
|
||||
}
|
||||
if (thumbnail != null) {
|
||||
final bool isSelected =
|
||||
selectedAlbums?.isAlbumSelected(c) ?? false;
|
||||
final String heroTag = tagPrefix + thumbnail.tag;
|
||||
final thumbnailWidget = ThumbnailWidget(
|
||||
thumbnail,
|
||||
shouldShowArchiveStatus: isOwner
|
||||
? c.isArchived()
|
||||
: c.hasShareeArchived(),
|
||||
showFavForAlbumOnly: true,
|
||||
shouldShowSyncStatus: false,
|
||||
shouldShowPinIcon: isOwner && c.isPinned,
|
||||
key: Key(heroTag),
|
||||
);
|
||||
return Hero(
|
||||
tag: heroTag,
|
||||
transitionOnUserGestures: true,
|
||||
child: ThumbnailWidget(
|
||||
thumbnail,
|
||||
shouldShowArchiveStatus: isOwner
|
||||
? c.isArchived()
|
||||
: c.hasShareeArchived(),
|
||||
showFavForAlbumOnly: true,
|
||||
shouldShowSyncStatus: false,
|
||||
shouldShowPinIcon: isOwner && c.isPinned,
|
||||
key: Key(heroTag),
|
||||
),
|
||||
child: isSelected
|
||||
? ColorFiltered(
|
||||
colorFilter: ColorFilter.mode(
|
||||
Colors.black.withOpacity(
|
||||
0.4,
|
||||
),
|
||||
BlendMode.darken,
|
||||
),
|
||||
child: thumbnailWidget,
|
||||
)
|
||||
: thumbnailWidget,
|
||||
);
|
||||
} else {
|
||||
return const NoThumbnailWidget();
|
||||
@@ -114,8 +124,9 @@ class AlbumRowItemWidget extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.topRight,
|
||||
Positioned(
|
||||
top: 6,
|
||||
right: 6,
|
||||
child: Hero(
|
||||
tag: tagPrefix + "_album_selection",
|
||||
transitionOnUserGestures: true,
|
||||
@@ -128,13 +139,11 @@ class AlbumRowItemWidget extends StatelessWidget {
|
||||
duration: const Duration(milliseconds: 200),
|
||||
switchInCurve: Curves.easeOut,
|
||||
switchOutCurve: Curves.easeIn,
|
||||
child: isSelected && !isFavCollection
|
||||
? IconButtonWidget(
|
||||
key: const ValueKey("selected"),
|
||||
icon: Icons.check_circle_rounded,
|
||||
iconButtonType:
|
||||
IconButtonType.secondary,
|
||||
iconColor: colorScheme.blurStrokeBase,
|
||||
child: isSelected
|
||||
? const Icon(
|
||||
Icons.check_circle_rounded,
|
||||
color: Colors.white,
|
||||
size: 22,
|
||||
)
|
||||
: null,
|
||||
);
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'package:photos/models/collection/collection_items.dart';
|
||||
import "package:photos/models/selected_albums.dart";
|
||||
import "package:photos/service_locator.dart";
|
||||
import "package:photos/services/collections_service.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/collections/flex_grid_view.dart";
|
||||
import "package:photos/ui/components/buttons/icon_button_widget.dart";
|
||||
import "package:photos/ui/components/searchable_appbar.dart";
|
||||
@@ -48,6 +49,7 @@ class _CollectionListPageState extends State<CollectionListPage> {
|
||||
List<Collection>? collections;
|
||||
AlbumSortKey? sortKey;
|
||||
AlbumViewType? albumViewType;
|
||||
AlbumSortDirection? albumSortDirection;
|
||||
String _searchQuery = "";
|
||||
final _selectedAlbum = SelectedAlbums();
|
||||
|
||||
@@ -61,6 +63,7 @@ class _CollectionListPageState extends State<CollectionListPage> {
|
||||
});
|
||||
sortKey = localSettings.albumSortKey();
|
||||
albumViewType = localSettings.albumViewType();
|
||||
albumSortDirection = localSettings.albumSortDirection();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -104,7 +107,6 @@ class _CollectionListPageState extends State<CollectionListPage> {
|
||||
refreshCollections();
|
||||
},
|
||||
actions: [
|
||||
const SizedBox(width: 8),
|
||||
_sortMenu(collections!),
|
||||
],
|
||||
),
|
||||
@@ -114,8 +116,6 @@ class _CollectionListPageState extends State<CollectionListPage> {
|
||||
tag: widget.tag,
|
||||
enableSelectionMode: enableSelectionMode,
|
||||
albumViewType: albumViewType ?? AlbumViewType.grid,
|
||||
shouldShowCreateAlbum:
|
||||
widget.sectionType == UISectionType.homeCollections,
|
||||
selectedAlbums: _selectedAlbum,
|
||||
),
|
||||
],
|
||||
@@ -132,24 +132,39 @@ class _CollectionListPageState extends State<CollectionListPage> {
|
||||
}
|
||||
|
||||
Widget _sortMenu(List<Collection> collections) {
|
||||
Text sortOptionText(AlbumSortKey key) {
|
||||
final colorTheme = getEnteColorScheme(context);
|
||||
|
||||
Widget sortOptionText(AlbumSortKey key) {
|
||||
String text = key.toString();
|
||||
switch (key) {
|
||||
case AlbumSortKey.albumName:
|
||||
text = S.of(context).name;
|
||||
break;
|
||||
case AlbumSortKey.newestPhoto:
|
||||
text = S.of(context).newest;
|
||||
text = "Date Created";
|
||||
break;
|
||||
case AlbumSortKey.lastUpdated:
|
||||
text = S.of(context).lastUpdated;
|
||||
text = "Date Modified";
|
||||
}
|
||||
return Text(
|
||||
text,
|
||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).iconTheme.color!.withOpacity(0.7),
|
||||
),
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
text,
|
||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).iconTheme.color!.withOpacity(0.7),
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
sortKey == key
|
||||
? (albumSortDirection == AlbumSortDirection.ascending
|
||||
? Icons.arrow_upward_outlined
|
||||
: Icons.arrow_downward_outlined)
|
||||
: null,
|
||||
color: Theme.of(context).iconTheme.color!.withOpacity(0.7),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -165,6 +180,7 @@ class _CollectionListPageState extends State<CollectionListPage> {
|
||||
? Icons.view_list_outlined
|
||||
: Icons.grid_view_outlined,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
iconColor: colorTheme.blurStrokePressed,
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
albumViewType = albumViewType == AlbumViewType.grid
|
||||
@@ -174,7 +190,6 @@ class _CollectionListPageState extends State<CollectionListPage> {
|
||||
await localSettings.setAlbumViewType(albumViewType!);
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
GestureDetector(
|
||||
onTapDown: (TapDownDetails details) async {
|
||||
final int? selectedValue = await showMenu<int>(
|
||||
@@ -195,14 +210,20 @@ class _CollectionListPageState extends State<CollectionListPage> {
|
||||
if (selectedValue != null) {
|
||||
sortKey = AlbumSortKey.values[selectedValue];
|
||||
await localSettings.setAlbumSortKey(sortKey!);
|
||||
albumSortDirection =
|
||||
albumSortDirection == AlbumSortDirection.ascending
|
||||
? AlbumSortDirection.descending
|
||||
: AlbumSortDirection.ascending;
|
||||
await localSettings.setAlbumSortDirection(albumSortDirection!);
|
||||
await refreshCollections();
|
||||
setState(() {});
|
||||
Bus.instance.fire(AlbumSortOrderChangeEvent());
|
||||
}
|
||||
},
|
||||
child: const IconButtonWidget(
|
||||
child: IconButtonWidget(
|
||||
icon: Icons.sort_outlined,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
iconColor: colorTheme.blurStrokePressed,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -88,9 +88,6 @@ class _CollectionsFlexiGridViewWidgetState
|
||||
|
||||
Future<void> _toggleAlbumSelection(Collection c) async {
|
||||
await HapticFeedback.lightImpact();
|
||||
if (c.type == CollectionType.favorites) {
|
||||
return;
|
||||
}
|
||||
widget.selectedAlbums!.toggleSelection(c);
|
||||
setState(() {
|
||||
isAnyAlbumSelected = widget.selectedAlbums!.albums.isNotEmpty;
|
||||
@@ -136,8 +133,7 @@ class _CollectionsFlexiGridViewWidgetState
|
||||
albumsCountInOneRow;
|
||||
|
||||
final int totalCollections = widget.collections!.length;
|
||||
final bool showCreateAlbum =
|
||||
widget.shouldShowCreateAlbum && !isAnyAlbumSelected;
|
||||
final bool showCreateAlbum = widget.shouldShowCreateAlbum;
|
||||
final int totalItemCount = totalCollections + (showCreateAlbum ? 1 : 0);
|
||||
final int displayItemCount = min(totalItemCount, widget.displayLimitCount);
|
||||
|
||||
@@ -160,6 +156,7 @@ class _CollectionsFlexiGridViewWidgetState
|
||||
sideOfThumbnail,
|
||||
tag: widget.tag,
|
||||
selectedAlbums: widget.selectedAlbums,
|
||||
showFileCount: false,
|
||||
onTapCallback: (c) {
|
||||
isAnyAlbumSelected
|
||||
? _toggleAlbumSelection(c)
|
||||
|
||||
@@ -85,6 +85,7 @@ class _SearchableAppBarState extends State<SearchableAppBar> {
|
||||
icon: Icons.search,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
onTap: _activateSearch,
|
||||
iconColor: getEnteColorScheme(context).blurStrokePressed,
|
||||
),
|
||||
...?widget.actions,
|
||||
],
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/core/event_bus.dart';
|
||||
import 'package:photos/events/tab_changed_event.dart';
|
||||
import "package:photos/models/selected_albums.dart";
|
||||
import 'package:photos/models/selected_files.dart';
|
||||
import "package:photos/theme/colors.dart";
|
||||
import 'package:photos/theme/ente_theme.dart';
|
||||
@@ -10,12 +11,14 @@ import 'package:photos/ui/tabs/nav_bar.dart';
|
||||
|
||||
class HomeBottomNavigationBar extends StatefulWidget {
|
||||
const HomeBottomNavigationBar(
|
||||
this.selectedFiles, {
|
||||
this.selectedFiles,
|
||||
this.selectedAlbums, {
|
||||
required this.selectedTabIndex,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final SelectedFiles selectedFiles;
|
||||
final SelectedAlbums selectedAlbums;
|
||||
final int selectedTabIndex;
|
||||
|
||||
@override
|
||||
@@ -32,6 +35,7 @@ class _HomeBottomNavigationBarState extends State<HomeBottomNavigationBar> {
|
||||
super.initState();
|
||||
currentTabIndex = widget.selectedTabIndex;
|
||||
widget.selectedFiles.addListener(_selectedFilesListener);
|
||||
widget.selectedAlbums.addListener(_selectedAlbumsListener);
|
||||
_tabChangedEventSubscription =
|
||||
Bus.instance.on<TabChangedEvent>().listen((event) {
|
||||
if (event.source != TabChangedEventSource.tabBar) {
|
||||
@@ -56,6 +60,7 @@ class _HomeBottomNavigationBarState extends State<HomeBottomNavigationBar> {
|
||||
void dispose() {
|
||||
_tabChangedEventSubscription.cancel();
|
||||
widget.selectedFiles.removeListener(_selectedFilesListener);
|
||||
widget.selectedAlbums.removeListener(_selectedAlbumsListener);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -65,6 +70,12 @@ class _HomeBottomNavigationBarState extends State<HomeBottomNavigationBar> {
|
||||
}
|
||||
}
|
||||
|
||||
void _selectedAlbumsListener() {
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
void _onTabChange(int index, {String mode = 'tabChanged'}) {
|
||||
debugPrint("_TabChanged called via method $mode");
|
||||
Bus.instance.fire(
|
||||
@@ -78,6 +89,7 @@ class _HomeBottomNavigationBarState extends State<HomeBottomNavigationBar> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bool filesAreSelected = widget.selectedFiles.files.isNotEmpty;
|
||||
final bool albumsAreSelected = widget.selectedAlbums.albums.isNotEmpty;
|
||||
final enteColorScheme = getEnteColorScheme(context);
|
||||
|
||||
return SafeArea(
|
||||
@@ -85,9 +97,9 @@ class _HomeBottomNavigationBarState extends State<HomeBottomNavigationBar> {
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
height: filesAreSelected ? 0 : 56,
|
||||
height: filesAreSelected || albumsAreSelected ? 0 : 56,
|
||||
child: IgnorePointer(
|
||||
ignoring: filesAreSelected,
|
||||
ignoring: filesAreSelected || albumsAreSelected,
|
||||
child: ListView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
children: [
|
||||
|
||||
@@ -35,7 +35,7 @@ class AddParticipantPage extends StatefulWidget {
|
||||
);
|
||||
|
||||
bool get isMultipleCollections =>
|
||||
collections != null && collections!.length > 1;
|
||||
collections != null && collections!.isNotEmpty;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _AddParticipantPage();
|
||||
@@ -84,9 +84,11 @@ class _AddParticipantPage extends State<AddParticipantPage> {
|
||||
resizeToAvoidBottomInset: isKeypadOpen,
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
widget.isAddingViewer
|
||||
? S.of(context).addViewer
|
||||
: S.of(context).addCollaborator,
|
||||
widget.isMultipleCollections
|
||||
? "Add participants"
|
||||
: widget.isAddingViewer
|
||||
? S.of(context).addViewer
|
||||
: S.of(context).addCollaborator,
|
||||
),
|
||||
),
|
||||
body: Column(
|
||||
@@ -228,52 +230,9 @@ class _AddParticipantPage extends State<AddParticipantPage> {
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.primary,
|
||||
buttonSize: ButtonSize.large,
|
||||
labelText: widget.isAddingViewer
|
||||
? S.of(context).addViewers(_selectedEmails.length)
|
||||
: S
|
||||
.of(context)
|
||||
.addCollaborators(_selectedEmails.length),
|
||||
isDisabled: _selectedEmails.isEmpty,
|
||||
onTap: () async {
|
||||
final results = <bool>[];
|
||||
final collections = getAllCollections();
|
||||
|
||||
for (String email in _selectedEmails) {
|
||||
for (Collection collection in collections) {
|
||||
results.add(
|
||||
await collectionActions.addEmailToCollection(
|
||||
context,
|
||||
collection,
|
||||
email,
|
||||
widget.isAddingViewer
|
||||
? CollectionParticipantRole.viewer
|
||||
: CollectionParticipantRole.collaborator,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final noOfSuccessfullAdds =
|
||||
results.where((e) => e).length;
|
||||
showToast(
|
||||
context,
|
||||
widget.isAddingViewer
|
||||
? S
|
||||
.of(context)
|
||||
.viewersSuccessfullyAdded(noOfSuccessfullAdds)
|
||||
: S.of(context).collaboratorsSuccessfullyAdded(
|
||||
noOfSuccessfullAdds,
|
||||
),
|
||||
);
|
||||
|
||||
if (!results.any((e) => e == false) && mounted) {
|
||||
Navigator.of(context).pop(true);
|
||||
}
|
||||
},
|
||||
),
|
||||
widget.isMultipleCollections
|
||||
? _multipleActionButton()
|
||||
: _singleActionButton(),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
),
|
||||
@@ -284,6 +243,124 @@ class _AddParticipantPage extends State<AddParticipantPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _singleActionButton() {
|
||||
return ButtonWidget(
|
||||
buttonType: ButtonType.primary,
|
||||
buttonSize: ButtonSize.large,
|
||||
labelText: widget.isAddingViewer
|
||||
? S.of(context).addViewers(_selectedEmails.length)
|
||||
: S.of(context).addCollaborators(_selectedEmails.length),
|
||||
isDisabled: _selectedEmails.isEmpty,
|
||||
onTap: () async {
|
||||
final results = <bool>[];
|
||||
final collections = getAllCollections();
|
||||
|
||||
for (String email in _selectedEmails) {
|
||||
for (Collection collection in collections) {
|
||||
results.add(
|
||||
await collectionActions.addEmailToCollection(
|
||||
context,
|
||||
collection,
|
||||
email,
|
||||
widget.isAddingViewer
|
||||
? CollectionParticipantRole.viewer
|
||||
: CollectionParticipantRole.collaborator,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final noOfSuccessfullAdds = results.where((e) => e).length;
|
||||
showToast(
|
||||
context,
|
||||
widget.isAddingViewer
|
||||
? S.of(context).viewersSuccessfullyAdded(noOfSuccessfullAdds)
|
||||
: S.of(context).collaboratorsSuccessfullyAdded(
|
||||
noOfSuccessfullAdds,
|
||||
),
|
||||
);
|
||||
|
||||
if (!results.any((e) => e == false) && mounted) {
|
||||
Navigator.of(context).pop(true);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _multipleActionButton() {
|
||||
return Column(
|
||||
children: [
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.primary,
|
||||
buttonSize: ButtonSize.large,
|
||||
labelText: S.of(context).addViewers(_selectedEmails.length),
|
||||
isDisabled: _selectedEmails.isEmpty,
|
||||
onTap: () async {
|
||||
final results = <bool>[];
|
||||
final collections = getAllCollections();
|
||||
|
||||
for (String email in _selectedEmails) {
|
||||
bool result = false;
|
||||
for (Collection collection in collections) {
|
||||
result = await collectionActions.addEmailToCollection(
|
||||
context,
|
||||
collection,
|
||||
email,
|
||||
CollectionParticipantRole.viewer,
|
||||
);
|
||||
}
|
||||
results.add(result);
|
||||
}
|
||||
|
||||
final noOfSuccessfullAdds = results.where((e) => e).length;
|
||||
showToast(
|
||||
context,
|
||||
S.of(context).viewersSuccessfullyAdded(noOfSuccessfullAdds),
|
||||
);
|
||||
|
||||
if (!results.any((e) => e == false) && mounted) {
|
||||
Navigator.of(context).pop(true);
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ButtonWidget(
|
||||
buttonType: ButtonType.primary,
|
||||
buttonSize: ButtonSize.large,
|
||||
labelText: S.of(context).addCollaborators(_selectedEmails.length),
|
||||
isDisabled: _selectedEmails.isEmpty,
|
||||
onTap: () async {
|
||||
final results = <bool>[];
|
||||
final collections = getAllCollections();
|
||||
|
||||
for (String email in _selectedEmails) {
|
||||
bool result = false;
|
||||
for (Collection collection in collections) {
|
||||
result = await collectionActions.addEmailToCollection(
|
||||
context,
|
||||
collection,
|
||||
email,
|
||||
CollectionParticipantRole.collaborator,
|
||||
);
|
||||
}
|
||||
results.add(result);
|
||||
}
|
||||
|
||||
final noOfSuccessfullAdds = results.where((e) => e).length;
|
||||
showToast(
|
||||
context,
|
||||
S.of(context).collaboratorsSuccessfullyAdded(noOfSuccessfullAdds),
|
||||
);
|
||||
|
||||
if (!results.any((e) => e == false) && mounted) {
|
||||
Navigator.of(context).pop(true);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void clearFocus() {
|
||||
_textController.clear();
|
||||
_newEmail = _textController.text;
|
||||
|
||||
@@ -33,6 +33,7 @@ import "package:photos/l10n/l10n.dart";
|
||||
import "package:photos/models/collection/collection.dart";
|
||||
import 'package:photos/models/collection/collection_items.dart';
|
||||
import "package:photos/models/file/file.dart";
|
||||
import "package:photos/models/selected_albums.dart";
|
||||
import 'package:photos/models/selected_files.dart';
|
||||
import "package:photos/service_locator.dart";
|
||||
import 'package:photos/services/account/user_service.dart';
|
||||
@@ -84,7 +85,6 @@ class HomeWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _HomeWidgetState extends State<HomeWidget> {
|
||||
static const _userCollectionsTab = UserCollectionsTab();
|
||||
static const _sharedCollectionTab = SharedCollectionsTab();
|
||||
static const _searchTab = SearchTab();
|
||||
static final _settingsPage = SettingsPage(
|
||||
@@ -92,6 +92,7 @@ class _HomeWidgetState extends State<HomeWidget> {
|
||||
);
|
||||
|
||||
final _logger = Logger("HomeWidgetState");
|
||||
final _selectedAlbums = SelectedAlbums();
|
||||
final _selectedFiles = SelectedFiles();
|
||||
|
||||
final PageController _pageController = PageController();
|
||||
@@ -708,7 +709,7 @@ class _HomeWidgetState extends State<HomeWidget> {
|
||||
),
|
||||
selectedFiles: _selectedFiles,
|
||||
),
|
||||
_userCollectionsTab,
|
||||
UserCollectionsTab(selectedAlbums: _selectedAlbums),
|
||||
_sharedCollectionTab,
|
||||
_searchTab,
|
||||
],
|
||||
@@ -755,6 +756,7 @@ class _HomeWidgetState extends State<HomeWidget> {
|
||||
: const SizedBox.shrink(),
|
||||
HomeBottomNavigationBar(
|
||||
_selectedFiles,
|
||||
_selectedAlbums,
|
||||
selectedTabIndex: _selectedTabIndex,
|
||||
),
|
||||
],
|
||||
|
||||
@@ -150,10 +150,11 @@ class QuickLinkAlbumItem extends StatelessWidget {
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
iconColor: colorScheme.blurStrokeBase,
|
||||
)
|
||||
: const IconButtonWidget(
|
||||
key: ValueKey("unselected"),
|
||||
: IconButtonWidget(
|
||||
key: const ValueKey("unselected"),
|
||||
icon: Icons.chevron_right_outlined,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
iconColor: colorScheme.blurStrokePressed,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -3,13 +3,17 @@ import "dart:math";
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import "package:photos/core/constants.dart";
|
||||
import 'package:photos/core/event_bus.dart';
|
||||
import 'package:photos/events/collection_updated_event.dart';
|
||||
import 'package:photos/events/local_photos_updated_event.dart';
|
||||
import 'package:photos/events/user_logged_out_event.dart';
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import 'package:photos/models/collection/collection_items.dart';
|
||||
import "package:photos/models/search/generic_search_result.dart";
|
||||
import 'package:photos/services/collections_service.dart';
|
||||
import "package:photos/services/search_service.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/collections/album/row_item.dart";
|
||||
import "package:photos/ui/collections/collection_list_page.dart";
|
||||
import 'package:photos/ui/common/loading_widget.dart';
|
||||
@@ -20,6 +24,7 @@ import "package:photos/ui/tabs/shared/empty_state.dart";
|
||||
import "package:photos/ui/tabs/shared/quick_link_album_item.dart";
|
||||
import "package:photos/ui/viewer/gallery/collect_photos_card_widget.dart";
|
||||
import "package:photos/ui/viewer/gallery/collection_page.dart";
|
||||
import "package:photos/ui/viewer/search_tab/contacts_section.dart";
|
||||
import "package:photos/utils/navigation_util.dart";
|
||||
import "package:photos/utils/standalone/debouncer.dart";
|
||||
|
||||
@@ -106,6 +111,7 @@ class _SharedCollectionsTabState extends State<SharedCollectionsTab>
|
||||
SectionTitle(title: S.of(context).sharedWithYou);
|
||||
final SectionTitle sharedByYou =
|
||||
SectionTitle(title: S.of(context).sharedByYou);
|
||||
final colorTheme = getEnteColorScheme(context);
|
||||
return SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: Container(
|
||||
@@ -136,9 +142,10 @@ class _SharedCollectionsTabState extends State<SharedCollectionsTab>
|
||||
: null,
|
||||
Hero(tag: "incoming", child: sharedWithYou),
|
||||
trailingWidget: collections.incoming.isNotEmpty
|
||||
? const IconButtonWidget(
|
||||
? IconButtonWidget(
|
||||
icon: Icons.chevron_right,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
iconColor: colorTheme.blurStrokePressed,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
@@ -158,6 +165,7 @@ class _SharedCollectionsTabState extends State<SharedCollectionsTab>
|
||||
collections.incoming[index],
|
||||
maxThumbnailWidth,
|
||||
tag: "incoming",
|
||||
showFileCount: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -192,9 +200,10 @@ class _SharedCollectionsTabState extends State<SharedCollectionsTab>
|
||||
: null,
|
||||
Hero(tag: "outgoing", child: sharedByYou),
|
||||
trailingWidget: collections.outgoing.isNotEmpty
|
||||
? const IconButtonWidget(
|
||||
? IconButtonWidget(
|
||||
icon: Icons.chevron_right,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
iconColor: colorTheme.blurStrokePressed,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
@@ -214,6 +223,7 @@ class _SharedCollectionsTabState extends State<SharedCollectionsTab>
|
||||
collections.outgoing[index],
|
||||
maxThumbnailWidth,
|
||||
tag: "outgoing",
|
||||
showFileCount: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -252,9 +262,10 @@ class _SharedCollectionsTabState extends State<SharedCollectionsTab>
|
||||
),
|
||||
),
|
||||
trailingWidget: numberOfQuickLinks > maxQuickLinks
|
||||
? const IconButtonWidget(
|
||||
? IconButtonWidget(
|
||||
icon: Icons.chevron_right,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
iconColor: colorTheme.blurStrokePressed,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
@@ -297,6 +308,27 @@ class _SharedCollectionsTabState extends State<SharedCollectionsTab>
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
const SizedBox(height: 2),
|
||||
FutureBuilder(
|
||||
future: SearchService.instance
|
||||
.getAllContactsSearchResults(kSearchSectionLimit),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return ContactsSection(
|
||||
snapshot.data as List<GenericSearchResult>,
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
_logger.severe(
|
||||
"failed to load contacts section",
|
||||
snapshot.error,
|
||||
snapshot.stackTrace,
|
||||
);
|
||||
return const EnteLoadingWidget();
|
||||
} else {
|
||||
return const EnteLoadingWidget();
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const CollectPhotosCardWidget(),
|
||||
const SizedBox(height: 32),
|
||||
|
||||
@@ -11,6 +11,7 @@ import 'package:photos/events/local_photos_updated_event.dart';
|
||||
import 'package:photos/events/user_logged_out_event.dart';
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import 'package:photos/models/collection/collection.dart';
|
||||
import "package:photos/models/selected_albums.dart";
|
||||
import 'package:photos/services/collections_service.dart';
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/collections/button/archived_button.dart";
|
||||
@@ -24,13 +25,16 @@ import "package:photos/ui/collections/flex_grid_view.dart";
|
||||
import 'package:photos/ui/common/loading_widget.dart';
|
||||
import 'package:photos/ui/components/buttons/icon_button_widget.dart';
|
||||
import "package:photos/ui/tabs/section_title.dart";
|
||||
import "package:photos/ui/viewer/actions/album_selection_overlay_bar.dart";
|
||||
import "package:photos/ui/viewer/actions/delete_empty_albums.dart";
|
||||
import "package:photos/ui/viewer/gallery/empty_state.dart";
|
||||
import "package:photos/utils/navigation_util.dart";
|
||||
import "package:photos/utils/standalone/debouncer.dart";
|
||||
|
||||
class UserCollectionsTab extends StatefulWidget {
|
||||
const UserCollectionsTab({super.key});
|
||||
const UserCollectionsTab({super.key, this.selectedAlbums});
|
||||
|
||||
final SelectedAlbums? selectedAlbums;
|
||||
|
||||
@override
|
||||
State<UserCollectionsTab> createState() => _UserCollectionsTabState();
|
||||
@@ -55,7 +59,8 @@ class _UserCollectionsTabState extends State<UserCollectionsTab>
|
||||
leading: true,
|
||||
);
|
||||
|
||||
static const int _kOnEnteItemLimitCount = 9;
|
||||
static const int _kOnEnteItemLimitCount = 12;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -123,95 +128,109 @@ class _UserCollectionsTabState extends State<UserCollectionsTab>
|
||||
.withOpacity(0.5),
|
||||
);
|
||||
|
||||
return CustomScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
controller: _scrollController,
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: SectionOptions(
|
||||
onTap: () {
|
||||
unawaited(
|
||||
routeToPage(
|
||||
context,
|
||||
DeviceFolderVerticalGridView(
|
||||
appTitle: SectionTitle(
|
||||
title: S.of(context).onDevice,
|
||||
return Stack(
|
||||
alignment: Alignment.bottomCenter,
|
||||
children: [
|
||||
CustomScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
controller: _scrollController,
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: SectionOptions(
|
||||
onTap: () {
|
||||
unawaited(
|
||||
routeToPage(
|
||||
context,
|
||||
DeviceFolderVerticalGridView(
|
||||
appTitle: SectionTitle(
|
||||
title: S.of(context).onDevice,
|
||||
),
|
||||
tag: "OnDeviceAppTitle",
|
||||
),
|
||||
),
|
||||
tag: "OnDeviceAppTitle",
|
||||
),
|
||||
);
|
||||
},
|
||||
Hero(
|
||||
tag: "OnDeviceAppTitle",
|
||||
child: SectionTitle(title: S.of(context).onDevice),
|
||||
),
|
||||
);
|
||||
},
|
||||
Hero(
|
||||
tag: "OnDeviceAppTitle",
|
||||
child: SectionTitle(title: S.of(context).onDevice),
|
||||
trailingWidget: IconButtonWidget(
|
||||
icon: Icons.chevron_right,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
iconColor: getEnteColorScheme(context).blurStrokePressed,
|
||||
),
|
||||
),
|
||||
),
|
||||
trailingWidget: const IconButtonWidget(
|
||||
icon: Icons.chevron_right,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
const SliverToBoxAdapter(child: DeviceFoldersGridView()),
|
||||
SliverToBoxAdapter(
|
||||
child: SectionOptions(
|
||||
onTap: () {
|
||||
unawaited(
|
||||
routeToPage(
|
||||
context,
|
||||
CollectionListPage(
|
||||
collections,
|
||||
sectionType: UISectionType.homeCollections,
|
||||
appTitle: SectionTitle(
|
||||
titleWithBrand: getOnEnteSection(context),
|
||||
),
|
||||
initialScrollOffset: _scrollController.offset,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
SectionTitle(titleWithBrand: getOnEnteSection(context)),
|
||||
trailingWidget: IconButtonWidget(
|
||||
icon: Icons.chevron_right,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
iconColor: getEnteColorScheme(context).blurStrokePressed,
|
||||
),
|
||||
padding: const EdgeInsets.only(left: 12, right: 6),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SliverToBoxAdapter(child: DeviceFoldersGridView()),
|
||||
SliverToBoxAdapter(
|
||||
child: SectionOptions(
|
||||
onTap: () {
|
||||
unawaited(
|
||||
routeToPage(
|
||||
context,
|
||||
CollectionListPage(
|
||||
SliverToBoxAdapter(child: DeleteEmptyAlbums(collections)),
|
||||
Configuration.instance.hasConfiguredAccount()
|
||||
? CollectionsFlexiGridViewWidget(
|
||||
collections,
|
||||
sectionType: UISectionType.homeCollections,
|
||||
appTitle: SectionTitle(
|
||||
titleWithBrand: getOnEnteSection(context),
|
||||
),
|
||||
initialScrollOffset: _scrollController.offset,
|
||||
),
|
||||
displayLimitCount: _kOnEnteItemLimitCount,
|
||||
selectedAlbums: widget.selectedAlbums,
|
||||
shrinkWrap: true,
|
||||
shouldShowCreateAlbum: true,
|
||||
enableSelectionMode: true,
|
||||
)
|
||||
: const SliverToBoxAdapter(child: EmptyState()),
|
||||
SliverToBoxAdapter(
|
||||
child: Divider(
|
||||
color: getEnteColorScheme(context).strokeFaint,
|
||||
),
|
||||
),
|
||||
const SliverToBoxAdapter(child: SizedBox(height: 12)),
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Column(
|
||||
children: [
|
||||
UnCategorizedCollections(trashAndHiddenTextStyle),
|
||||
const SizedBox(height: 12),
|
||||
ArchivedCollectionsButton(trashAndHiddenTextStyle),
|
||||
const SizedBox(height: 12),
|
||||
HiddenCollectionsButtonWidget(trashAndHiddenTextStyle),
|
||||
const SizedBox(height: 12),
|
||||
TrashSectionButton(trashAndHiddenTextStyle),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
SectionTitle(titleWithBrand: getOnEnteSection(context)),
|
||||
trailingWidget: const IconButtonWidget(
|
||||
icon: Icons.chevron_right,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.only(left: 12, right: 6),
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(child: DeleteEmptyAlbums(collections)),
|
||||
Configuration.instance.hasConfiguredAccount()
|
||||
? CollectionsFlexiGridViewWidget(
|
||||
collections,
|
||||
displayLimitCount: _kOnEnteItemLimitCount,
|
||||
shrinkWrap: true,
|
||||
shouldShowCreateAlbum: true,
|
||||
enableSelectionMode: false,
|
||||
)
|
||||
: const SliverToBoxAdapter(child: EmptyState()),
|
||||
SliverToBoxAdapter(
|
||||
child: Divider(
|
||||
color: getEnteColorScheme(context).strokeFaint,
|
||||
),
|
||||
),
|
||||
const SliverToBoxAdapter(child: SizedBox(height: 12)),
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Column(
|
||||
children: [
|
||||
UnCategorizedCollections(trashAndHiddenTextStyle),
|
||||
const SizedBox(height: 12),
|
||||
ArchivedCollectionsButton(trashAndHiddenTextStyle),
|
||||
const SizedBox(height: 12),
|
||||
HiddenCollectionsButtonWidget(trashAndHiddenTextStyle),
|
||||
const SizedBox(height: 12),
|
||||
TrashSectionButton(trashAndHiddenTextStyle),
|
||||
],
|
||||
SliverToBoxAdapter(
|
||||
child:
|
||||
SizedBox(height: 64 + MediaQuery.of(context).padding.bottom),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(height: 64 + MediaQuery.of(context).padding.bottom),
|
||||
AlbumSelectionOverlayBar(
|
||||
widget.selectedAlbums!,
|
||||
UISectionType.homeCollections,
|
||||
collections,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import "package:flutter/cupertino.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/db/files_db.dart";
|
||||
@@ -12,8 +13,11 @@ import "package:photos/ui/components/action_sheet_widget.dart";
|
||||
import "package:photos/ui/components/bottom_action_bar/selection_action_button_widget.dart";
|
||||
import "package:photos/ui/components/buttons/button_widget.dart";
|
||||
import "package:photos/ui/components/models/button_type.dart";
|
||||
import "package:photos/ui/notification/toast.dart";
|
||||
import "package:photos/ui/sharing/add_participant_page.dart";
|
||||
import "package:photos/utils/dialog_util.dart";
|
||||
import "package:photos/utils/magic_util.dart";
|
||||
import "package:photos/utils/navigation_util.dart";
|
||||
|
||||
class AlbumSelectionActionWidget extends StatefulWidget {
|
||||
final SelectedAlbums selectedAlbums;
|
||||
@@ -34,19 +38,31 @@ class _AlbumSelectionActionWidgetState
|
||||
extends State<AlbumSelectionActionWidget> {
|
||||
final _logger = Logger("AlbumSelectionActionWidgetState");
|
||||
late CollectionActions collectionActions;
|
||||
bool hasFavorites = false;
|
||||
|
||||
@override
|
||||
initState() {
|
||||
collectionActions = CollectionActions(CollectionsService.instance);
|
||||
widget.selectedAlbums.addListener(_selectionChangedListener);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
widget.selectedAlbums.removeListener(_selectionChangedListener);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (widget.selectedAlbums.albums.isEmpty) {
|
||||
return const SizedBox();
|
||||
}
|
||||
final List<SelectionActionButton> items = [];
|
||||
final hasPinnedAlbum =
|
||||
widget.selectedAlbums.albums.any((album) => album.isPinned);
|
||||
final hasUnpinnedAlbum =
|
||||
widget.selectedAlbums.albums.any((album) => !album.isPinned);
|
||||
|
||||
if (widget.sectionType == UISectionType.homeCollections ||
|
||||
widget.sectionType == UISectionType.outgoingCollections) {
|
||||
@@ -62,8 +78,19 @@ class _AlbumSelectionActionWidgetState
|
||||
labelText: "Pin",
|
||||
icon: Icons.push_pin_rounded,
|
||||
onTap: _onPinClick,
|
||||
shouldShow: hasUnpinnedAlbum,
|
||||
),
|
||||
);
|
||||
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
labelText: "Unpin",
|
||||
icon: CupertinoIcons.pin_slash,
|
||||
onTap: _onUnpinClick,
|
||||
shouldShow: hasPinnedAlbum,
|
||||
),
|
||||
);
|
||||
|
||||
items.add(
|
||||
SelectionActionButton(
|
||||
labelText: S.of(context).delete,
|
||||
@@ -131,10 +158,17 @@ class _AlbumSelectionActionWidgetState
|
||||
}
|
||||
|
||||
Future<void> _shareCollection() async {
|
||||
await collectionActions.shareMultipleCollectionSheet(
|
||||
await routeToPage(
|
||||
context,
|
||||
widget.selectedAlbums.albums.toList(),
|
||||
AddParticipantPage(
|
||||
widget.selectedAlbums.albums.toList().first,
|
||||
false,
|
||||
collections: widget.selectedAlbums.albums.toList(),
|
||||
),
|
||||
);
|
||||
if (hasFavorites) {
|
||||
_showFavToast();
|
||||
}
|
||||
widget.selectedAlbums.clearAll();
|
||||
}
|
||||
|
||||
@@ -170,6 +204,9 @@ class _AlbumSelectionActionWidgetState
|
||||
debugPrint("No pop");
|
||||
}
|
||||
}
|
||||
if (hasFavorites) {
|
||||
_showFavToast();
|
||||
}
|
||||
widget.selectedAlbums.clearAll();
|
||||
}
|
||||
|
||||
@@ -185,6 +222,27 @@ class _AlbumSelectionActionWidgetState
|
||||
collection.isPinned ? 1 : 1,
|
||||
);
|
||||
}
|
||||
if (hasFavorites) {
|
||||
_showFavToast();
|
||||
}
|
||||
widget.selectedAlbums.clearAll();
|
||||
}
|
||||
|
||||
Future<void> _onUnpinClick() async {
|
||||
for (final collection in widget.selectedAlbums.albums) {
|
||||
if (collection.type == CollectionType.favorites || !collection.isPinned) {
|
||||
continue;
|
||||
}
|
||||
|
||||
await updateOrder(
|
||||
context,
|
||||
collection,
|
||||
collection.isPinned ? 0 : 0,
|
||||
);
|
||||
}
|
||||
if (hasFavorites) {
|
||||
_showFavToast();
|
||||
}
|
||||
widget.selectedAlbums.clearAll();
|
||||
}
|
||||
|
||||
@@ -204,6 +262,9 @@ class _AlbumSelectionActionWidgetState
|
||||
prevVisibility: prevVisiblity,
|
||||
);
|
||||
}
|
||||
if (hasFavorites) {
|
||||
_showFavToast();
|
||||
}
|
||||
widget.selectedAlbums.clearAll();
|
||||
}
|
||||
|
||||
@@ -240,6 +301,9 @@ class _AlbumSelectionActionWidgetState
|
||||
prevVisibility: prevVisiblity,
|
||||
);
|
||||
}
|
||||
if (hasFavorites) {
|
||||
_showFavToast();
|
||||
}
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
@@ -290,4 +354,19 @@ class _AlbumSelectionActionWidgetState
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _selectionChangedListener() {
|
||||
if (mounted) {
|
||||
hasFavorites = widget.selectedAlbums.albums
|
||||
.any((album) => album.type == CollectionType.favorites);
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
void _showFavToast() {
|
||||
showShortToast(
|
||||
context,
|
||||
"The Favorites album cannot be modified",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,11 +133,12 @@ class SearchableItemWidget extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
const Flexible(
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: IconButtonWidget(
|
||||
icon: Icons.chevron_right_outlined,
|
||||
iconButtonType: IconButtonType.secondary,
|
||||
iconColor: colorScheme.blurStrokePressed,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -16,7 +16,6 @@ import "package:photos/ui/viewer/search/result/no_result_widget.dart";
|
||||
import "package:photos/ui/viewer/search/search_suggestions.dart";
|
||||
import "package:photos/ui/viewer/search/tab_empty_state.dart";
|
||||
import 'package:photos/ui/viewer/search_tab/albums_section.dart';
|
||||
import "package:photos/ui/viewer/search_tab/contacts_section.dart";
|
||||
import "package:photos/ui/viewer/search_tab/file_type_section.dart";
|
||||
import "package:photos/ui/viewer/search_tab/locations_section.dart";
|
||||
import "package:photos/ui/viewer/search_tab/magic_section.dart";
|
||||
@@ -142,10 +141,7 @@ class _AllSearchSectionsState extends State<AllSearchSections> {
|
||||
as List<GenericSearchResult>,
|
||||
);
|
||||
case SectionType.contacts:
|
||||
return ContactsSection(
|
||||
snapshot.data!.elementAt(index)
|
||||
as List<GenericSearchResult>,
|
||||
);
|
||||
return const SizedBox.shrink();
|
||||
case SectionType.fileTypesAndExtension:
|
||||
return FileTypeSection(
|
||||
snapshot.data!.elementAt(index)
|
||||
|
||||
@@ -39,7 +39,7 @@ class SectionHeader extends StatelessWidget {
|
||||
padding: const EdgeInsets.fromLTRB(24, 12, 12, 12),
|
||||
child: Icon(
|
||||
Icons.chevron_right_outlined,
|
||||
color: getEnteColorScheme(context).strokeMuted,
|
||||
color: getEnteColorScheme(context).blurStrokePressed,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -8,6 +8,11 @@ enum AlbumSortKey {
|
||||
lastUpdated,
|
||||
}
|
||||
|
||||
enum AlbumSortDirection {
|
||||
ascending,
|
||||
descending,
|
||||
}
|
||||
|
||||
enum AlbumViewType {
|
||||
grid,
|
||||
list,
|
||||
@@ -29,6 +34,7 @@ class LocalSettings {
|
||||
static const _hideSharedItemsFromHomeGalleryTag =
|
||||
"hide_shared_items_from_home_gallery";
|
||||
static const kCollectionViewType = "collection_view_type";
|
||||
static const kCollectionSortDirection = "collection_sort_direction";
|
||||
|
||||
final SharedPreferences _prefs;
|
||||
|
||||
@@ -51,6 +57,15 @@ class LocalSettings {
|
||||
return AlbumViewType.values[index];
|
||||
}
|
||||
|
||||
AlbumSortDirection albumSortDirection() {
|
||||
return AlbumSortDirection
|
||||
.values[_prefs.getInt(kCollectionSortDirection) ?? 1];
|
||||
}
|
||||
|
||||
Future<bool> setAlbumSortDirection(AlbumSortDirection direction) {
|
||||
return _prefs.setInt(kCollectionSortDirection, direction.index);
|
||||
}
|
||||
|
||||
int getPhotoGridSize() {
|
||||
if (_prefs.containsKey(kPhotoGridSize)) {
|
||||
return _prefs.getInt(kPhotoGridSize)!;
|
||||
|
||||
Reference in New Issue
Block a user