temp
This commit is contained in:
@@ -4,6 +4,7 @@ import "package:flutter/widgets.dart";
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/models/file/file.dart";
|
||||
import "package:photos/models/selected_files.dart";
|
||||
import "package:photos/ui/viewer/gallery/component/group/lazy_group_gallery.dart";
|
||||
|
||||
class LastSelectedFileByDragging extends InheritedWidget {
|
||||
///Check if this should updates on didUpdateWidget. If so, use a state varaible
|
||||
@@ -63,6 +64,7 @@ class _PointerProviderState extends State<PointerProvider> {
|
||||
int prevSelectedFileIndex = -1;
|
||||
int currentSelectedFileIndex = -1;
|
||||
final _logger = Logger("PointerProvider");
|
||||
final _groupGalleryGlobalKey = GlobalKey();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -125,42 +127,47 @@ class _PointerProviderState extends State<PointerProvider> {
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
pointer = Pointer.of(context);
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
pointer.onTapStreamController.add(pointer.pointerPosition);
|
||||
},
|
||||
onLongPress: () {
|
||||
_isFingerOnScreenSinceLongPress = true;
|
||||
pointer.onLongPressStreamController.add(pointer.pointerPosition);
|
||||
},
|
||||
onHorizontalDragUpdate: (details) {
|
||||
onDragToSelect(details.localPosition);
|
||||
},
|
||||
child: Listener(
|
||||
onPointerMove: (event) {
|
||||
pointer.pointerPosition = event.localPosition;
|
||||
return GroupGalleryGlobalKey(
|
||||
globalKey: _groupGalleryGlobalKey,
|
||||
child: GestureDetector(
|
||||
key: _groupGalleryGlobalKey,
|
||||
onTap: () {
|
||||
pointer.onTapStreamController.add(pointer.pointerPosition);
|
||||
},
|
||||
onLongPress: () {
|
||||
_isFingerOnScreenSinceLongPress = true;
|
||||
pointer.onLongPressStreamController
|
||||
.add(pointer.pointerPosition);
|
||||
},
|
||||
onHorizontalDragUpdate: (details) {
|
||||
onDragToSelect(details.localPosition);
|
||||
},
|
||||
child: Listener(
|
||||
onPointerMove: (event) {
|
||||
pointer.pointerPosition = event.localPosition;
|
||||
|
||||
//onHorizontalDragUpdate is not called when dragging after
|
||||
//long press without lifting finger. This is for handling only
|
||||
//this case.
|
||||
if (_isFingerOnScreenSinceLongPress &&
|
||||
(event.localDelta.dx.abs() > 0 &&
|
||||
event.localDelta.dy.abs() > 0)) {
|
||||
onDragToSelect(event.localPosition);
|
||||
}
|
||||
},
|
||||
onPointerDown: (event) {
|
||||
pointer.pointerPosition = event.localPosition;
|
||||
},
|
||||
onPointerUp: (event) {
|
||||
_isFingerOnScreenSinceLongPress = false;
|
||||
_isDragging = false;
|
||||
pointer.upOffsetStreamController.add(event.localPosition);
|
||||
//onHorizontalDragUpdate is not called when dragging after
|
||||
//long press without lifting finger. This is for handling only
|
||||
//this case.
|
||||
if (_isFingerOnScreenSinceLongPress &&
|
||||
(event.localDelta.dx.abs() > 0 &&
|
||||
event.localDelta.dy.abs() > 0)) {
|
||||
onDragToSelect(event.localPosition);
|
||||
}
|
||||
},
|
||||
onPointerDown: (event) {
|
||||
pointer.pointerPosition = event.localPosition;
|
||||
},
|
||||
onPointerUp: (event) {
|
||||
_isFingerOnScreenSinceLongPress = false;
|
||||
_isDragging = false;
|
||||
pointer.upOffsetStreamController.add(event.localPosition);
|
||||
|
||||
LastSelectedFileByDragging.of(context).index.value = -1;
|
||||
currentSelectedFileIndex = -1;
|
||||
},
|
||||
child: widget.child,
|
||||
LastSelectedFileByDragging.of(context).index.value = -1;
|
||||
currentSelectedFileIndex = -1;
|
||||
},
|
||||
child: widget.child,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import 'dart:math' show max;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import "package:photos/models/file/file.dart";
|
||||
import "package:photos/models/selected_files.dart";
|
||||
import "package:photos/states/pointer_provider.dart";
|
||||
import 'package:photos/ui/huge_listview/draggable_scrollbar.dart';
|
||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||
|
||||
@@ -14,6 +17,10 @@ typedef HugeListViewErrorBuilder = Widget Function(
|
||||
);
|
||||
|
||||
class HugeListView<T> extends StatefulWidget {
|
||||
final List<EnteFile> files;
|
||||
|
||||
final SelectedFiles? selectedFiles;
|
||||
|
||||
/// A [ScrollablePositionedList] controller for jumping or scrolling to an item.
|
||||
final ItemScrollController? controller;
|
||||
|
||||
@@ -66,6 +73,8 @@ class HugeListView<T> extends StatefulWidget {
|
||||
|
||||
const HugeListView({
|
||||
Key? key,
|
||||
required this.files,
|
||||
required this.selectedFiles,
|
||||
this.controller,
|
||||
required this.startIndex,
|
||||
required this.totalCount,
|
||||
@@ -167,30 +176,62 @@ class HugeListViewState<T> extends State<HugeListView<T>> {
|
||||
currentFirstIndex: _currentFirst(),
|
||||
isEnabled: widget.isDraggableScrollbarEnabled,
|
||||
padding: widget.thumbPadding,
|
||||
child: ScrollablePositionedList.builder(
|
||||
physics: widget.disableScroll
|
||||
? const NeverScrollableScrollPhysics()
|
||||
: const BouncingScrollPhysics(),
|
||||
itemScrollController: widget.controller,
|
||||
itemPositionsListener: listener,
|
||||
initialScrollIndex: widget.startIndex,
|
||||
itemCount: max(widget.totalCount, 0),
|
||||
itemBuilder: (context, index) {
|
||||
return ExcludeSemantics(
|
||||
child: widget.itemBuilder(context, index),
|
||||
);
|
||||
},
|
||||
child: LastSelectedFileByDragging(
|
||||
filesInGroup: widget.files,
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return PointerProvider(
|
||||
selectedFiles: widget.selectedFiles!,
|
||||
files: widget.files,
|
||||
child: ScrollablePositionedList.builder(
|
||||
physics: widget.disableScroll
|
||||
? const NeverScrollableScrollPhysics()
|
||||
: const BouncingScrollPhysics(),
|
||||
itemScrollController: widget.controller,
|
||||
itemPositionsListener: listener,
|
||||
initialScrollIndex: widget.startIndex,
|
||||
itemCount: max(widget.totalCount, 0),
|
||||
itemBuilder: (context, index) {
|
||||
return ExcludeSemantics(
|
||||
child: widget.itemBuilder(context, index),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
itemCount: max(widget.totalCount, 0),
|
||||
itemBuilder: (context, index) {
|
||||
return ExcludeSemantics(
|
||||
child: widget.itemBuilder(context, index),
|
||||
: widget.selectedFiles != null
|
||||
? LastSelectedFileByDragging(
|
||||
filesInGroup: widget.files,
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return PointerProvider(
|
||||
selectedFiles: widget.selectedFiles!,
|
||||
files: widget.files,
|
||||
child: ListView.builder(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
itemCount: max(widget.totalCount, 0),
|
||||
itemBuilder: (context, index) {
|
||||
return ExcludeSemantics(
|
||||
child: widget.itemBuilder(context, index),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
itemCount: max(widget.totalCount, 0),
|
||||
itemBuilder: (context, index) {
|
||||
return ExcludeSemantics(
|
||||
child: widget.itemBuilder(context, index),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Jump to the [position] in the list. [position] is between 0.0 (first item) and 1.0 (last item), practically currentIndex / totalCount.
|
||||
|
||||
@@ -7,7 +7,6 @@ import 'package:photos/core/constants.dart';
|
||||
import 'package:photos/events/files_updated_event.dart';
|
||||
import 'package:photos/models/file/file.dart';
|
||||
import 'package:photos/models/selected_files.dart';
|
||||
import "package:photos/states/pointer_provider.dart";
|
||||
import 'package:photos/theme/ente_theme.dart';
|
||||
import "package:photos/ui/viewer/gallery/component/grid/place_holder_grid_view_widget.dart";
|
||||
import "package:photos/ui/viewer/gallery/component/group/group_gallery.dart";
|
||||
@@ -62,7 +61,6 @@ class _LazyGroupGalleryState extends State<LazyGroupGallery> {
|
||||
late StreamSubscription<FilesUpdatedEvent>? _reloadEventSubscription;
|
||||
late StreamSubscription<int> _currentIndexSubscription;
|
||||
bool? _shouldRender;
|
||||
final _groupGalleryGlobalKey = GlobalKey();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -236,39 +234,21 @@ class _LazyGroupGalleryState extends State<LazyGroupGallery> {
|
||||
],
|
||||
),
|
||||
widget.selectedFiles != null
|
||||
? LastSelectedFileByDragging(
|
||||
filesInGroup: _filesInGroup,
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return PointerProvider(
|
||||
selectedFiles: widget.selectedFiles!,
|
||||
files: _filesInGroup,
|
||||
child: GroupGalleryGlobalKey(
|
||||
globalKey: _groupGalleryGlobalKey,
|
||||
child: SizedBox(
|
||||
key: _groupGalleryGlobalKey,
|
||||
child: _shouldRender!
|
||||
? GroupGallery(
|
||||
photoGridSize: widget.photoGridSize,
|
||||
files: _filesInGroup,
|
||||
tag: widget.tag,
|
||||
asyncLoader: widget.asyncLoader,
|
||||
selectedFiles: widget.selectedFiles,
|
||||
limitSelectionToOne:
|
||||
widget.limitSelectionToOne,
|
||||
)
|
||||
// todo: perf eval should we have separate PlaceHolder for Groups
|
||||
// instead of creating a large cached view
|
||||
: PlaceHolderGridViewWidget(
|
||||
_filesInGroup.length,
|
||||
widget.photoGridSize,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
? _shouldRender!
|
||||
? GroupGallery(
|
||||
photoGridSize: widget.photoGridSize,
|
||||
files: _filesInGroup,
|
||||
tag: widget.tag,
|
||||
asyncLoader: widget.asyncLoader,
|
||||
selectedFiles: widget.selectedFiles,
|
||||
limitSelectionToOne: widget.limitSelectionToOne,
|
||||
)
|
||||
// todo: perf eval should we have separate PlaceHolder for Groups
|
||||
// instead of creating a large cached view
|
||||
: PlaceHolderGridViewWidget(
|
||||
_filesInGroup.length,
|
||||
widget.photoGridSize,
|
||||
)
|
||||
: _shouldRender!
|
||||
? GroupGallery(
|
||||
photoGridSize: widget.photoGridSize,
|
||||
|
||||
@@ -24,7 +24,7 @@ particular group of files.
|
||||
If a group has more than 400 files, LazyGroupGallery internally divides the
|
||||
group into multiple grid views during rendering.
|
||||
*/
|
||||
class MultipleGroupsGalleryView extends StatelessWidget {
|
||||
class MultipleGroupsGalleryView extends StatefulWidget {
|
||||
final ItemScrollController itemScroller;
|
||||
final List<List<EnteFile>> groupedFiles;
|
||||
final bool disableScroll;
|
||||
@@ -66,31 +66,42 @@ class MultipleGroupsGalleryView extends StatelessWidget {
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
State<MultipleGroupsGalleryView> createState() =>
|
||||
_MultipleGroupsGalleryViewState();
|
||||
}
|
||||
|
||||
class _MultipleGroupsGalleryViewState extends State<MultipleGroupsGalleryView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final filesInGroup =
|
||||
widget.groupedFiles.expand((element) => element).toList();
|
||||
final gType = GalleryContextState.of(context)!.type;
|
||||
|
||||
return HugeListView<List<EnteFile>>(
|
||||
controller: itemScroller,
|
||||
files: filesInGroup,
|
||||
selectedFiles: widget.selectedFiles,
|
||||
controller: widget.itemScroller,
|
||||
startIndex: 0,
|
||||
totalCount: groupedFiles.length,
|
||||
isDraggableScrollbarEnabled: groupedFiles.length > 10,
|
||||
disableScroll: disableScroll,
|
||||
isScrollablePositionedList: isScrollablePositionedList,
|
||||
totalCount: widget.groupedFiles.length,
|
||||
isDraggableScrollbarEnabled: widget.groupedFiles.length > 10,
|
||||
disableScroll: widget.disableScroll,
|
||||
isScrollablePositionedList: widget.isScrollablePositionedList,
|
||||
waitBuilder: (_) {
|
||||
return const EnteLoadingWidget();
|
||||
},
|
||||
emptyResultBuilder: (_) {
|
||||
final List<Widget> children = [];
|
||||
if (header != null) {
|
||||
children.add(header!);
|
||||
if (widget.header != null) {
|
||||
children.add(widget.header!);
|
||||
}
|
||||
children.add(
|
||||
Expanded(
|
||||
child: emptyState,
|
||||
child: widget.emptyState,
|
||||
),
|
||||
);
|
||||
if (footer != null) {
|
||||
children.add(footer!);
|
||||
if (widget.footer != null) {
|
||||
children.add(widget.footer!);
|
||||
}
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
@@ -100,60 +111,63 @@ class MultipleGroupsGalleryView extends StatelessWidget {
|
||||
itemBuilder: (context, index) {
|
||||
Widget gallery;
|
||||
gallery = LazyGroupGallery(
|
||||
groupedFiles[index],
|
||||
widget.groupedFiles[index],
|
||||
index,
|
||||
reloadEvent,
|
||||
removalEventTypes,
|
||||
asyncLoader,
|
||||
selectedFiles,
|
||||
tagPrefix,
|
||||
widget.reloadEvent,
|
||||
widget.removalEventTypes,
|
||||
widget.asyncLoader,
|
||||
widget.selectedFiles,
|
||||
widget.tagPrefix,
|
||||
Bus.instance
|
||||
.on<GalleryIndexUpdatedEvent>()
|
||||
.where((event) => event.tag == tagPrefix)
|
||||
.where((event) => event.tag == widget.tagPrefix)
|
||||
.map((event) => event.index),
|
||||
enableFileGrouping,
|
||||
showSelectAllByDefault,
|
||||
logTag: logTag,
|
||||
widget.enableFileGrouping,
|
||||
widget.showSelectAllByDefault,
|
||||
logTag: widget.logTag,
|
||||
photoGridSize: LocalSettings.instance.getPhotoGridSize(),
|
||||
limitSelectionToOne: limitSelectionToOne,
|
||||
limitSelectionToOne: widget.limitSelectionToOne,
|
||||
);
|
||||
if (header != null && index == 0) {
|
||||
gallery = Column(children: [header!, gallery]);
|
||||
if (widget.header != null && index == 0) {
|
||||
gallery = Column(children: [widget.header!, gallery]);
|
||||
}
|
||||
if (footer != null && index == groupedFiles.length - 1) {
|
||||
gallery = Column(children: [gallery, footer!]);
|
||||
if (widget.footer != null && index == widget.groupedFiles.length - 1) {
|
||||
gallery = Column(children: [gallery, widget.footer!]);
|
||||
}
|
||||
return gallery;
|
||||
},
|
||||
labelTextBuilder: (int index) {
|
||||
try {
|
||||
final EnteFile file = groupedFiles[index][0];
|
||||
final EnteFile file = widget.groupedFiles[index][0];
|
||||
if (gType == GroupType.size) {
|
||||
return file.fileSize != null
|
||||
? convertBytesToReadableFormat(file.fileSize!)
|
||||
: "";
|
||||
}
|
||||
|
||||
return DateFormat.yMMM(Localizations.localeOf(context).languageCode)
|
||||
.format(
|
||||
return DateFormat.yMMM(
|
||||
Localizations.localeOf(context).languageCode,
|
||||
).format(
|
||||
DateTime.fromMicrosecondsSinceEpoch(
|
||||
file.creationTime!,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
logger.severe("label text builder failed", e);
|
||||
widget.logger.severe("label text builder failed", e);
|
||||
return "";
|
||||
}
|
||||
},
|
||||
thumbBackgroundColor:
|
||||
Theme.of(context).colorScheme.galleryThumbBackgroundColor,
|
||||
thumbDrawColor: Theme.of(context).colorScheme.galleryThumbDrawColor,
|
||||
thumbPadding: header != null
|
||||
thumbPadding: widget.header != null
|
||||
? const EdgeInsets.only(top: 60)
|
||||
: const EdgeInsets.all(0),
|
||||
bottomSafeArea: scrollBottomSafeArea,
|
||||
bottomSafeArea: widget.scrollBottomSafeArea,
|
||||
firstShown: (int firstIndex) {
|
||||
Bus.instance.fire(GalleryIndexUpdatedEvent(tagPrefix, firstIndex));
|
||||
Bus.instance.fire(
|
||||
GalleryIndexUpdatedEvent(widget.tagPrefix, firstIndex),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user