Image cards, thumbnails, the lightbox, and `clide image show` rendered via Image.file, whose FileImage keys Flutter's imageCache by (path, scale) only — so overwriting a file at the same path handed back the previously decoded frame (hit live re-exporting a wireframe PNG). Add ClideFileImage, a FileImage that folds mtime + size into ==/hashCode so an in-place change is a fresh cache key (miss → re-decode), and route the five Image.file sites through it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
33 lines
1.2 KiB
Dart
33 lines
1.2 KiB
Dart
/// [ClideFileImage] folds mtime + size into the imageCache key so an in-place
|
|
/// overwrite re-decodes instead of returning Flutter's stale frame (T-312).
|
|
library;
|
|
|
|
import 'dart:io';
|
|
|
|
import 'package:clide/widgets/widgets.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
test('an in-place overwrite produces a different cache key', () {
|
|
final dir = Directory.systemTemp.createTempSync('clide_fileimg_');
|
|
addTearDown(() => dir.deleteSync(recursive: true));
|
|
final f = File('${dir.path}/img.bin')..writeAsBytesSync([1, 2, 3]);
|
|
|
|
final before = ClideFileImage(f.path);
|
|
// Same bytes → same key (cache hit).
|
|
expect(before, ClideFileImage(f.path));
|
|
expect(before.hashCode, ClideFileImage(f.path).hashCode);
|
|
|
|
// Overwrite at the same path with a different length → different key.
|
|
f.writeAsBytesSync([9, 8, 7, 6]);
|
|
final after = ClideFileImage(f.path);
|
|
expect(after, isNot(before));
|
|
expect(after.hashCode, isNot(before.hashCode));
|
|
expect(after.file.path, before.file.path); // same path, just a fresh key
|
|
});
|
|
|
|
test('a missing file falls back to path-only keying', () {
|
|
expect(ClideFileImage('/no/such/clide/file.png'), ClideFileImage('/no/such/clide/file.png'));
|
|
});
|
|
}
|