mirror of
https://github.com/immich-app/immich.git
synced 2025-06-03 05:34:32 -04:00
Improve scrolling performance in albums and search
This commit is contained in:
parent
87ca031335
commit
8440d9890c
@ -1,9 +1,12 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/draggable_scrollbar.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_list_v2/asset_grid_data_structure.dart';
|
||||||
|
import 'package:immich_mobile/modules/home/ui/asset_list_v2/immich_asset_grid.dart';
|
||||||
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
|
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
|
||||||
import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart';
|
import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart';
|
||||||
import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart';
|
import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart';
|
||||||
@ -12,12 +15,10 @@ import 'package:immich_mobile/modules/album/services/album.service.dart';
|
|||||||
import 'package:immich_mobile/modules/album/ui/album_action_outlined_button.dart';
|
import 'package:immich_mobile/modules/album/ui/album_action_outlined_button.dart';
|
||||||
import 'package:immich_mobile/modules/album/ui/album_viewer_appbar.dart';
|
import 'package:immich_mobile/modules/album/ui/album_viewer_appbar.dart';
|
||||||
import 'package:immich_mobile/modules/album/ui/album_viewer_editable_title.dart';
|
import 'package:immich_mobile/modules/album/ui/album_viewer_editable_title.dart';
|
||||||
import 'package:immich_mobile/modules/album/ui/album_viewer_thumbnail.dart';
|
|
||||||
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
|
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
|
||||||
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
|
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_sliver_persistent_app_bar_delegate.dart';
|
|
||||||
import 'package:immich_mobile/shared/views/immich_loading_overlay.dart';
|
import 'package:immich_mobile/shared/views/immich_loading_overlay.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ class AlbumViewerPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final appSettingService = ref.watch(appSettingsServiceProvider);
|
||||||
FocusNode titleFocusNode = useFocusNode();
|
FocusNode titleFocusNode = useFocusNode();
|
||||||
ScrollController scrollController = useScrollController();
|
ScrollController scrollController = useScrollController();
|
||||||
var albumInfo = ref.watch(sharedAlbumDetailProvider(albumId));
|
var albumInfo = ref.watch(sharedAlbumDetailProvider(albumId));
|
||||||
@ -188,34 +190,17 @@ class AlbumViewerPage extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildImageGrid(AlbumResponseDto albumInfo) {
|
Widget _buildImageGrid(AlbumResponseDto albumInfo) {
|
||||||
final appSettingService = ref.watch(appSettingsServiceProvider);
|
final assetsPerRow =
|
||||||
|
appSettingService.getSetting(AppSettingsEnum.tilesPerRow);
|
||||||
final bool showStorageIndicator =
|
final bool showStorageIndicator =
|
||||||
appSettingService.getSetting(AppSettingsEnum.storageIndicator);
|
appSettingService.getSetting(AppSettingsEnum.storageIndicator);
|
||||||
|
final renderList = assetsToRenderList(albumInfo.assets, assetsPerRow);
|
||||||
|
|
||||||
if (albumInfo.assets.isNotEmpty) {
|
return ImmichAssetGrid(
|
||||||
return SliverPadding(
|
assetsPerRow: assetsPerRow,
|
||||||
padding: const EdgeInsets.only(top: 10.0),
|
renderList: renderList,
|
||||||
sliver: SliverGrid(
|
showStorageIndicator: showStorageIndicator,
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
);
|
||||||
crossAxisCount:
|
|
||||||
appSettingService.getSetting(AppSettingsEnum.tilesPerRow),
|
|
||||||
crossAxisSpacing: 5.0,
|
|
||||||
mainAxisSpacing: 5,
|
|
||||||
),
|
|
||||||
delegate: SliverChildBuilderDelegate(
|
|
||||||
(BuildContext context, int index) {
|
|
||||||
return AlbumViewerThumbnail(
|
|
||||||
asset: albumInfo.assets[index],
|
|
||||||
assetList: albumInfo.assets,
|
|
||||||
showStorageIndicator: showStorageIndicator,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
childCount: albumInfo.assetCount,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return const SliverToBoxAdapter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildControlButton(AlbumResponseDto albumInfo) {
|
Widget _buildControlButton(AlbumResponseDto albumInfo) {
|
||||||
@ -248,29 +233,7 @@ class AlbumViewerPage extends HookConsumerWidget {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
titleFocusNode.unfocus();
|
titleFocusNode.unfocus();
|
||||||
},
|
},
|
||||||
child: DraggableScrollbar.semicircle(
|
child: _buildImageGrid(albumInfo),
|
||||||
backgroundColor: Theme.of(context).hintColor,
|
|
||||||
controller: scrollController,
|
|
||||||
heightScrollThumb: 48.0,
|
|
||||||
child: CustomScrollView(
|
|
||||||
controller: scrollController,
|
|
||||||
slivers: [
|
|
||||||
_buildHeader(albumInfo),
|
|
||||||
SliverPersistentHeader(
|
|
||||||
pinned: true,
|
|
||||||
delegate: ImmichSliverPersistentAppBarDelegate(
|
|
||||||
minHeight: 50,
|
|
||||||
maxHeight: 50,
|
|
||||||
child: Container(
|
|
||||||
color: Theme.of(context).scaffoldBackgroundColor,
|
|
||||||
child: _buildControlButton(albumInfo),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
_buildImageGrid(albumInfo)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,38 +1,10 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/modules/home/ui/asset_list_v2/asset_grid_data_structure.dart';
|
||||||
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
|
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
|
||||||
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
|
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
|
||||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
||||||
import 'package:openapi/api.dart';
|
|
||||||
|
|
||||||
enum RenderAssetGridElementType {
|
|
||||||
assetRow,
|
|
||||||
dayTitle,
|
|
||||||
monthTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
class RenderAssetGridRow {
|
|
||||||
final List<AssetResponseDto> assets;
|
|
||||||
|
|
||||||
RenderAssetGridRow(this.assets);
|
|
||||||
}
|
|
||||||
|
|
||||||
class RenderAssetGridElement {
|
|
||||||
final RenderAssetGridElementType type;
|
|
||||||
final RenderAssetGridRow? assetRow;
|
|
||||||
final String? title;
|
|
||||||
final DateTime date;
|
|
||||||
final List<AssetResponseDto>? relatedAssetList;
|
|
||||||
|
|
||||||
RenderAssetGridElement(
|
|
||||||
this.type, {
|
|
||||||
this.assetRow,
|
|
||||||
this.title,
|
|
||||||
required this.date,
|
|
||||||
this.relatedAssetList,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
final renderListProvider = StateProvider((ref) {
|
final renderListProvider = StateProvider((ref) {
|
||||||
var assetGroups = ref.watch(assetGroupByDateTimeProvider);
|
var assetGroups = ref.watch(assetGroupByDateTimeProvider);
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
|
enum RenderAssetGridElementType {
|
||||||
|
assetRow,
|
||||||
|
dayTitle,
|
||||||
|
monthTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
class RenderAssetGridRow {
|
||||||
|
final List<AssetResponseDto> assets;
|
||||||
|
|
||||||
|
RenderAssetGridRow(this.assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
class RenderAssetGridElement {
|
||||||
|
final RenderAssetGridElementType type;
|
||||||
|
final RenderAssetGridRow? assetRow;
|
||||||
|
final String? title;
|
||||||
|
final DateTime date;
|
||||||
|
final List<AssetResponseDto>? relatedAssetList;
|
||||||
|
|
||||||
|
RenderAssetGridElement(
|
||||||
|
this.type, {
|
||||||
|
this.assetRow,
|
||||||
|
this.title,
|
||||||
|
required this.date,
|
||||||
|
this.relatedAssetList,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
List<RenderAssetGridElement> assetsToRenderList(
|
||||||
|
List<AssetResponseDto> assets, int assetsPerRow) {
|
||||||
|
List<RenderAssetGridElement> elements = [];
|
||||||
|
|
||||||
|
int cursor = 0;
|
||||||
|
while (cursor < assets.length) {
|
||||||
|
int rowElements = min(assets.length - cursor, assetsPerRow);
|
||||||
|
final date = DateTime.parse(assets[cursor].createdAt);
|
||||||
|
|
||||||
|
final rowElement = RenderAssetGridElement(
|
||||||
|
RenderAssetGridElementType.assetRow,
|
||||||
|
date: date,
|
||||||
|
assetRow: RenderAssetGridRow(
|
||||||
|
assets.sublist(cursor, cursor + rowElements),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
elements.add(rowElement);
|
||||||
|
cursor += rowElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
}
|
@ -7,13 +7,13 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/src/widgets/framework.dart';
|
import 'package:flutter/src/widgets/framework.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/modules/home/providers/home_page_render_list_provider.dart';
|
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_list_v2/daily_title_text.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_list_v2/daily_title_text.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_list_v2/draggable_scrollbar_custom.dart';
|
import 'package:immich_mobile/modules/home/ui/asset_list_v2/draggable_scrollbar_custom.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||||
|
|
||||||
import '../thumbnail_image.dart';
|
import '../thumbnail_image.dart';
|
||||||
|
import 'asset_grid_data_structure.dart';
|
||||||
|
|
||||||
class ImmichAssetGrid extends HookConsumerWidget {
|
class ImmichAssetGrid extends HookConsumerWidget {
|
||||||
final ItemScrollController _itemScrollController = ItemScrollController();
|
final ItemScrollController _itemScrollController = ItemScrollController();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user