Merge branch 'main' into horizontal_grid
This commit is contained in:
commit
0545d401d6
8
lib/generated/intl/messages_en.dart
generated
8
lib/generated/intl/messages_en.dart
generated
|
@ -832,9 +832,13 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"noExifData": MessageLookupByLibrary.simpleMessage("No EXIF data"),
|
||||
"noHiddenPhotosOrVideos":
|
||||
MessageLookupByLibrary.simpleMessage("No hidden photos or videos"),
|
||||
"noImagesWithLocation":
|
||||
MessageLookupByLibrary.simpleMessage("No images with location"),
|
||||
"noPhotosAreBeingBackedUpRightNow":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"No photos are being backed up right now"),
|
||||
"noPhotosFoundHere":
|
||||
MessageLookupByLibrary.simpleMessage("No photos found here"),
|
||||
"noRecoveryKey":
|
||||
MessageLookupByLibrary.simpleMessage("No recovery key?"),
|
||||
"noRecoveryKeyNoDecryption": MessageLookupByLibrary.simpleMessage(
|
||||
|
@ -1367,6 +1371,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"You\'ve no duplicate files that can be cleared"),
|
||||
"youveNoFilesInThisAlbumThatCanBeDeleted":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"You\'ve no files in this album that can be deleted")
|
||||
"You\'ve no files in this album that can be deleted"),
|
||||
"zoomOutToSeePhotos":
|
||||
MessageLookupByLibrary.simpleMessage("Zoom out to see photos")
|
||||
};
|
||||
}
|
||||
|
|
30
lib/generated/l10n.dart
generated
30
lib/generated/l10n.dart
generated
|
@ -7415,6 +7415,36 @@ class S {
|
|||
);
|
||||
}
|
||||
|
||||
/// `No photos found here`
|
||||
String get noPhotosFoundHere {
|
||||
return Intl.message(
|
||||
'No photos found here',
|
||||
name: 'noPhotosFoundHere',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Zoom out to see photos`
|
||||
String get zoomOutToSeePhotos {
|
||||
return Intl.message(
|
||||
'Zoom out to see photos',
|
||||
name: 'zoomOutToSeePhotos',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `No images with location`
|
||||
String get noImagesWithLocation {
|
||||
return Intl.message(
|
||||
'No images with location',
|
||||
name: 'noImagesWithLocation',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Unpin album`
|
||||
String get unpinAlbum {
|
||||
return Intl.message(
|
||||
|
|
|
@ -1084,6 +1084,9 @@
|
|||
"addSelected": "Add selected",
|
||||
"addFromDevice": "Add from device",
|
||||
"addPhotos": "Add photos",
|
||||
"noPhotosFoundHere": "No photos found here",
|
||||
"zoomOutToSeePhotos": "Zoom out to see photos",
|
||||
"noImagesWithLocation": "No images with location",
|
||||
"unpinAlbum": "Unpin album",
|
||||
"pinAlbum": "Pin album",
|
||||
"create": "Create",
|
||||
|
|
|
@ -6,6 +6,7 @@ import "package:logging/logging.dart";
|
|||
import "package:photos/core/event_bus.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.dart";
|
||||
import "package:photos/models/file_load_result.dart";
|
||||
import "package:photos/models/gallery_type.dart";
|
||||
|
@ -133,12 +134,12 @@ class _MapPullUpGalleryState extends State<MapPullUpGallery> {
|
|||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"No photos found here",
|
||||
S.of(context).noPhotosFoundHere,
|
||||
style: textTheme.large,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
"Zoom out to see photos",
|
||||
S.of(context).zoomOutToSeePhotos,
|
||||
style: textTheme.smallFaint,
|
||||
)
|
||||
],
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_map/flutter_map.dart';
|
||||
import "package:latlong2/latlong.dart";
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/generated/l10n.dart";
|
||||
import "package:photos/models/file.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/common/loading_widget.dart";
|
||||
|
@ -108,7 +109,7 @@ class _MapScreenState extends State<MapScreen> {
|
|||
debugPrint("Info for map: center $center, initialZoom $initialZoom");
|
||||
}
|
||||
} else {
|
||||
showShortToast(context, "No images with location");
|
||||
showShortToast(context, S.of(context).noImagesWithLocation);
|
||||
}
|
||||
|
||||
setState(() {
|
||||
|
|
|
@ -70,14 +70,12 @@ class _DetailPageState extends State<DetailPage> {
|
|||
final _logger = Logger("DetailPageState");
|
||||
bool _shouldDisableScroll = false;
|
||||
List<File>? _files;
|
||||
PageController? _pageController;
|
||||
late PageController _pageController;
|
||||
int _selectedIndex = 0;
|
||||
bool _hasPageChanged = false;
|
||||
bool _hasLoadedTillStart = false;
|
||||
bool _hasLoadedTillEnd = false;
|
||||
bool _shouldHideAppBar = false;
|
||||
GlobalKey<FadingAppBarState>? _appBarKey;
|
||||
GlobalKey<FadingBottomBarState>? _bottomBarKey;
|
||||
final _enableFullScreenNotifier = ValueNotifier(false);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -87,11 +85,12 @@ class _DetailPageState extends State<DetailPage> {
|
|||
]; // Make a copy since we append preceding and succeeding entries to this
|
||||
_selectedIndex = widget.config.selectedIndex;
|
||||
_preloadEntries();
|
||||
_pageController = PageController(initialPage: _selectedIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// _pageController?.dispose();
|
||||
_pageController.dispose();
|
||||
SystemChrome.setEnabledSystemUIMode(
|
||||
SystemUiMode.manual,
|
||||
overlays: SystemUiOverlay.values,
|
||||
|
@ -110,8 +109,6 @@ class _DetailPageState extends State<DetailPage> {
|
|||
_files!.length.toString() +
|
||||
" files .",
|
||||
);
|
||||
_appBarKey = GlobalKey<FadingAppBarState>();
|
||||
_bottomBarKey = GlobalKey<FadingBottomBarState>();
|
||||
return Scaffold(
|
||||
appBar: FadingAppBar(
|
||||
_files![_selectedIndex],
|
||||
|
@ -119,34 +116,31 @@ class _DetailPageState extends State<DetailPage> {
|
|||
Configuration.instance.getUserID(),
|
||||
100,
|
||||
widget.config.mode == DetailPageMode.full,
|
||||
key: _appBarKey,
|
||||
enableFullScreenNotifier: _enableFullScreenNotifier,
|
||||
),
|
||||
extendBodyBehindAppBar: true,
|
||||
resizeToAvoidBottomInset: false,
|
||||
body: Center(
|
||||
child: Stack(
|
||||
children: [
|
||||
_buildPageView(),
|
||||
_buildPageView(context),
|
||||
FadingBottomBar(
|
||||
_files![_selectedIndex],
|
||||
_onEditFileRequested,
|
||||
widget.config.mode == DetailPageMode.minimalistic,
|
||||
onFileRemoved: _onFileRemoved,
|
||||
userID: Configuration.instance.getUserID(),
|
||||
key: _bottomBarKey,
|
||||
enableFullScreenNotifier: _enableFullScreenNotifier,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// backgroundColor: Theme.of(context).colorScheme.onPrimary,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPageView() {
|
||||
Widget _buildPageView(BuildContext context) {
|
||||
final bottomPadding = MediaQuery.of(context).padding.bottom;
|
||||
_logger.info("Building with " + _selectedIndex.toString());
|
||||
// todo: perf.. do we always need to create new controller?
|
||||
_pageController = PageController(initialPage: _selectedIndex);
|
||||
return PageView.builder(
|
||||
itemBuilder: (context, index) {
|
||||
final file = _files![index];
|
||||
|
@ -161,18 +155,21 @@ class _DetailPageState extends State<DetailPage> {
|
|||
});
|
||||
}
|
||||
},
|
||||
playbackCallback: (isPlaying) {
|
||||
_shouldHideAppBar = isPlaying;
|
||||
Future.delayed(Duration.zero, () {
|
||||
_toggleFullScreen();
|
||||
});
|
||||
},
|
||||
//Noticed that when the video is seeked, the video pops and moves the
|
||||
//seek bar along with it and it happens when bottomPadding is 0. So we
|
||||
//don't toggle full screen for cases where this issue happens.
|
||||
playbackCallback: bottomPadding != 0
|
||||
? (isPlaying) {
|
||||
Future.delayed(Duration.zero, () {
|
||||
_toggleFullScreen();
|
||||
});
|
||||
}
|
||||
: null,
|
||||
backgroundDecoration: const BoxDecoration(color: Colors.black),
|
||||
);
|
||||
_preloadFiles(index);
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
_shouldHideAppBar = !_shouldHideAppBar;
|
||||
_toggleFullScreen();
|
||||
},
|
||||
child: content,
|
||||
|
@ -195,18 +192,13 @@ class _DetailPageState extends State<DetailPage> {
|
|||
}
|
||||
|
||||
void _toggleFullScreen() {
|
||||
if (_shouldHideAppBar) {
|
||||
_appBarKey!.currentState!.hide();
|
||||
_bottomBarKey!.currentState!.hide();
|
||||
} else {
|
||||
_appBarKey!.currentState!.show();
|
||||
_bottomBarKey!.currentState!.show();
|
||||
}
|
||||
Future.delayed(Duration.zero, () {
|
||||
_enableFullScreenNotifier.value = !_enableFullScreenNotifier.value;
|
||||
|
||||
Future.delayed(const Duration(milliseconds: 125), () {
|
||||
SystemChrome.setEnabledSystemUIMode(
|
||||
//to hide status bar?
|
||||
SystemUiMode.manual,
|
||||
overlays: _shouldHideAppBar ? [] : SystemUiOverlay.values,
|
||||
overlays: _enableFullScreenNotifier.value ? [] : SystemUiOverlay.values,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -249,7 +241,7 @@ class _DetailPageState extends State<DetailPage> {
|
|||
final length = files.length;
|
||||
files.addAll(_files!);
|
||||
_files = files;
|
||||
_pageController!.jumpToPage(length);
|
||||
_pageController.jumpToPage(length);
|
||||
_selectedIndex = length;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ class FadingAppBar extends StatefulWidget implements PreferredSizeWidget {
|
|||
final double height;
|
||||
final bool shouldShowActions;
|
||||
final int? userID;
|
||||
final ValueNotifier<bool> enableFullScreenNotifier;
|
||||
|
||||
const FadingAppBar(
|
||||
this.file,
|
||||
|
@ -43,6 +44,7 @@ class FadingAppBar extends StatefulWidget implements PreferredSizeWidget {
|
|||
this.userID,
|
||||
this.height,
|
||||
this.shouldShowActions, {
|
||||
required this.enableFullScreenNotifier,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
|
@ -55,51 +57,41 @@ class FadingAppBar extends StatefulWidget implements PreferredSizeWidget {
|
|||
|
||||
class FadingAppBarState extends State<FadingAppBar> {
|
||||
final _logger = Logger("FadingAppBar");
|
||||
bool _shouldHide = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomAppBar(
|
||||
IgnorePointer(
|
||||
ignoring: _shouldHide,
|
||||
child: AnimatedOpacity(
|
||||
opacity: _shouldHide ? 0 : 1,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Colors.black.withOpacity(0.72),
|
||||
Colors.black.withOpacity(0.6),
|
||||
Colors.transparent,
|
||||
],
|
||||
stops: const [0, 0.2, 1],
|
||||
ValueListenableBuilder(
|
||||
valueListenable: widget.enableFullScreenNotifier,
|
||||
builder: (context, bool isFullScreen, _) {
|
||||
return IgnorePointer(
|
||||
ignoring: isFullScreen,
|
||||
child: AnimatedOpacity(
|
||||
opacity: isFullScreen ? 0 : 1,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Colors.black.withOpacity(0.72),
|
||||
Colors.black.withOpacity(0.6),
|
||||
Colors.transparent,
|
||||
],
|
||||
stops: const [0, 0.2, 1],
|
||||
),
|
||||
),
|
||||
child: _buildAppBar(),
|
||||
),
|
||||
),
|
||||
child: _buildAppBar(),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
Size.fromHeight(Platform.isAndroid ? 80 : 96),
|
||||
);
|
||||
}
|
||||
|
||||
void hide() {
|
||||
setState(() {
|
||||
_shouldHide = true;
|
||||
});
|
||||
}
|
||||
|
||||
void show() {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_shouldHide = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
AppBar _buildAppBar() {
|
||||
debugPrint("building app bar");
|
||||
|
||||
|
|
|
@ -20,12 +20,14 @@ class FadingBottomBar extends StatefulWidget {
|
|||
final Function(File) onFileRemoved;
|
||||
final bool showOnlyInfoButton;
|
||||
final int? userID;
|
||||
final ValueNotifier<bool> enableFullScreenNotifier;
|
||||
|
||||
const FadingBottomBar(
|
||||
this.file,
|
||||
this.onEditRequested,
|
||||
this.showOnlyInfoButton, {
|
||||
required this.onFileRemoved,
|
||||
required this.enableFullScreenNotifier,
|
||||
this.userID,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
@ -35,7 +37,6 @@ class FadingBottomBar extends StatefulWidget {
|
|||
}
|
||||
|
||||
class FadingBottomBarState extends State<FadingBottomBar> {
|
||||
bool _shouldHide = false;
|
||||
final GlobalKey shareButtonKey = GlobalKey();
|
||||
|
||||
@override
|
||||
|
@ -43,18 +44,6 @@ class FadingBottomBarState extends State<FadingBottomBar> {
|
|||
return _getBottomBar();
|
||||
}
|
||||
|
||||
void hide() {
|
||||
setState(() {
|
||||
_shouldHide = true;
|
||||
});
|
||||
}
|
||||
|
||||
void show() {
|
||||
setState(() {
|
||||
_shouldHide = false;
|
||||
});
|
||||
}
|
||||
|
||||
void safeRefresh() {
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
|
@ -155,60 +144,65 @@ class FadingBottomBarState extends State<FadingBottomBar> {
|
|||
);
|
||||
}
|
||||
final safeAreaBottomPadding = MediaQuery.of(context).padding.bottom * .5;
|
||||
return IgnorePointer(
|
||||
ignoring: _shouldHide,
|
||||
child: AnimatedOpacity(
|
||||
opacity: _shouldHide ? 0 : 1,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
Colors.black.withOpacity(0.6),
|
||||
Colors.black.withOpacity(0.72),
|
||||
],
|
||||
stops: const [0, 0.8, 1],
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(bottom: safeAreaBottomPadding),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
widget.file.caption?.isNotEmpty ?? false
|
||||
? Padding(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
16,
|
||||
28,
|
||||
16,
|
||||
12,
|
||||
),
|
||||
child: Text(
|
||||
widget.file.caption!,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 4,
|
||||
style: getEnteTextTheme(context)
|
||||
.small
|
||||
.copyWith(color: textBaseDark),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: children,
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: widget.enableFullScreenNotifier,
|
||||
builder: (BuildContext context, bool isFullScreen, _) {
|
||||
return IgnorePointer(
|
||||
ignoring: isFullScreen,
|
||||
child: AnimatedOpacity(
|
||||
opacity: isFullScreen ? 0 : 1,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
Colors.black.withOpacity(0.6),
|
||||
Colors.black.withOpacity(0.72),
|
||||
],
|
||||
stops: const [0, 0.8, 1],
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(bottom: safeAreaBottomPadding),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
widget.file.caption?.isNotEmpty ?? false
|
||||
? Padding(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
16,
|
||||
28,
|
||||
16,
|
||||
12,
|
||||
),
|
||||
child: Text(
|
||||
widget.file.caption!,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 4,
|
||||
style: getEnteTextTheme(context)
|
||||
.small
|
||||
.copyWith(color: textBaseDark),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: children,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -111,12 +111,8 @@ class _VideoWidgetState extends State<VideoWidget> {
|
|||
|
||||
@override
|
||||
void dispose() {
|
||||
if (_videoPlayerController != null) {
|
||||
_videoPlayerController!.dispose();
|
||||
}
|
||||
if (_chewieController != null) {
|
||||
_chewieController!.dispose();
|
||||
}
|
||||
_videoPlayerController?.dispose();
|
||||
_chewieController?.dispose();
|
||||
if (_wakeLockEnabledHere) {
|
||||
unawaited(
|
||||
Wakelock.enabled.then((isEnabled) {
|
||||
|
|
Loading…
Reference in a new issue