|
@@ -22,14 +22,13 @@ class FrameAnimationView extends StatefulWidget {
|
|
|
|
|
|
|
|
final double? height;
|
|
final double? height;
|
|
|
|
|
|
|
|
- const FrameAnimationView(
|
|
|
|
|
- {super.key,
|
|
|
|
|
- required this.framePath,
|
|
|
|
|
- this.frameRate = 25,
|
|
|
|
|
- this.controller,
|
|
|
|
|
- this.speed,
|
|
|
|
|
- this.width,
|
|
|
|
|
- this.height});
|
|
|
|
|
|
|
+ const FrameAnimationView({super.key,
|
|
|
|
|
+ required this.framePath,
|
|
|
|
|
+ this.frameRate = 25,
|
|
|
|
|
+ this.controller,
|
|
|
|
|
+ this.speed,
|
|
|
|
|
+ this.width,
|
|
|
|
|
+ this.height});
|
|
|
|
|
|
|
|
@override
|
|
@override
|
|
|
State<StatefulWidget> createState() {
|
|
State<StatefulWidget> createState() {
|
|
@@ -50,9 +49,10 @@ class FrameAnimationViewState extends State<FrameAnimationView> {
|
|
|
loadFrameFromAssets()
|
|
loadFrameFromAssets()
|
|
|
.then((_) => initializeImageFiles())
|
|
.then((_) => initializeImageFiles())
|
|
|
.then((_) => precacheImageFiles())
|
|
.then((_) => precacheImageFiles())
|
|
|
- .then((_) => widget.controller == null || widget.controller!.autoPlay
|
|
|
|
|
- ? startAnimation()
|
|
|
|
|
- : null)
|
|
|
|
|
|
|
+ .then((_) =>
|
|
|
|
|
+ widget.controller == null || widget.controller!.autoPlay
|
|
|
|
|
+ ? startAnimation()
|
|
|
|
|
+ : null)
|
|
|
.catchError((error) => debugPrint('FrameAnimationView error: $error'));
|
|
.catchError((error) => debugPrint('FrameAnimationView error: $error'));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -60,6 +60,11 @@ class FrameAnimationViewState extends State<FrameAnimationView> {
|
|
|
void dispose() {
|
|
void dispose() {
|
|
|
super.dispose();
|
|
super.dispose();
|
|
|
_timer?.cancel();
|
|
_timer?.cancel();
|
|
|
|
|
+ imageFiles.clear();
|
|
|
|
|
+ for (var image in images) {
|
|
|
|
|
+ image.dispose();
|
|
|
|
|
+ }
|
|
|
|
|
+ images.clear();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
@override
|
|
@@ -97,8 +102,12 @@ class FrameAnimationViewState extends State<FrameAnimationView> {
|
|
|
final Directory cacheDir = await createCacheDirectory();
|
|
final Directory cacheDir = await createCacheDirectory();
|
|
|
|
|
|
|
|
// if the cache directory is not empty and frame images count is equal to the zip file's files count
|
|
// if the cache directory is not empty and frame images count is equal to the zip file's files count
|
|
|
- if (cacheDir.listSync().isNotEmpty &&
|
|
|
|
|
- cacheDir.listSync().length == archive.length) {
|
|
|
|
|
|
|
+ if (cacheDir
|
|
|
|
|
+ .listSync()
|
|
|
|
|
+ .isNotEmpty &&
|
|
|
|
|
+ cacheDir
|
|
|
|
|
+ .listSync()
|
|
|
|
|
+ .length == archive.length) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -120,7 +129,7 @@ class FrameAnimationViewState extends State<FrameAnimationView> {
|
|
|
Future<void> copyToCache() async {
|
|
Future<void> copyToCache() async {
|
|
|
// Read AssetManifest.json file
|
|
// Read AssetManifest.json file
|
|
|
final String manifestContent =
|
|
final String manifestContent =
|
|
|
- await rootBundle.loadString('AssetManifest.json');
|
|
|
|
|
|
|
+ await rootBundle.loadString('AssetManifest.json');
|
|
|
|
|
|
|
|
// Parse JSON string into Map
|
|
// Parse JSON string into Map
|
|
|
final Map<String, dynamic> manifestMap = json.decode(manifestContent);
|
|
final Map<String, dynamic> manifestMap = json.decode(manifestContent);
|
|
@@ -134,8 +143,12 @@ class FrameAnimationViewState extends State<FrameAnimationView> {
|
|
|
final Directory cacheDir = await createCacheDirectory();
|
|
final Directory cacheDir = await createCacheDirectory();
|
|
|
|
|
|
|
|
// if the cache directory is not empty and frame images count is equal to the zip file's files count
|
|
// if the cache directory is not empty and frame images count is equal to the zip file's files count
|
|
|
- if (cacheDir.listSync().isNotEmpty &&
|
|
|
|
|
- cacheDir.listSync().length == filePaths.length) {
|
|
|
|
|
|
|
+ if (cacheDir
|
|
|
|
|
+ .listSync()
|
|
|
|
|
+ .isNotEmpty &&
|
|
|
|
|
+ cacheDir
|
|
|
|
|
+ .listSync()
|
|
|
|
|
+ .length == filePaths.length) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -143,7 +156,9 @@ class FrameAnimationViewState extends State<FrameAnimationView> {
|
|
|
for (final String path in filePaths) {
|
|
for (final String path in filePaths) {
|
|
|
final ByteData data = await rootBundle.load(path);
|
|
final ByteData data = await rootBundle.load(path);
|
|
|
final List<int> bytes = data.buffer.asUint8List();
|
|
final List<int> bytes = data.buffer.asUint8List();
|
|
|
- final File newFile = File('${cacheDir.path}/${path.split('/').last}');
|
|
|
|
|
|
|
+ final File newFile = File('${cacheDir.path}/${path
|
|
|
|
|
+ .split('/')
|
|
|
|
|
+ .last}');
|
|
|
if (newFile.existsSync()) {
|
|
if (newFile.existsSync()) {
|
|
|
newFile.deleteSync();
|
|
newFile.deleteSync();
|
|
|
} else {
|
|
} else {
|
|
@@ -168,7 +183,8 @@ class FrameAnimationViewState extends State<FrameAnimationView> {
|
|
|
|
|
|
|
|
// create unique directory by framePath's md5
|
|
// create unique directory by framePath's md5
|
|
|
final Directory frameDir = Directory(
|
|
final Directory frameDir = Directory(
|
|
|
- '${cacheDir.path}/${md5.convert(utf8.encode(widget.framePath)).toString()}');
|
|
|
|
|
|
|
+ '${cacheDir.path}/${md5.convert(utf8.encode(widget.framePath))
|
|
|
|
|
+ .toString()}');
|
|
|
|
|
|
|
|
// Check if the directory exists, if not, create it
|
|
// Check if the directory exists, if not, create it
|
|
|
if (!await frameDir.exists()) {
|
|
if (!await frameDir.exists()) {
|
|
@@ -194,7 +210,7 @@ class FrameAnimationViewState extends State<FrameAnimationView> {
|
|
|
setState(() {
|
|
setState(() {
|
|
|
int targetFrame = (_currentFrame + 1) % imageFiles.length;
|
|
int targetFrame = (_currentFrame + 1) % imageFiles.length;
|
|
|
_currentFrame =
|
|
_currentFrame =
|
|
|
- targetFrame >= images.length ? images.length - 1 : targetFrame;
|
|
|
|
|
|
|
+ targetFrame >= images.length ? images.length - 1 : targetFrame;
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
@@ -206,10 +222,10 @@ class FrameAnimationViewState extends State<FrameAnimationView> {
|
|
|
.listSync()
|
|
.listSync()
|
|
|
.map((file) => File(file.path))
|
|
.map((file) => File(file.path))
|
|
|
.where((file) =>
|
|
.where((file) =>
|
|
|
- file.path.endsWith('.png') ||
|
|
|
|
|
- file.path.endsWith('.jpg') ||
|
|
|
|
|
- file.path.endsWith('.jpeg') ||
|
|
|
|
|
- file.path.endsWith('.webp'))
|
|
|
|
|
|
|
+ file.path.endsWith('.png') ||
|
|
|
|
|
+ file.path.endsWith('.jpg') ||
|
|
|
|
|
+ file.path.endsWith('.jpeg') ||
|
|
|
|
|
+ file.path.endsWith('.webp'))
|
|
|
.toList();
|
|
.toList();
|
|
|
|
|
|
|
|
if (imageFiles.isEmpty) {
|
|
if (imageFiles.isEmpty) {
|