Initial project import and stabilization baseline
This commit is contained in:
102
lib/features/home/unsplash_background.dart
Normal file
102
lib/features/home/unsplash_background.dart
Normal file
@@ -0,0 +1,102 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../data/services/unsplash_service.dart';
|
||||
import '../../providers.dart';
|
||||
|
||||
/// Renders a securely rotating background using Unsplash API.
|
||||
class UnsplashBackground extends ConsumerStatefulWidget {
|
||||
const UnsplashBackground({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<UnsplashBackground> createState() => _UnsplashBackgroundState();
|
||||
}
|
||||
|
||||
class _UnsplashBackgroundState extends ConsumerState<UnsplashBackground> {
|
||||
List<String> _urls = [];
|
||||
int _currentIndex = 0;
|
||||
Timer? _rotationTimer;
|
||||
String? _lastKeyword;
|
||||
int? _lastRotationHours;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_initDataAndTimer();
|
||||
}
|
||||
|
||||
void _initDataAndTimer() async {
|
||||
final settings = ref.read(settingsProvider);
|
||||
_lastKeyword = settings.unsplashKeyword;
|
||||
_lastRotationHours = settings.unsplashRotationHours;
|
||||
|
||||
await _fetchImages(settings.unsplashKeyword);
|
||||
_startTimer(settings.unsplashRotationHours);
|
||||
}
|
||||
|
||||
Future<void> _fetchImages(String keyword) async {
|
||||
final urls = await UnsplashService.instance.fetchLandscapeBackgrounds(keyword);
|
||||
if (urls.isNotEmpty && mounted) {
|
||||
setState(() {
|
||||
_urls = urls;
|
||||
_currentIndex = 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _startTimer(int hours) {
|
||||
_rotationTimer?.cancel();
|
||||
if (hours <= 0) return;
|
||||
|
||||
_rotationTimer = Timer.periodic(Duration(hours: hours), (_) {
|
||||
if (_urls.isNotEmpty && mounted) {
|
||||
setState(() {
|
||||
_currentIndex = (_currentIndex + 1) % _urls.length;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_rotationTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final settings = ref.watch(settingsProvider);
|
||||
|
||||
// Watch for config changes
|
||||
if (settings.unsplashKeyword != _lastKeyword) {
|
||||
_lastKeyword = settings.unsplashKeyword;
|
||||
// Re-fetch images organically
|
||||
_fetchImages(settings.unsplashKeyword);
|
||||
}
|
||||
|
||||
if (settings.unsplashRotationHours != _lastRotationHours) {
|
||||
_lastRotationHours = settings.unsplashRotationHours;
|
||||
_startTimer(settings.unsplashRotationHours);
|
||||
}
|
||||
|
||||
if (!settings.useUnsplashBackground || _urls.isEmpty) {
|
||||
return const SizedBox.shrink(); // Fallback to flat background handled underneath
|
||||
}
|
||||
|
||||
return AnimatedSwitcher(
|
||||
duration: const Duration(seconds: 3),
|
||||
transitionBuilder: (child, animation) => FadeTransition(opacity: animation, child: child),
|
||||
child: Image.network(
|
||||
_urls[_currentIndex],
|
||||
key: ValueKey(_urls[_currentIndex]),
|
||||
fit: BoxFit.cover,
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
// Soft opacity behind the MainScreen's dark glass vignette
|
||||
color: Colors.black.withValues(alpha: 0.5),
|
||||
colorBlendMode: BlendMode.darken,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user