[mob][photos] Use GalleryAppBar widget on location screen
This commit is contained in:
@@ -4,13 +4,17 @@ class EntePopupMenuItem<T> extends PopupMenuItem<T> {
|
||||
final String label;
|
||||
final IconData? icon;
|
||||
final Widget? iconWidget;
|
||||
final Color? iconColor;
|
||||
final Color? labelColor;
|
||||
|
||||
EntePopupMenuItem(
|
||||
this.label, {
|
||||
required T value,
|
||||
required T super.value,
|
||||
this.icon,
|
||||
this.iconWidget,
|
||||
Key? key,
|
||||
this.iconColor,
|
||||
this.labelColor,
|
||||
super.key,
|
||||
}) : assert(
|
||||
icon != null || iconWidget != null,
|
||||
'Either icon or iconWidget must be provided.',
|
||||
@@ -20,18 +24,19 @@ class EntePopupMenuItem<T> extends PopupMenuItem<T> {
|
||||
'Only one of icon or iconWidget can be provided.',
|
||||
),
|
||||
super(
|
||||
value: value,
|
||||
key: key,
|
||||
child: Row(
|
||||
children: [
|
||||
if (iconWidget != null)
|
||||
iconWidget
|
||||
else if (icon != null)
|
||||
Icon(icon),
|
||||
Icon(icon, color: iconColor),
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
),
|
||||
Text(label),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(color: labelColor),
|
||||
),
|
||||
],
|
||||
), // Initially empty, will be populated in build
|
||||
);
|
||||
|
||||
@@ -23,8 +23,11 @@ import "package:photos/models/metadata/common_keys.dart";
|
||||
import 'package:photos/models/selected_files.dart';
|
||||
import 'package:photos/service_locator.dart';
|
||||
import 'package:photos/services/collections_service.dart';
|
||||
import "package:photos/services/location_service.dart";
|
||||
import 'package:photos/services/sync_service.dart';
|
||||
import 'package:photos/services/update_service.dart';
|
||||
import "package:photos/states/location_screen_state.dart";
|
||||
import "package:photos/theme/colors.dart";
|
||||
import 'package:photos/ui/actions/collection/collection_sharing_actions.dart';
|
||||
import "package:photos/ui/cast/auto.dart";
|
||||
import "package:photos/ui/cast/choose.dart";
|
||||
@@ -42,6 +45,7 @@ import "package:photos/ui/viewer/gallery/hooks/add_photos_sheet.dart";
|
||||
import 'package:photos/ui/viewer/gallery/hooks/pick_cover_photo.dart';
|
||||
import "package:photos/ui/viewer/hierarchicial_search/applied_filters.dart";
|
||||
import "package:photos/ui/viewer/hierarchicial_search/recommended_filters.dart";
|
||||
import "package:photos/ui/viewer/location/edit_location_sheet.dart";
|
||||
import 'package:photos/utils/data_util.dart';
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/magic_util.dart';
|
||||
@@ -88,7 +92,9 @@ enum AlbumPopupAction {
|
||||
removeLink,
|
||||
cleanUncategorized,
|
||||
sortByMostRecent,
|
||||
sortByMostRelevant
|
||||
sortByMostRelevant,
|
||||
editLocation,
|
||||
deleteLocation,
|
||||
}
|
||||
|
||||
class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
|
||||
@@ -452,6 +458,20 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
|
||||
child: const Icon(CupertinoIcons.pin),
|
||||
),
|
||||
),
|
||||
if (galleryType == GalleryType.locationTag)
|
||||
EntePopupMenuItem(
|
||||
S.of(context).editLocation,
|
||||
value: AlbumPopupAction.editLocation,
|
||||
icon: Icons.edit_outlined,
|
||||
),
|
||||
if (galleryType == GalleryType.locationTag)
|
||||
EntePopupMenuItem(
|
||||
S.of(context).deleteLocation,
|
||||
value: AlbumPopupAction.deleteLocation,
|
||||
icon: Icons.delete_outline,
|
||||
iconColor: warning500,
|
||||
labelColor: warning500,
|
||||
),
|
||||
]);
|
||||
final bool isArchived = widget.collection?.isArchived() ?? false;
|
||||
final bool isHidden = widget.collection?.isHidden() ?? false;
|
||||
@@ -571,6 +591,10 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
|
||||
await showOnMap();
|
||||
} else if (value == AlbumPopupAction.cleanUncategorized) {
|
||||
await onCleanUncategorizedClick(context);
|
||||
} else if (value == AlbumPopupAction.editLocation) {
|
||||
editLocation();
|
||||
} else if (value == AlbumPopupAction.deleteLocation) {
|
||||
await deleteLocation();
|
||||
} else {
|
||||
showToast(context, S.of(context).somethingWentWrong);
|
||||
}
|
||||
@@ -582,6 +606,24 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
|
||||
return actions;
|
||||
}
|
||||
|
||||
void editLocation() {
|
||||
showEditLocationSheet(
|
||||
context,
|
||||
InheritedLocationScreenState.of(context).locationTagEntity,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> deleteLocation() async {
|
||||
try {
|
||||
await LocationService.instance.deleteLocationTag(
|
||||
InheritedLocationScreenState.of(context).locationTagEntity.id,
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
} catch (e) {
|
||||
await showGenericErrorDialog(context: context, error: e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> onCleanUncategorizedClick(BuildContext buildContext) async {
|
||||
final actionResult = await showChoiceActionSheet(
|
||||
context,
|
||||
|
||||
@@ -2,131 +2,79 @@ import "dart:async";
|
||||
import 'dart:developer' as dev;
|
||||
|
||||
import "package:flutter/material.dart";
|
||||
import "package:intl/intl.dart";
|
||||
import "package:photos/core/constants.dart";
|
||||
import "package:photos/core/event_bus.dart";
|
||||
import "package:photos/db/files_db.dart";
|
||||
import "package:photos/events/files_updated_event.dart";
|
||||
import "package:photos/events/local_photos_updated_event.dart";
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import 'package:photos/models/file/file.dart';
|
||||
import "package:photos/models/file_load_result.dart";
|
||||
import "package:photos/models/gallery_type.dart";
|
||||
import "package:photos/models/search/hierarchical/hierarchical_search_filter.dart";
|
||||
import "package:photos/models/search/hierarchical/location_filter.dart";
|
||||
import "package:photos/models/selected_files.dart";
|
||||
import "package:photos/services/collections_service.dart";
|
||||
import "package:photos/services/filter/db_filters.dart";
|
||||
import "package:photos/services/location_service.dart";
|
||||
import "package:photos/states/location_screen_state.dart";
|
||||
import "package:photos/theme/colors.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/common/loading_widget.dart";
|
||||
import "package:photos/ui/components/buttons/icon_button_widget.dart";
|
||||
import "package:photos/ui/components/title_bar_title_widget.dart";
|
||||
import "package:photos/ui/components/title_bar_widget.dart";
|
||||
import "package:photos/ui/viewer/actions/file_selection_overlay_bar.dart";
|
||||
import "package:photos/ui/viewer/gallery/gallery.dart";
|
||||
import "package:photos/ui/viewer/gallery/gallery_app_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";
|
||||
import "package:photos/ui/viewer/gallery/state/search_filter_data_provider.dart";
|
||||
import "package:photos/ui/viewer/gallery/state/selection_state.dart";
|
||||
import "package:photos/ui/viewer/location/edit_location_sheet.dart";
|
||||
import "package:photos/utils/dialog_util.dart";
|
||||
|
||||
class LocationScreen extends StatelessWidget {
|
||||
class LocationScreen extends StatefulWidget {
|
||||
final String tagPrefix;
|
||||
const LocationScreen({this.tagPrefix = "", super.key});
|
||||
|
||||
@override
|
||||
State<LocationScreen> createState() => _LocationScreenState();
|
||||
}
|
||||
|
||||
class _LocationScreenState extends State<LocationScreen> {
|
||||
final selectedFiles = SelectedFiles();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final heightOfStatusBar = MediaQuery.of(context).viewPadding.top;
|
||||
const heightOfAppBar = 48.0;
|
||||
final locationTag =
|
||||
InheritedLocationScreenState.of(context).locationTagEntity.item;
|
||||
|
||||
return GalleryFilesState(
|
||||
child: Scaffold(
|
||||
appBar: const PreferredSize(
|
||||
preferredSize: Size(double.infinity, heightOfAppBar),
|
||||
child: TitleBarWidget(
|
||||
isSliver: false,
|
||||
isFlexibleSpaceDisabled: true,
|
||||
actionIcons: [LocationScreenPopUpMenu()],
|
||||
child: InheritedSearchFilterData(
|
||||
searchFilterDataProvider: SearchFilterDataProvider(
|
||||
initialGalleryFilter: LocationFilter(
|
||||
locationTag: locationTag,
|
||||
occurrence: kMostRelevantFilter,
|
||||
),
|
||||
),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height -
|
||||
(heightOfAppBar + heightOfStatusBar),
|
||||
width: double.infinity,
|
||||
child: LocationGalleryWidget(
|
||||
tagPrefix: tagPrefix,
|
||||
),
|
||||
child: Scaffold(
|
||||
appBar: PreferredSize(
|
||||
preferredSize: const Size(double.infinity, heightOfAppBar),
|
||||
child: GalleryAppBarWidget(
|
||||
GalleryType.locationTag,
|
||||
locationTag.name,
|
||||
selectedFiles,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LocationScreenPopUpMenu extends StatelessWidget {
|
||||
const LocationScreenPopUpMenu({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final textTheme = getEnteTextTheme(context);
|
||||
final colorScheme = getEnteColorScheme(context);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 4),
|
||||
child: Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
),
|
||||
child: PopupMenuButton(
|
||||
elevation: 2,
|
||||
offset: const Offset(10, 50),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
color: colorScheme.backgroundElevated2,
|
||||
child: const IconButtonWidget(
|
||||
icon: Icons.more_horiz,
|
||||
iconButtonType: IconButtonType.primary,
|
||||
disableGestureDetector: true,
|
||||
),
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem(
|
||||
value: "edit",
|
||||
child: Text(
|
||||
S.of(context).edit,
|
||||
style: textTheme.bodyBold,
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height -
|
||||
(heightOfAppBar + heightOfStatusBar),
|
||||
width: double.infinity,
|
||||
child: LocationGalleryWidget(
|
||||
tagPrefix: widget.tagPrefix,
|
||||
selectedFiles: selectedFiles,
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: () {},
|
||||
value: "delete",
|
||||
child: Text(
|
||||
S.of(context).deleteLocation,
|
||||
style: textTheme.bodyBold.copyWith(color: warning500),
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
onSelected: (value) async {
|
||||
if (value == "edit") {
|
||||
showEditLocationSheet(
|
||||
context,
|
||||
InheritedLocationScreenState.of(context).locationTagEntity,
|
||||
);
|
||||
} else if (value == "delete") {
|
||||
try {
|
||||
await LocationService.instance.deleteLocationTag(
|
||||
InheritedLocationScreenState.of(context).locationTagEntity.id,
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
} catch (e) {
|
||||
await showGenericErrorDialog(context: context, error: e);
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -135,7 +83,12 @@ class LocationScreenPopUpMenu extends StatelessWidget {
|
||||
|
||||
class LocationGalleryWidget extends StatefulWidget {
|
||||
final String tagPrefix;
|
||||
const LocationGalleryWidget({required this.tagPrefix, super.key});
|
||||
final SelectedFiles selectedFiles;
|
||||
const LocationGalleryWidget({
|
||||
required this.tagPrefix,
|
||||
required this.selectedFiles,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
State<LocationGalleryWidget> createState() => _LocationGalleryWidgetState();
|
||||
@@ -145,7 +98,6 @@ class _LocationGalleryWidgetState extends State<LocationGalleryWidget> {
|
||||
late final Future<FileLoadResult> fileLoadResult;
|
||||
late final List<EnteFile> allFilesWithLocation;
|
||||
|
||||
late Widget galleryHeaderWidget;
|
||||
final _selectedFiles = SelectedFiles();
|
||||
late final StreamSubscription<LocalPhotosUpdatedEvent> _filesUpdateEvent;
|
||||
@override
|
||||
@@ -183,8 +135,6 @@ class _LocationGalleryWidgetState extends State<LocationGalleryWidget> {
|
||||
});
|
||||
return value;
|
||||
});
|
||||
|
||||
galleryHeaderWidget = const GalleryHeaderWidget();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -243,13 +193,11 @@ class _LocationGalleryWidgetState extends State<LocationGalleryWidget> {
|
||||
Gallery(
|
||||
loadingWidget: Column(
|
||||
children: [
|
||||
galleryHeaderWidget,
|
||||
EnteLoadingWidget(
|
||||
color: getEnteColorScheme(context).strokeMuted,
|
||||
),
|
||||
],
|
||||
),
|
||||
header: galleryHeaderWidget,
|
||||
asyncLoader: (
|
||||
creationStartTime,
|
||||
creationEndTime, {
|
||||
@@ -274,10 +222,9 @@ class _LocationGalleryWidgetState extends State<LocationGalleryWidget> {
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Column(
|
||||
return const Column(
|
||||
children: [
|
||||
galleryHeaderWidget,
|
||||
const Expanded(
|
||||
Expanded(
|
||||
child: EnteLoadingWidget(),
|
||||
),
|
||||
],
|
||||
@@ -288,65 +235,3 @@ class _LocationGalleryWidgetState extends State<LocationGalleryWidget> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class GalleryHeaderWidget extends StatefulWidget {
|
||||
const GalleryHeaderWidget({super.key});
|
||||
|
||||
@override
|
||||
State<GalleryHeaderWidget> createState() => _GalleryHeaderWidgetState();
|
||||
}
|
||||
|
||||
class _GalleryHeaderWidgetState extends State<GalleryHeaderWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final locationName =
|
||||
InheritedLocationScreenState.of(context).locationTagEntity.item.name;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 20),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
key: ValueKey(locationName),
|
||||
width: double.infinity,
|
||||
child: TitleBarTitleWidget(
|
||||
title: locationName,
|
||||
onTap: () {
|
||||
showEditLocationSheet(
|
||||
context,
|
||||
InheritedLocationScreenState.of(context).locationTagEntity,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
ValueListenableBuilder(
|
||||
valueListenable: InheritedLocationScreenState.memoryCountNotifier,
|
||||
builder: (context, int? value, _) {
|
||||
if (value == null) {
|
||||
return RepaintBoundary(
|
||||
child: EnteLoadingWidget(
|
||||
size: 12,
|
||||
color: getEnteColorScheme(context).strokeMuted,
|
||||
alignment: Alignment.centerLeft,
|
||||
padding: 2.5,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Text(
|
||||
S
|
||||
.of(context)
|
||||
.memoryCount(value, NumberFormat().format(value)),
|
||||
style: getEnteTextTheme(context).smallMuted,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user