Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 3 additions & 0 deletions lib/domain/interfaces/config_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 10 additions & 1 deletion lib/infrastructure/services/json_config_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -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",

Expand Down
2 changes: 2 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -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",

Expand Down
12 changes: 12 additions & 0 deletions lib/l10n/app_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
7 changes: 7 additions & 0 deletions lib/l10n/app_localizations_de.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
6 changes: 6 additions & 0 deletions lib/l10n/app_localizations_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
15 changes: 15 additions & 0 deletions lib/ui/screens/settings_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class SettingsScreen extends StatefulWidget {
class _SettingsScreenState extends State<SettingsScreen> with WidgetsBindingObserver {
late int _slideDurationMinutes;
late double _transitionDurationSeconds;
late bool _blurBorders;
late String _syncType;
late TextEditingController _nextcloudUrlController;
late int _syncIntervalMinutes;
Expand Down Expand Up @@ -94,6 +95,7 @@ class _SettingsScreenState extends State<SettingsScreen> with WidgetsBindingObse
final config = context.read<ConfigProvider>();
_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;
Expand Down Expand Up @@ -204,6 +206,7 @@ class _SettingsScreenState extends State<SettingsScreen> 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;
Expand Down Expand Up @@ -313,6 +316,18 @@ class _SettingsScreenState extends State<SettingsScreen> 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),

Expand Down
1 change: 1 addition & 0 deletions lib/ui/screens/slideshow_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,7 @@ class _SlideshowScreenState extends State<SlideshowScreen> 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
Expand Down
30 changes: 17 additions & 13 deletions lib/ui/widgets/photo_slide.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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(
Expand Down