- _imageSize reset on image switch (wrong swap threshold on nav) - downsample caps both dims (tall images no longer full-res decode) - single _readImageSize instead of leaking loadingBuilder listeners - evict old downsample provider on full-res swap - remove imageCache.clear() that dropped live image (gallery flash)
115 lines
3.1 KiB
Dart
115 lines
3.1 KiB
Dart
import 'dart:io';
|
|
import 'package:flutter/material.dart';
|
|
|
|
class ImageManager extends ChangeNotifier {
|
|
static final ImageManager _instance = ImageManager._();
|
|
static ImageManager get instance => _instance;
|
|
ImageManager._();
|
|
|
|
static const _supportedExtensions = [
|
|
'png', 'jpg', 'jpeg', 'jfif', 'jpe', 'webp', 'bmp', 'gif', 'wbmp',
|
|
];
|
|
|
|
final List<String> _images = [];
|
|
int _currentIndex = 0;
|
|
bool _sortByName = false;
|
|
|
|
List<String> get images => List.unmodifiable(_images);
|
|
int get currentIndex => _currentIndex;
|
|
int get imageCount => _images.length;
|
|
bool get sortByName => _sortByName;
|
|
|
|
String get currentImagePath {
|
|
if (_images.isEmpty) return '';
|
|
return _images[_currentIndex];
|
|
}
|
|
|
|
/// Açılan resmin bulunduğu klasörü galeri olarak kurar (en yeni önce).
|
|
void setGalleryFromPaths(List<String> paths) {
|
|
String? anchor;
|
|
for (final p in paths) {
|
|
final ext = p.toLowerCase().split('.').last;
|
|
if (_supportedExtensions.contains(ext) && File(p).existsSync()) {
|
|
anchor = p;
|
|
break;
|
|
}
|
|
}
|
|
if (anchor == null) return;
|
|
|
|
final dir = File(anchor).parent;
|
|
if (!dir.existsSync()) return;
|
|
|
|
final List<(String, DateTime)> entries = [];
|
|
for (final entity in dir.listSync()) {
|
|
if (entity is! File) continue;
|
|
final p = entity.path;
|
|
final ext = p.toLowerCase().split('.').last;
|
|
if (!_supportedExtensions.contains(ext)) continue;
|
|
try {
|
|
entries.add((p, entity.lastModifiedSync()));
|
|
} catch (_) {}
|
|
}
|
|
entries.sort((a, b) {
|
|
if (_sortByName) {
|
|
return a.$1.toLowerCase().compareTo(b.$1.toLowerCase());
|
|
}
|
|
final byDate = b.$2.compareTo(a.$2);
|
|
return byDate != 0 ? byDate : a.$1.compareTo(b.$1);
|
|
});
|
|
|
|
_images
|
|
..clear()
|
|
..addAll(entries.map((e) => e.$1));
|
|
|
|
_currentIndex = _images.indexOf(anchor);
|
|
if (_currentIndex < 0) {
|
|
final base = anchor.split(Platform.pathSeparator).last;
|
|
_currentIndex = _images
|
|
.indexWhere((p) => p.split(Platform.pathSeparator).last == base);
|
|
}
|
|
if (_currentIndex < 0) _currentIndex = 0;
|
|
|
|
notifyListeners();
|
|
}
|
|
|
|
void setSortByName(bool value) {
|
|
if (_sortByName == value) return;
|
|
_sortByName = value;
|
|
if (_images.isNotEmpty) {
|
|
setGalleryFromPaths([_images[_currentIndex]]);
|
|
} else {
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
void setCurrentIndex(int index) {
|
|
if (index < 0 || index >= _images.length) return;
|
|
_currentIndex = index;
|
|
notifyListeners();
|
|
}
|
|
|
|
void previousImage() {
|
|
if (_images.isEmpty) return;
|
|
_currentIndex = (_currentIndex - 1 + _images.length) % _images.length;
|
|
notifyListeners();
|
|
}
|
|
|
|
void nextImage() {
|
|
if (_images.isEmpty) return;
|
|
_currentIndex = (_currentIndex + 1) % _images.length;
|
|
notifyListeners();
|
|
}
|
|
|
|
/// Configure image cache for high-res images
|
|
static void configureCache() {
|
|
PaintingBinding.instance.imageCache.maximumSize = 16;
|
|
PaintingBinding.instance.imageCache.maximumSizeBytes = 256 * 1024 * 1024; // 256 MB
|
|
}
|
|
|
|
void clear() {
|
|
_images.clear();
|
|
_currentIndex = 0;
|
|
notifyListeners();
|
|
}
|
|
}
|