From f7c651f560e0cb83b8800fe90dced6229f200e84 Mon Sep 17 00:00:00 2001 From: roman Date: Mon, 9 Mar 2026 10:07:30 +0100 Subject: [PATCH] Added the blur background option --- lib/domain/interfaces/config_provider.dart | 3 ++ .../services/json_config_service.dart | 11 ++++++- lib/l10n/app_de.arb | 2 ++ lib/l10n/app_en.arb | 2 ++ lib/l10n/app_localizations.dart | 12 ++++++++ lib/l10n/app_localizations_de.dart | 7 +++++ lib/l10n/app_localizations_en.dart | 6 ++++ lib/ui/screens/settings_screen.dart | 15 ++++++++++ lib/ui/screens/slideshow_screen.dart | 1 + lib/ui/widgets/photo_slide.dart | 30 +++++++++++-------- 10 files changed, 75 insertions(+), 14 deletions(-) diff --git a/lib/domain/interfaces/config_provider.dart b/lib/domain/interfaces/config_provider.dart index 6bf8051..f66f760 100644 --- a/lib/domain/interfaces/config_provider.dart +++ b/lib/domain/interfaces/config_provider.dart @@ -16,6 +16,9 @@ abstract class ConfigProvider extends ChangeNotifier { int get transitionDurationMs; // Fade transition duration set transitionDurationMs(int value); + + bool get blurBorders; // Blur borders outside image + set blurBorders(bool value); // Sync settings int get syncIntervalMinutes; // 0 = disabled, otherwise interval in minutes diff --git a/lib/infrastructure/services/json_config_service.dart b/lib/infrastructure/services/json_config_service.dart index b798b1f..ba472bc 100644 --- a/lib/infrastructure/services/json_config_service.dart +++ b/lib/infrastructure/services/json_config_service.dart @@ -113,7 +113,16 @@ class JsonConfigService extends ConfigProvider { set transitionDurationMs(int value) { _config['transition_duration_ms'] = value; } - + + @override + bool get blurBorders => _config['blur_borders'] ?? false; + + @override + set blurBorders(bool value) { + _config['blur_borders'] = value; + } + + // Sync settings @override int get syncIntervalMinutes => _config['sync_interval_minutes'] ?? 15; diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 9c09f73..c5c00f6 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -6,6 +6,8 @@ "sectionSlideshow": "Diashow", "slideDuration": "Anzeigedauer", "transitionDuration": "Überblendzeit", + "blurBorders": "Rand unscharf", + "blurBordersSubtitle": "Bild mit Unschärfe bis zum Bildschirmrand zeichnen", "unitMinutes": "Min", "unitSeconds": "Sek", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 300b167..66dfb8b 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -6,6 +6,8 @@ "sectionSlideshow": "Slideshow", "slideDuration": "Slide Duration", "transitionDuration": "Transition Duration", + "blurBorders": "Blur Borders", + "blurBordersSubtitle": "Extend image to screen size", "unitMinutes": "min", "unitSeconds": "sec", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 2982ac9..6ad9866 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -122,6 +122,18 @@ abstract class AppLocalizations { /// **'Transition Duration'** String get transitionDuration; + /// No description provided for @blurBorders. + /// + /// In en, this message translates to: + /// **'Blur Borders'** + String get blurBorders; + + /// No description provided for @blurBordersSubtitle. + /// + /// In en, this message translates to: + /// **'Extend image to screen size'** + String get blurBordersSubtitle; + /// No description provided for @unitMinutes. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 875fc4c..738ffc6 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -20,6 +20,13 @@ class AppLocalizationsDe extends AppLocalizations { @override String get transitionDuration => 'Überblendzeit'; + @override + String get blurBorders => 'Rand unscharf'; + + @override + String get blurBordersSubtitle => + 'Bild mit Unschärfe bis zum Bildschirmrand zeichnen'; + @override String get unitMinutes => 'Min'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index a1ce11a..5235770 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -20,6 +20,12 @@ class AppLocalizationsEn extends AppLocalizations { @override String get transitionDuration => 'Transition Duration'; + @override + String get blurBorders => 'Blur Borders'; + + @override + String get blurBordersSubtitle => 'Extend image to screen size'; + @override String get unitMinutes => 'min'; diff --git a/lib/ui/screens/settings_screen.dart b/lib/ui/screens/settings_screen.dart index c133a35..4ac48f7 100644 --- a/lib/ui/screens/settings_screen.dart +++ b/lib/ui/screens/settings_screen.dart @@ -27,6 +27,7 @@ class SettingsScreen extends StatefulWidget { class _SettingsScreenState extends State with WidgetsBindingObserver { late int _slideDurationMinutes; late double _transitionDurationSeconds; + late bool _blurBorders; late String _syncType; late TextEditingController _nextcloudUrlController; late int _syncIntervalMinutes; @@ -94,6 +95,7 @@ class _SettingsScreenState extends State with WidgetsBindingObse final config = context.read(); _slideDurationMinutes = (config.slideDurationSeconds / 60).round().clamp(1, 15); _transitionDurationSeconds = (config.transitionDurationMs / 1000.0).clamp(0.5, 5.0); + _blurBorders = config.blurBorders; // Default sync type: app_folder on Android, local_folder on Desktop final defaultSyncType = Platform.isAndroid ? 'app_folder' : 'local_folder'; _syncType = config.activeSourceType.isEmpty ? defaultSyncType : config.activeSourceType; @@ -204,6 +206,7 @@ class _SettingsScreenState extends State with WidgetsBindingObse config.slideDurationSeconds = _slideDurationMinutes * 60; config.transitionDurationMs = (_transitionDurationSeconds * 1000).round(); + config.blurBorders = _blurBorders; // app_folder and local_folder both use empty activeSourceType (no sync) final isLocalMode = _syncType == 'local_folder' || _syncType == 'app_folder'; config.activeSourceType = isLocalMode ? '' : _syncType; @@ -313,6 +316,18 @@ class _SettingsScreenState extends State with WidgetsBindingObse setState(() => _transitionDurationSeconds = value); }, ), + + const SizedBox(height: 16), + + SwitchListTile( + title: Text(AppLocalizations.of(context)!.blurBorders), + subtitle: Text(AppLocalizations.of(context)!.blurBordersSubtitle), + secondary: const Icon(Icons.blur_linear), + value: _blurBorders, + onChanged: (value) { + setState(() => _blurBorders = value); + }, + ), const SizedBox(height: 16), diff --git a/lib/ui/screens/slideshow_screen.dart b/lib/ui/screens/slideshow_screen.dart index 81b0941..ea5deed 100644 --- a/lib/ui/screens/slideshow_screen.dart +++ b/lib/ui/screens/slideshow_screen.dart @@ -623,6 +623,7 @@ class _SlideshowScreenState extends State with TickerProviderSt key: ValueKey(slide.photo.file.path), photo: slide.photo, screenSize: _screenSize!, + blurBorders: config.blurBorders, ); // Use slide animation for manual navigation, fade for auto-advance diff --git a/lib/ui/widgets/photo_slide.dart b/lib/ui/widgets/photo_slide.dart index df484ac..c3edb23 100644 --- a/lib/ui/widgets/photo_slide.dart +++ b/lib/ui/widgets/photo_slide.dart @@ -6,8 +6,9 @@ import '../../domain/models/photo_entry.dart'; class PhotoSlide extends StatelessWidget { final PhotoEntry photo; final Size screenSize; + final bool blurBorders; - const PhotoSlide({super.key, required this.photo, required this.screenSize}); + const PhotoSlide({super.key, required this.photo, required this.screenSize, required this.blurBorders}); /// Creates a ResizeImage provider optimized for the screen size. /// This significantly speeds up decoding on slower devices. @@ -27,23 +28,26 @@ class PhotoSlide extends StatelessWidget { Widget build(BuildContext context) { // Use ResizeImage for faster decoding - loads image at screen resolution final imageProvider = createOptimizedProvider(photo.file, screenSize); - + return Stack( fit: StackFit.expand, children: [ - // 1. Blurred Background - Image( - image: imageProvider, - fit: BoxFit.cover, - gaplessPlayback: true, - ), - BackdropFilter( - filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20), - child: Container( + if (blurBorders) ...[ + Image( + image: imageProvider, + fit: BoxFit.cover, + gaplessPlayback: true, + ), + BackdropFilter( + filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20), + child: Container( color: Colors.black.withOpacity(0.4), + ), + ), + ] else + Container( + color: Colors.black, ), - ), - // 2. Main Image Center( child: Image(