Skip to content

Commit

Permalink
chore: add attributes - as key and removed unused to focus on error on
Browse files Browse the repository at this point in the history
  • Loading branch information
felipecastrosales committed Jul 11, 2023
1 parent f57287f commit e1f5719
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 130 deletions.
2 changes: 1 addition & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ class _SynchronizedDisplayState extends State<SynchronizedDisplay> with SingleTi

@override
void dispose() {
controller.dispose();
// controller.dispose();
super.dispose();
}

Expand Down
23 changes: 15 additions & 8 deletions lib/src/blurhash.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'dart:async';
import 'dart:math';
import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:flutter/foundation.dart';
Expand Down Expand Up @@ -78,11 +77,15 @@ Future<ui.Image> blurHashDecodeImage({

if (kIsWeb) {
// https://github.com/flutter/flutter/issues/45190
final pixels = await blurHashDecode(blurHash: blurHash, width: width, height: height, punch: punch);
final pixels = await blurHashDecode(
blurHash: blurHash, width: width, height: height, punch: punch);
completer.complete(_createBmp(pixels, width, height));
} else {
blurHashDecode(blurHash: blurHash, width: width, height: height, punch: punch).then((pixels) {
ui.decodeImageFromPixels(pixels, width, height, ui.PixelFormat.rgba8888, completer.complete);
blurHashDecode(
blurHash: blurHash, width: width, height: height, punch: punch)
.then((pixels) {
ui.decodeImageFromPixels(
pixels, width, height, ui.PixelFormat.rgba8888, completer.complete);
});
}

Expand Down Expand Up @@ -142,7 +145,8 @@ void _validateBlurHash(String blurHash) {
final numX = (sizeFlag % 9) + 1;

if (blurHash.length != 4 + 2 * numX * numY) {
throw Exception('blurhash length mismatch: length is ${blurHash.length} but '
throw Exception(
'blurhash length mismatch: length is ${blurHash.length} but '
'it should be ${4 + 2 * numX * numY}');
}
}
Expand Down Expand Up @@ -198,22 +202,25 @@ bool validateBlurhash(String blurhash) {
final x = (sizeFlag % 9) + 1;

if (blurhash.length != 4 + 2 * x * y) {
debugPrint("blurhash length mismatch: length is ${blurhash.length} but it should be ${4 + 2 * x * y}");
debugPrint(
"blurhash length mismatch: length is ${blurhash.length} but it should be ${4 + 2 * x * y}");
return false;
}

return true;
}

const _digitCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#\$%*+,-.:;=?@[]^_{|}~";
const _digitCharacters =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#\$%*+,-.:;=?@[]^_{|}~";

class Style {
final String name;
final List<ui.Color> colors;
final ui.Color? stroke;
final ui.Color? background;

const Style({required this.name, required this.colors, this.stroke, this.background});
const Style(
{required this.name, required this.colors, this.stroke, this.background});
}

const styles = {
Expand Down
169 changes: 48 additions & 121 deletions lib/src/blurhash_widget.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:ui' as ui;

import 'package:flutter/foundation.dart';
Expand All @@ -11,6 +12,7 @@ class BlurHash extends StatefulWidget {
const BlurHash({
required this.hash,
Key? key,
this.imageKey,
this.color = Colors.blueGrey,
this.imageFit = BoxFit.fill,
this.decodingWidth = _DEFAULT_SIZE,
Expand All @@ -20,6 +22,7 @@ class BlurHash extends StatefulWidget {
this.onDisplayed,
this.onReady,
this.onStarted,
this.onError,
this.duration = const Duration(milliseconds: 1000),
this.httpHeaders = const {},
this.curve = Curves.easeOut,
Expand All @@ -40,6 +43,9 @@ class BlurHash extends StatefulWidget {
/// Callback when image is downloaded
final VoidCallback? onStarted;

/// Calback when image is error
final FutureOr<Image>? onError;

/// Hash to decode
final String hash;

Expand Down Expand Up @@ -68,6 +74,9 @@ class BlurHash extends StatefulWidget {
/// Network image errorBuilder
final ImageErrorWidgetBuilder? errorBuilder;

// Key to use for the widget
final Key? imageKey;

@override
BlurHashState createState() => BlurHashState();
}
Expand All @@ -89,25 +98,25 @@ class BlurHashState extends State<BlurHash> {
loading = false;
}

@override
void didUpdateWidget(BlurHash oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.hash != oldWidget.hash ||
widget.image != oldWidget.image ||
widget.decodingWidth != oldWidget.decodingWidth ||
widget.decodingHeight != oldWidget.decodingHeight) {
_init();
}
}
// @override
// void didUpdateWidget(BlurHash oldWidget) {
// super.didUpdateWidget(oldWidget);
// if (widget.hash != oldWidget.hash ||
// widget.image != oldWidget.image ||
// widget.decodingWidth != oldWidget.decodingWidth ||
// widget.decodingHeight != oldWidget.decodingHeight) {
// _init();
// }
// }

void _decodeImage() {
_image = blurHashDecodeImage(
blurHash: widget.hash,
width: widget.decodingWidth,
height: widget.decodingHeight,
);

_image.whenComplete(() => widget.onDecoded?.call());
// .onError((error, stackTrace) {},);
}

@override
Expand All @@ -117,125 +126,43 @@ class BlurHashState extends State<BlurHash> {
clipBehavior: Clip.none,
children: [
Positioned.fill(
child: buildBlurHashBackground(),
// child: StreamBuilder<ui.Image>(
// stream: Stream.fromFuture(_image),
child: FutureBuilder<ui.Image>(
future: _image,
builder: (_, snap) => snap.data != null &&
snap.data!.debugDisposed == false &&
snap.data!.width > 0 &&
snap.data!.height > 0 &&
!loading &&
snap.hasData &&
!snap.hasError
? Image(
image: UiImage(
snap.data!,
// key: ValueKey(_image.hashCode),
key: widget.key,
),
fit: widget.imageFit,
errorBuilder: widget.errorBuilder,
)
: Container(color: widget.color),
),
),
if (widget.image != null) prepareDisplayedImage(widget.image!),
],
);

Widget prepareDisplayedImage(String image) => Image.network(
image,
fit: widget.imageFit,
headers: widget.httpHeaders,
errorBuilder: widget.errorBuilder,
loadingBuilder: (context, img, loadingProgress) {
// Download started
if (loading == false) {
loading = true;
widget.onStarted?.call();
}

if (loadingProgress == null) {
// Image is now loaded, trigger the event
loaded = true;
widget.onReady?.call();
return _DisplayImage(
child: img,
duration: widget.duration,
curve: widget.curve,
onCompleted: () => widget.onDisplayed?.call(),
);
}

if (loadingProgress.expectedTotalBytes == null ||
(loadingProgress.expectedTotalBytes ?? 0) >= 0) {
// return Center(
// child: CircularProgressIndicator(
// value: loadingProgress.expectedTotalBytes != null
// ? loadingProgress.cumulativeBytesLoaded /
// loadingProgress.expectedTotalBytes!
// : null,
// ),
// );
return const SizedBox();
} else {
return const SizedBox();
}
},
);

/// Decode the blurhash then display the resulting Image
Widget buildBlurHashBackground() => FutureBuilder<ui.Image>(
future: _image,
builder: (ctx, snap) => snap.hasData
? Image(
image: UiImage(snap.data!),
fit: widget.imageFit,
errorBuilder: widget.errorBuilder,
)
: Container(color: widget.color),
);
}

// Inner display details & controls
class _DisplayImage extends StatefulWidget {
final Widget child;
final Duration duration;
final Curve curve;
final VoidCallback onCompleted;

const _DisplayImage({
required this.child,
this.duration = const Duration(milliseconds: 800),
required this.curve,
required this.onCompleted,
Key? key,
}) : super(key: key);

@override
_DisplayImageState createState() => _DisplayImageState();
}

class _DisplayImageState extends State<_DisplayImage>
with SingleTickerProviderStateMixin {
late Animation<double> opacity;
late AnimationController controller;

@override
Widget build(BuildContext context) => FadeTransition(
opacity: opacity,
child: widget.child,
);

@override
void initState() {
super.initState();
controller = AnimationController(duration: widget.duration, vsync: this);
final curved = CurvedAnimation(parent: controller, curve: widget.curve);
opacity = Tween<double>(begin: .0, end: 1.0).animate(curved);
controller.forward();

curved.addStatusListener(listener);
}

void listener(AnimationStatus status) {
if (status == AnimationStatus.completed) widget.onCompleted.call();
}

@override
void dispose() {
controller.removeStatusListener(listener);
if (controller.isAnimating) controller.stop();
controller.dispose();
super.dispose();
}
}

class UiImage extends ImageProvider<UiImage> {
final ui.Image image;
final double scale;
final Key? key;

const UiImage(this.image, {this.scale = 1.0});
const UiImage(
this.image, {
this.key,
this.scale = 1.0,
});

@override
Future<UiImage> obtainKey(ImageConfiguration configuration) =>
Expand Down

0 comments on commit e1f5719

Please sign in to comment.