[mob][debug] To debug thumbnail not loading (#7036)
This commit is contained in:
@@ -9,12 +9,20 @@ import 'package:photos/theme/ente_theme.dart';
|
||||
import 'package:photos/ui/components/captioned_text_widget.dart';
|
||||
import 'package:photos/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/menu_item_widget/menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/toggle_switch_widget.dart';
|
||||
import 'package:photos/ui/notification/toast.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
import 'package:photos/ui/settings/debug/local_thumbnail_config_screen.dart';
|
||||
import 'package:photos/utils/navigation_util.dart';
|
||||
|
||||
class DebugSectionWidget extends StatelessWidget {
|
||||
class DebugSectionWidget extends StatefulWidget {
|
||||
const DebugSectionWidget({super.key});
|
||||
|
||||
@override
|
||||
State<DebugSectionWidget> createState() => _DebugSectionWidgetState();
|
||||
}
|
||||
|
||||
class _DebugSectionWidgetState extends State<DebugSectionWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpandableMenuItemWidget(
|
||||
@@ -27,6 +35,43 @@ class DebugSectionWidget extends StatelessWidget {
|
||||
Widget _getSectionOptions(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Show local ID over thumbnails",
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingWidget: ToggleSwitchWidget(
|
||||
value: () => localSettings.showLocalIDOverThumbnails,
|
||||
onChanged: () async {
|
||||
await localSettings.setShowLocalIDOverThumbnails(
|
||||
!localSettings.showLocalIDOverThumbnails,
|
||||
);
|
||||
setState(() {});
|
||||
showShortToast(
|
||||
context,
|
||||
localSettings.showLocalIDOverThumbnails
|
||||
? "Local IDs will be shown. Restart app."
|
||||
: "Local IDs hidden. Restart app.",
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Local thumbnail queue config",
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
await routeToPage(
|
||||
context,
|
||||
const LocalThumbnailConfigScreen(),
|
||||
);
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:photos/service_locator.dart';
|
||||
import 'package:photos/theme/ente_theme.dart';
|
||||
import 'package:photos/ui/components/title_bar_title_widget.dart';
|
||||
import 'package:photos/ui/notification/toast.dart';
|
||||
|
||||
class LocalThumbnailConfigScreen extends StatefulWidget {
|
||||
const LocalThumbnailConfigScreen({super.key});
|
||||
|
||||
@override
|
||||
State<LocalThumbnailConfigScreen> createState() =>
|
||||
_LocalThumbnailConfigScreenState();
|
||||
}
|
||||
|
||||
class _LocalThumbnailConfigScreenState
|
||||
extends State<LocalThumbnailConfigScreen> {
|
||||
static final Logger _logger = Logger("LocalThumbnailConfigScreen");
|
||||
|
||||
late TextEditingController _smallMaxConcurrentController;
|
||||
late TextEditingController _smallTimeoutController;
|
||||
late TextEditingController _smallMaxSizeController;
|
||||
late TextEditingController _largeMaxConcurrentController;
|
||||
late TextEditingController _largeTimeoutController;
|
||||
late TextEditingController _largeMaxSizeController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_initControllers();
|
||||
}
|
||||
|
||||
void _initControllers() {
|
||||
_smallMaxConcurrentController = TextEditingController(
|
||||
text: localSettings.smallQueueMaxConcurrent.toString(),
|
||||
);
|
||||
_smallTimeoutController = TextEditingController(
|
||||
text: localSettings.smallQueueTimeoutSeconds.toString(),
|
||||
);
|
||||
_smallMaxSizeController = TextEditingController(
|
||||
text: localSettings.smallQueueMaxSize.toString(),
|
||||
);
|
||||
_largeMaxConcurrentController = TextEditingController(
|
||||
text: localSettings.largeQueueMaxConcurrent.toString(),
|
||||
);
|
||||
_largeTimeoutController = TextEditingController(
|
||||
text: localSettings.largeQueueTimeoutSeconds.toString(),
|
||||
);
|
||||
_largeMaxSizeController = TextEditingController(
|
||||
text: localSettings.largeQueueMaxSize.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_smallMaxConcurrentController.dispose();
|
||||
_smallTimeoutController.dispose();
|
||||
_smallMaxSizeController.dispose();
|
||||
_largeMaxConcurrentController.dispose();
|
||||
_largeTimeoutController.dispose();
|
||||
_largeMaxSizeController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _saveSettings() async {
|
||||
try {
|
||||
// Validate and save small queue settings
|
||||
final smallMaxConcurrent =
|
||||
int.tryParse(_smallMaxConcurrentController.text);
|
||||
final smallTimeout = int.tryParse(_smallTimeoutController.text);
|
||||
final smallMaxSize = int.tryParse(_smallMaxSizeController.text);
|
||||
|
||||
// Validate and save large queue settings
|
||||
final largeMaxConcurrent =
|
||||
int.tryParse(_largeMaxConcurrentController.text);
|
||||
final largeTimeout = int.tryParse(_largeTimeoutController.text);
|
||||
final largeMaxSize = int.tryParse(_largeMaxSizeController.text);
|
||||
|
||||
if (smallMaxConcurrent == null ||
|
||||
smallTimeout == null ||
|
||||
smallMaxSize == null ||
|
||||
largeMaxConcurrent == null ||
|
||||
largeTimeout == null ||
|
||||
largeMaxSize == null) {
|
||||
showShortToast(context, "Please enter valid numbers");
|
||||
return;
|
||||
}
|
||||
|
||||
// Basic validation - just ensure positive numbers
|
||||
if (smallMaxConcurrent < 1 ||
|
||||
largeMaxConcurrent < 1 ||
|
||||
smallTimeout < 1 ||
|
||||
largeTimeout < 1 ||
|
||||
smallMaxSize < 1 ||
|
||||
largeMaxSize < 1) {
|
||||
showShortToast(
|
||||
context,
|
||||
"All values must be positive numbers",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await localSettings.setSmallQueueMaxConcurrent(smallMaxConcurrent);
|
||||
await localSettings.setSmallQueueTimeout(smallTimeout);
|
||||
await localSettings.setSmallQueueMaxSize(smallMaxSize);
|
||||
await localSettings.setLargeQueueMaxConcurrent(largeMaxConcurrent);
|
||||
await localSettings.setLargeQueueTimeout(largeTimeout);
|
||||
await localSettings.setLargeQueueMaxSize(largeMaxSize);
|
||||
|
||||
_logger.info(
|
||||
"Local thumbnail queue settings updated:\n"
|
||||
"Small Queue - MaxConcurrent: $smallMaxConcurrent, Timeout: ${smallTimeout}s, MaxSize: $smallMaxSize\n"
|
||||
"Large Queue - MaxConcurrent: $largeMaxConcurrent, Timeout: ${largeTimeout}s, MaxSize: $largeMaxSize",
|
||||
);
|
||||
|
||||
if (mounted) {
|
||||
showShortToast(
|
||||
context,
|
||||
"Settings saved. Restart app to apply changes.",
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
showShortToast(context, "Error saving settings");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _resetToDefaults() async {
|
||||
await localSettings.resetThumbnailQueueSettings();
|
||||
setState(() {
|
||||
_smallMaxConcurrentController.text = "15";
|
||||
_smallTimeoutController.text = "60";
|
||||
_smallMaxSizeController.text = "200";
|
||||
_largeMaxConcurrentController.text = "5";
|
||||
_largeTimeoutController.text = "60";
|
||||
_largeMaxSizeController.text = "200";
|
||||
});
|
||||
|
||||
_logger.info(
|
||||
"Local thumbnail queue settings reset to defaults:\n"
|
||||
"Small Queue - MaxConcurrent: 15, Timeout: 60s, MaxSize: 200\n"
|
||||
"Large Queue - MaxConcurrent: 5, Timeout: 60s, MaxSize: 200",
|
||||
);
|
||||
|
||||
if (mounted) {
|
||||
showShortToast(
|
||||
context,
|
||||
"Reset to defaults. Restart app to apply changes.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildNumberField({
|
||||
required String label,
|
||||
required String hint,
|
||||
required TextEditingController controller,
|
||||
}) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: getEnteTextTheme(context).body.copyWith(
|
||||
color: getEnteColorScheme(context).textMuted,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
TextField(
|
||||
controller: controller,
|
||||
keyboardType: TextInputType.number,
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
decoration: InputDecoration(
|
||||
hintText: hint,
|
||||
hintStyle: getEnteTextTheme(context).body.copyWith(
|
||||
color: getEnteColorScheme(context).textFaint,
|
||||
),
|
||||
filled: true,
|
||||
fillColor: getEnteColorScheme(context).fillFaint,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 8,
|
||||
),
|
||||
),
|
||||
style: getEnteTextTheme(context).body,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = getEnteColorScheme(context);
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
color: colorScheme.backdropBase,
|
||||
child: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
const TitleBarTitleWidget(
|
||||
title: "Local Thumbnail Queue Config",
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Small Local Thumbnail Queue",
|
||||
style: getEnteTextTheme(context).largeBold,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
"Used when gallery grid has 4 or more columns",
|
||||
style: getEnteTextTheme(context).small.copyWith(
|
||||
color: colorScheme.textMuted,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildNumberField(
|
||||
label: "Max Concurrent Tasks",
|
||||
hint: "Default: 15",
|
||||
controller: _smallMaxConcurrentController,
|
||||
),
|
||||
_buildNumberField(
|
||||
label: "Timeout (seconds)",
|
||||
hint: "Default: 60",
|
||||
controller: _smallTimeoutController,
|
||||
),
|
||||
_buildNumberField(
|
||||
label: "Max Queue Size",
|
||||
hint: "Default: 200",
|
||||
controller: _smallMaxSizeController,
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
Text(
|
||||
"Large Local Thumbnail Queue",
|
||||
style: getEnteTextTheme(context).largeBold,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
"Used when gallery grid has less than 4 columns",
|
||||
style: getEnteTextTheme(context).small.copyWith(
|
||||
color: colorScheme.textMuted,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildNumberField(
|
||||
label: "Max Concurrent Tasks",
|
||||
hint: "Default: 5",
|
||||
controller: _largeMaxConcurrentController,
|
||||
),
|
||||
_buildNumberField(
|
||||
label: "Timeout (seconds)",
|
||||
hint: "Default: 60",
|
||||
controller: _largeTimeoutController,
|
||||
),
|
||||
_buildNumberField(
|
||||
label: "Max Queue Size",
|
||||
hint: "Default: 200",
|
||||
controller: _largeMaxSizeController,
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: _saveSettings,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: colorScheme.primary700,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
"Save Settings",
|
||||
style: getEnteTextTheme(context).bodyBold.copyWith(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: TextButton(
|
||||
onPressed: _resetToDefaults,
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: colorScheme.primary700,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(
|
||||
color: colorScheme.strokeMuted,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
"Reset to Defaults",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.fillFaint,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.info_outline,
|
||||
size: 20,
|
||||
color: colorScheme.textMuted,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"Changes require app restart to take effect",
|
||||
style: getEnteTextTheme(context).small.copyWith(
|
||||
color: colorScheme.textMuted,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import 'package:photos/models/file/extensions/file_props.dart';
|
||||
import 'package:photos/models/file/file.dart';
|
||||
import 'package:photos/models/file/file_type.dart';
|
||||
import 'package:photos/models/file/trash_file.dart';
|
||||
import 'package:photos/service_locator.dart';
|
||||
import 'package:photos/services/collections_service.dart';
|
||||
import 'package:photos/services/favorites_service.dart';
|
||||
import 'package:photos/ui/viewer/file/file_icons_widget.dart';
|
||||
@@ -98,13 +99,20 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
|
||||
if (!mounted && _localThumbnailQueueTaskId != null) {
|
||||
if (widget.thumbnailSize == thumbnailLargeSize) {
|
||||
largeLocalThumbnailQueue.removeTask(_localThumbnailQueueTaskId!);
|
||||
_logger.info(
|
||||
"Cancelled large thumbnail task: $_localThumbnailQueueTaskId",
|
||||
);
|
||||
} else if (widget.thumbnailSize == thumbnailSmallSize) {
|
||||
smallLocalThumbnailQueue.removeTask(_localThumbnailQueueTaskId!);
|
||||
_logger.info(
|
||||
"Cancelled small thumbnail task: $_localThumbnailQueueTaskId",
|
||||
);
|
||||
}
|
||||
}
|
||||
// Cancel request only if the widget has been unmounted
|
||||
if (!mounted && widget.file.isRemoteFile && !_hasLoadedThumbnail) {
|
||||
removePendingGetThumbnailRequestIfAny(widget.file);
|
||||
_logger.info("Cancelled thumbnail request for " + widget.file.tag);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -117,17 +125,42 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
|
||||
}
|
||||
}
|
||||
|
||||
static final smallLocalThumbnailQueue = TaskQueue<String>(
|
||||
maxConcurrentTasks: 15,
|
||||
taskTimeout: const Duration(minutes: 1),
|
||||
maxQueueSize: 200,
|
||||
);
|
||||
static final TaskQueue<String> smallLocalThumbnailQueue = _initSmallQueue();
|
||||
static final TaskQueue<String> largeLocalThumbnailQueue = _initLargeQueue();
|
||||
|
||||
static final largeLocalThumbnailQueue = TaskQueue<String>(
|
||||
maxConcurrentTasks: 5,
|
||||
taskTimeout: const Duration(minutes: 1),
|
||||
maxQueueSize: 200,
|
||||
);
|
||||
static TaskQueue<String> _initSmallQueue() {
|
||||
final maxConcurrent = localSettings.smallQueueMaxConcurrent;
|
||||
final timeoutSeconds = localSettings.smallQueueTimeoutSeconds;
|
||||
final maxSize = localSettings.smallQueueMaxSize;
|
||||
|
||||
_logger.info(
|
||||
"Initializing Small Local Thumbnail Queue - "
|
||||
"MaxConcurrent: $maxConcurrent, Timeout: ${timeoutSeconds}s, MaxSize: $maxSize",
|
||||
);
|
||||
|
||||
return TaskQueue<String>(
|
||||
maxConcurrentTasks: maxConcurrent,
|
||||
taskTimeout: Duration(seconds: timeoutSeconds),
|
||||
maxQueueSize: maxSize,
|
||||
);
|
||||
}
|
||||
|
||||
static TaskQueue<String> _initLargeQueue() {
|
||||
final maxConcurrent = localSettings.largeQueueMaxConcurrent;
|
||||
final timeoutSeconds = localSettings.largeQueueTimeoutSeconds;
|
||||
final maxSize = localSettings.largeQueueMaxSize;
|
||||
|
||||
_logger.info(
|
||||
"Initializing Large Local Thumbnail Queue - "
|
||||
"MaxConcurrent: $maxConcurrent, Timeout: ${timeoutSeconds}s, MaxSize: $maxSize",
|
||||
);
|
||||
|
||||
return TaskQueue<String>(
|
||||
maxConcurrentTasks: maxConcurrent,
|
||||
taskTimeout: Duration(seconds: timeoutSeconds),
|
||||
maxQueueSize: maxSize,
|
||||
);
|
||||
}
|
||||
|
||||
///Assigned dimension will be the size of a grid item. The size will be
|
||||
///assigned to the side which is smaller in dimension.
|
||||
@@ -230,6 +263,32 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
|
||||
if (widget.shouldShowPinIcon) {
|
||||
viewChildren.add(const PinOverlayIcon());
|
||||
}
|
||||
if (localSettings.showLocalIDOverThumbnails &&
|
||||
widget.file.localID != null) {
|
||||
viewChildren.add(
|
||||
Positioned(
|
||||
bottom: 4,
|
||||
left: 4,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color.fromRGBO(0, 0, 0, 0.8),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: FittedBox(
|
||||
child: Text(
|
||||
"${widget.file.localID}",
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 8,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
@@ -311,9 +370,14 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
|
||||
_errorLoadingLocalThumbnail = true;
|
||||
if (e is WidgetUnmountedException) {
|
||||
// Widget was unmounted - this is expected behavior
|
||||
_logger.fine("Thumbnail loading cancelled: widget unmounted");
|
||||
_logger.fine(
|
||||
"Thumbnail loading cancelled: widget unmounted for localID: ${widget.file.localID}",
|
||||
);
|
||||
} else {
|
||||
_logger.warning("Could not load thumbnail from disk: ", e);
|
||||
_logger.warning(
|
||||
"Could not load thumbnail from disk for localID: ${widget.file.localID}",
|
||||
e,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -343,7 +407,7 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
|
||||
);
|
||||
if (retryAttempts <= _maxLocalThumbnailRetries) {
|
||||
_logger.warning(
|
||||
"Error getting local thumbnail for ${widget.file.displayName}, retrying (attempt $retryAttempts) in ${backoff.inMilliseconds} ms",
|
||||
"Error getting local thumbnail for ${widget.file.displayName} (localID: ${widget.file.localID}) due to ${e.runtimeType}, retrying (attempt $retryAttempts) in ${backoff.inMilliseconds} ms",
|
||||
e,
|
||||
);
|
||||
await Future.delayed(backoff); // Exponential backoff
|
||||
|
||||
@@ -41,6 +41,15 @@ class LocalSettings {
|
||||
"hide_shared_items_from_home_gallery";
|
||||
static const kCollectionViewType = "collection_view_type";
|
||||
static const kCollectionSortDirection = "collection_sort_direction";
|
||||
static const kShowLocalIDOverThumbnails = "show_local_id_over_thumbnails";
|
||||
|
||||
// Thumbnail queue configuration keys
|
||||
static const kSmallQueueMaxConcurrent = "small_queue_max_concurrent";
|
||||
static const kSmallQueueTimeout = "small_queue_timeout_seconds";
|
||||
static const kSmallQueueMaxSize = "small_queue_max_size";
|
||||
static const kLargeQueueMaxConcurrent = "large_queue_max_concurrent";
|
||||
static const kLargeQueueTimeout = "large_queue_timeout_seconds";
|
||||
static const kLargeQueueMaxSize = "large_queue_max_size";
|
||||
|
||||
final SharedPreferences _prefs;
|
||||
|
||||
@@ -217,4 +226,59 @@ class LocalSettings {
|
||||
|
||||
bool get hideSharedItemsFromHomeGallery =>
|
||||
_prefs.getBool(_hideSharedItemsFromHomeGalleryTag) ?? false;
|
||||
|
||||
bool get showLocalIDOverThumbnails =>
|
||||
_prefs.getBool(kShowLocalIDOverThumbnails) ?? false;
|
||||
|
||||
Future<void> setShowLocalIDOverThumbnails(bool value) async {
|
||||
await _prefs.setBool(kShowLocalIDOverThumbnails, value);
|
||||
}
|
||||
|
||||
// Thumbnail queue configuration - Small queue
|
||||
int get smallQueueMaxConcurrent => _prefs.getInt(kSmallQueueMaxConcurrent) ?? 15;
|
||||
|
||||
int get smallQueueTimeoutSeconds => _prefs.getInt(kSmallQueueTimeout) ?? 60;
|
||||
|
||||
int get smallQueueMaxSize => _prefs.getInt(kSmallQueueMaxSize) ?? 200;
|
||||
|
||||
Future<void> setSmallQueueMaxConcurrent(int value) async {
|
||||
await _prefs.setInt(kSmallQueueMaxConcurrent, value);
|
||||
}
|
||||
|
||||
Future<void> setSmallQueueTimeout(int seconds) async {
|
||||
await _prefs.setInt(kSmallQueueTimeout, seconds);
|
||||
}
|
||||
|
||||
Future<void> setSmallQueueMaxSize(int value) async {
|
||||
await _prefs.setInt(kSmallQueueMaxSize, value);
|
||||
}
|
||||
|
||||
// Thumbnail queue configuration - Large queue
|
||||
int get largeQueueMaxConcurrent => _prefs.getInt(kLargeQueueMaxConcurrent) ?? 5;
|
||||
|
||||
int get largeQueueTimeoutSeconds => _prefs.getInt(kLargeQueueTimeout) ?? 60;
|
||||
|
||||
int get largeQueueMaxSize => _prefs.getInt(kLargeQueueMaxSize) ?? 200;
|
||||
|
||||
Future<void> setLargeQueueMaxConcurrent(int value) async {
|
||||
await _prefs.setInt(kLargeQueueMaxConcurrent, value);
|
||||
}
|
||||
|
||||
Future<void> setLargeQueueTimeout(int seconds) async {
|
||||
await _prefs.setInt(kLargeQueueTimeout, seconds);
|
||||
}
|
||||
|
||||
Future<void> setLargeQueueMaxSize(int value) async {
|
||||
await _prefs.setInt(kLargeQueueMaxSize, value);
|
||||
}
|
||||
|
||||
// Reset thumbnail queue settings to defaults
|
||||
Future<void> resetThumbnailQueueSettings() async {
|
||||
await _prefs.remove(kSmallQueueMaxConcurrent);
|
||||
await _prefs.remove(kSmallQueueTimeout);
|
||||
await _prefs.remove(kSmallQueueMaxSize);
|
||||
await _prefs.remove(kLargeQueueMaxConcurrent);
|
||||
await _prefs.remove(kLargeQueueTimeout);
|
||||
await _prefs.remove(kLargeQueueMaxSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
- Ashil: Add new section (show local ID & config local thumb queue) in debug section in settings to help in debugging thumbnail not loading issue.
|
||||
- Ashil: Revert diskLoadDeferDuration to 80ms (Fixes local thumbnails taking ~1 sec to load on scrolling gallery)
|
||||
- Ashil: Revert diskLoadDeferDuration to 500ms (Was 80ms before but fixes local thumbnail taking very long to load or never loading)
|
||||
- Ashil: Revert increase in cache extent for gallery - to check if thumbnail not loading regression resolves
|
||||
|
||||
Reference in New Issue
Block a user