Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve image caching #1105

Merged
merged 4 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/core/enums/image_caching_mode.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
enum ImageCachingMode {
aggressive,
relaxed;
}
2 changes: 2 additions & 0 deletions lib/core/enums/local_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ enum LocalSettings {
// Advanced Settings
userFormat(name: 'user_format', key: 'userFormat', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced),
communityFormat(name: 'community_format', key: 'communityFormat', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced),
imageCachingMode(name: 'setting_advanced_image_caching_mode', key: 'imageCachingMode', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced),

/// -------------------------- Post Page Related Settings --------------------------
// Comment Related Settings
Expand Down Expand Up @@ -286,6 +287,7 @@ extension LocalizationExt on AppLocalizations {
'hideTopBarOnScroll': hideTopBarOnScroll,
'userFormat': userFormat,
'communityFormat': communityFormat,
'imageCachingMode': imageCachingMode,
'defaultCommentSortType': defaultCommentSortType,
'collapseParentCommentBodyOnGesture': collapseParentCommentBodyOnGesture,
'showCommentActionButtons': showCommentActionButtons,
Expand Down
20 changes: 20 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,26 @@
"@hot": {},
"image": "Image",
"@image": {},
"imageCachingMode": "Image Caching Mode",
"@imageCachingMode": {
"description": "Title for setting related to image caching mode"
},
"imageCachingModeAggressive": "Aggressively cache images (uses more memory)",
"@imageCachingModeAggressive": {
"description": "Long description for aggressive image caching mode"
},
"imageCachingModeAggressiveShort": "Aggressive",
"@imageCachingModeAggressiveShort": {
"description": "Short description for aggressive image caching mode"
},
"imageCachingModeRelaxed": "Let image caches expire (uses less memory but causes images to reload more often)",
"@imageCachingModeRelaxed": {
"description": "Long description for relaxed image caching mode"
},
"imageCachingModeRelaxedShort": "Relaxed",
"@imageCachingModeRelaxedShort": {
"description": "Short description for relaxed image caching mode"
},
"importExportSettings": "Import/Export Settings",
"@importExportSettings": {
"description": "Category for settings related to import and export."
Expand Down
34 changes: 34 additions & 0 deletions lib/settings/pages/general_settings_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:thunder/core/enums/browser_mode.dart';
import 'package:thunder/core/enums/full_name_separator.dart';
import 'package:thunder/core/enums/image_caching_mode.dart';

import 'package:thunder/core/enums/local_settings.dart';
import 'package:thunder/core/singletons/lemmy_client.dart';
Expand Down Expand Up @@ -102,6 +103,9 @@ class _GeneralSettingsPageState extends State<GeneralSettingsPage> with SingleTi
/// Defines the separator used to denote full commuity names
FullNameSeparator communitySeparator = FullNameSeparator.dot;

/// Defines the image caching mode
ImageCachingMode imageCachingMode = ImageCachingMode.relaxed;

SortType defaultSortType = DEFAULT_SORT_TYPE;

void setPreferences(attribute, value) async {
Expand Down Expand Up @@ -194,6 +198,10 @@ class _GeneralSettingsPageState extends State<GeneralSettingsPage> with SingleTi
await prefs.setString(LocalSettings.communityFormat.name, value);
setState(() => communitySeparator = FullNameSeparator.values.byName(value ?? FullNameSeparator.dot));
break;
case LocalSettings.imageCachingMode:
await prefs.setString(LocalSettings.imageCachingMode.name, value);
setState(() => imageCachingMode = ImageCachingMode.values.byName(value ?? ImageCachingMode.relaxed));
break;
}

if (context.mounted) {
Expand Down Expand Up @@ -236,6 +244,7 @@ class _GeneralSettingsPageState extends State<GeneralSettingsPage> with SingleTi

userSeparator = FullNameSeparator.values.byName(prefs.getString(LocalSettings.userFormat.name) ?? FullNameSeparator.at.name);
communitySeparator = FullNameSeparator.values.byName(prefs.getString(LocalSettings.communityFormat.name) ?? FullNameSeparator.dot.name);
imageCachingMode = ImageCachingMode.values.byName(prefs.getString(LocalSettings.imageCachingMode.name) ?? ImageCachingMode.relaxed.name);

showInAppUpdateNotification = prefs.getBool(LocalSettings.showInAppUpdateNotification.name) ?? false;
enableInboxNotifications = prefs.getBool(LocalSettings.enableInboxNotifications.name) ?? false;
Expand Down Expand Up @@ -641,6 +650,31 @@ class _GeneralSettingsPageState extends State<GeneralSettingsPage> with SingleTi
),
),
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: ListOption(
description: l10n.imageCachingMode,
micahmo marked this conversation as resolved.
Show resolved Hide resolved
value: ListPickerItem(
label: switch (imageCachingMode) {
ImageCachingMode.aggressive => l10n.imageCachingModeAggressiveShort,
ImageCachingMode.relaxed => l10n.imageCachingModeRelaxedShort,
},
payload: imageCachingMode,
capitalizeLabel: false,
),
options: [
ListPickerItem(icon: Icons.broken_image, label: l10n.imageCachingModeAggressive, payload: ImageCachingMode.aggressive, capitalizeLabel: false),
ListPickerItem(icon: Icons.broken_image_outlined, label: l10n.imageCachingModeRelaxed, payload: ImageCachingMode.relaxed, capitalizeLabel: false),
],
icon: switch (imageCachingMode) {
ImageCachingMode.aggressive => Icons.broken_image,
ImageCachingMode.relaxed => Icons.broken_image_outlined,
},
onChanged: (value) => setPreferences(LocalSettings.imageCachingMode, value.payload.name),
),
),
),

const SliverToBoxAdapter(child: SizedBox(height: 16.0)),
SliverToBoxAdapter(
Expand Down
9 changes: 6 additions & 3 deletions lib/shared/image_preview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import 'dart:typed_data';
import 'package:flutter/material.dart';

import 'package:extended_image/extended_image.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:thunder/core/enums/image_caching_mode.dart';
import 'package:thunder/thunder/bloc/thunder_bloc.dart';

import 'package:thunder/utils/image.dart';

Expand Down Expand Up @@ -82,6 +85,7 @@ class _ImagePreviewState extends State<ImagePreview> {
Widget imagePreview(BuildContext context) {
final ThemeData theme = Theme.of(context);
final AppLocalizations l10n = AppLocalizations.of(context)!;
final ThunderState thunderState = context.read<ThunderBloc>().state;

return Container(
clipBehavior: Clip.hardEdge,
Expand All @@ -108,8 +112,7 @@ class _ImagePreviewState extends State<ImagePreview> {
width: widget.width,
fit: BoxFit.cover,
cache: true,
clearMemoryCacheWhenDispose: false,
cacheMaxAge: const Duration(minutes: 1),
clearMemoryCacheWhenDispose: thunderState.imageCachingMode == ImageCachingMode.relaxed,
cacheWidth: ((MediaQuery.of(context).size.width - 24) * View.of(context).devicePixelRatio.ceil()).toInt(),
loadStateChanged: (state) {
if (state.extendedImageLoadState == LoadState.loading) {
Expand Down Expand Up @@ -141,7 +144,7 @@ class _ImagePreviewState extends State<ImagePreview> {
height: widget.height,
width: widget.width,
fit: BoxFit.cover,
clearMemoryCacheWhenDispose: true,
clearMemoryCacheWhenDispose: thunderState.imageCachingMode == ImageCachingMode.relaxed,
cacheWidth: ((MediaQuery.of(context).size.width - 24) * View.of(context).devicePixelRatio.ceil()).toInt(),
loadStateChanged: (state) {
if (state.extendedImageLoadState == LoadState.loading) {
Expand Down
8 changes: 6 additions & 2 deletions lib/shared/image_viewer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ import 'package:flutter/material.dart';

import 'package:extended_image/extended_image.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gal/gal.dart';
import 'package:share_plus/share_plus.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:thunder/core/enums/image_caching_mode.dart';
import 'package:thunder/shared/dialogs.dart';

import 'package:thunder/shared/snackbar.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:thunder/thunder/bloc/thunder_bloc.dart';
import 'package:thunder/utils/image.dart';

class ImageViewer extends StatefulWidget {
Expand Down Expand Up @@ -134,6 +137,8 @@ class _ImageViewerState extends State<ImageViewer> with TickerProviderStateMixin

@override
Widget build(BuildContext context) {
final ThunderState thunderState = context.read<ThunderBloc>().state;

AnimationController animationController = AnimationController(duration: const Duration(milliseconds: 140), vsync: this);
Function() animationListener = () {};
Animation? animation;
Expand Down Expand Up @@ -254,8 +259,7 @@ class _ImageViewerState extends State<ImageViewer> with TickerProviderStateMixin
mode: ExtendedImageMode.gesture,
extendedImageGestureKey: gestureKey,
cache: true,
clearMemoryCacheWhenDispose: false,
cacheMaxAge: const Duration(minutes: 1),
clearMemoryCacheWhenDispose: thunderState.imageCachingMode == ImageCachingMode.relaxed,
initGestureConfigHandler: (ExtendedImageState state) {
return GestureConfig(
minScale: 0.8,
Expand Down
6 changes: 4 additions & 2 deletions lib/shared/media_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:extended_image/extended_image.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lemmy_api_client/v3.dart';
import 'package:thunder/core/enums/image_caching_mode.dart';

import 'package:thunder/feed/bloc/feed_bloc.dart';
import 'package:thunder/post/enums/post_action.dart';
import 'package:thunder/thunder/bloc/thunder_bloc.dart';
import 'package:thunder/utils/links.dart';
import 'package:thunder/user/bloc/user_bloc.dart';
import 'package:thunder/core/enums/media_type.dart';
Expand Down Expand Up @@ -212,6 +214,7 @@ class _MediaViewState extends State<MediaView> with SingleTickerProviderStateMix

Widget previewImage(BuildContext context) {
final theme = Theme.of(context);
final ThunderState thunderState = context.read<ThunderBloc>().state;

double? height = widget.viewMode == ViewMode.compact ? 75 : (widget.showFullHeightImages ? widget.postView!.media.first.height : 150);
double width = widget.viewMode == ViewMode.compact ? 75 : MediaQuery.of(context).size.width - (widget.edgeToEdgeImages ? 0 : 24);
Expand All @@ -224,8 +227,7 @@ class _MediaViewState extends State<MediaView> with SingleTickerProviderStateMix
width: width,
fit: widget.viewMode == ViewMode.compact ? BoxFit.cover : BoxFit.fitWidth,
cache: true,
clearMemoryCacheWhenDispose: false,
cacheMaxAge: const Duration(minutes: 1),
clearMemoryCacheWhenDispose: thunderState.imageCachingMode == ImageCachingMode.relaxed,
cacheWidth: widget.viewMode == ViewMode.compact
? (75 * View.of(context).devicePixelRatio.ceil())
: ((MediaQuery.of(context).size.width - (widget.edgeToEdgeImages ? 0 : 24)) * View.of(context).devicePixelRatio.ceil()).toInt(),
Expand Down
4 changes: 2 additions & 2 deletions lib/shared/preview_image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';

import 'package:extended_image/extended_image.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:thunder/core/enums/image_caching_mode.dart';

import 'package:thunder/core/enums/view_mode.dart';
import 'package:thunder/thunder/bloc/thunder_bloc.dart';
Expand Down Expand Up @@ -55,8 +56,7 @@ class _PreviewImageState extends State<PreviewImage> with SingleTickerProviderSt
width: width,
fit: widget.viewMode == ViewMode.compact ? BoxFit.cover : BoxFit.fitWidth,
cache: true,
clearMemoryCacheWhenDispose: false,
cacheMaxAge: const Duration(minutes: 1),
clearMemoryCacheWhenDispose: state.imageCachingMode == ImageCachingMode.relaxed,
cacheWidth: widget.viewMode == ViewMode.compact ? (75 * View.of(context).devicePixelRatio.ceil()) : ((MediaQuery.of(context).size.width - 24) * View.of(context).devicePixelRatio.ceil()).toInt(),
loadStateChanged: (ExtendedImageState state) {
switch (state.extendedImageLoadState) {
Expand Down
3 changes: 3 additions & 0 deletions lib/thunder/bloc/thunder_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:thunder/core/enums/custom_theme_type.dart';
import 'package:thunder/core/enums/fab_action.dart';
import 'package:thunder/core/enums/font_scale.dart';
import 'package:thunder/core/enums/full_name_separator.dart';
import 'package:thunder/core/enums/image_caching_mode.dart';
import 'package:thunder/core/enums/local_settings.dart';
import 'package:thunder/core/enums/nested_comment_indicator.dart';
import 'package:thunder/core/enums/post_body_view_type.dart';
Expand Down Expand Up @@ -115,6 +116,7 @@ class ThunderBloc extends Bloc<ThunderEvent, ThunderState> {
String? appLanguageCode = prefs.getString(LocalSettings.appLanguageCode.name) ?? 'en';
FullNameSeparator userSeparator = FullNameSeparator.values.byName(prefs.getString(LocalSettings.userFormat.name) ?? FullNameSeparator.at.name);
FullNameSeparator communitySeparator = FullNameSeparator.values.byName(prefs.getString(LocalSettings.communityFormat.name) ?? FullNameSeparator.dot.name);
ImageCachingMode imageCachingMode = ImageCachingMode.values.byName(prefs.getString(LocalSettings.imageCachingMode.name) ?? ImageCachingMode.relaxed.name);
bool hideTopBarOnScroll = prefs.getBool(LocalSettings.hideTopBarOnScroll.name) ?? false;

BrowserMode browserMode = BrowserMode.values.byName(prefs.getString(LocalSettings.browserMode.name) ?? BrowserMode.customTabs.name);
Expand Down Expand Up @@ -247,6 +249,7 @@ class ThunderBloc extends Bloc<ThunderEvent, ThunderState> {
appLanguageCode: appLanguageCode,
userSeparator: userSeparator,
communitySeparator: communitySeparator,
imageCachingMode: imageCachingMode,
hideTopBarOnScroll: hideTopBarOnScroll,

/// -------------------------- Feed Post Related Settings --------------------------
Expand Down
5 changes: 5 additions & 0 deletions lib/thunder/bloc/thunder_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class ThunderState extends Equatable {
this.scoreCounters = false,
this.userSeparator = FullNameSeparator.at,
this.communitySeparator = FullNameSeparator.dot,
this.imageCachingMode = ImageCachingMode.relaxed,
this.hideTopBarOnScroll = false,

/// -------------------------- Feed Post Related Settings --------------------------
Expand Down Expand Up @@ -162,6 +163,7 @@ class ThunderState extends Equatable {
final String? appLanguageCode;
final FullNameSeparator userSeparator;
final FullNameSeparator communitySeparator;
final ImageCachingMode imageCachingMode;
final bool hideTopBarOnScroll;

/// -------------------------- Feed Post Related Settings --------------------------
Expand Down Expand Up @@ -298,6 +300,7 @@ class ThunderState extends Equatable {
bool? scoreCounters,
FullNameSeparator? userSeparator,
FullNameSeparator? communitySeparator,
ImageCachingMode? imageCachingMode,
bool? hideTopBarOnScroll,

/// -------------------------- Feed Post Related Settings --------------------------
Expand Down Expand Up @@ -427,6 +430,7 @@ class ThunderState extends Equatable {
appLanguageCode: appLanguageCode ?? this.appLanguageCode,
userSeparator: userSeparator ?? this.userSeparator,
communitySeparator: communitySeparator ?? this.communitySeparator,
imageCachingMode: imageCachingMode ?? this.imageCachingMode,
hideTopBarOnScroll: hideTopBarOnScroll ?? this.hideTopBarOnScroll,

/// -------------------------- Feed Post Related Settings --------------------------
Expand Down Expand Up @@ -561,6 +565,7 @@ class ThunderState extends Equatable {
enableInboxNotifications,
userSeparator,
communitySeparator,
imageCachingMode,

/// -------------------------- Feed Post Related Settings --------------------------
/// Compact Related Settings
Expand Down
Loading