Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

image_cache #996

Merged
merged 11 commits into from
Dec 13, 2023
4 changes: 4 additions & 0 deletions assets/schema/ensemble_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,10 @@
"type": "string",
"description": "A unique identifier for this widget"
},
"cache": {
"type": "boolean",
"description": "To put the image in the cache"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makek sure you add "... default true."

},
"source": {
"type": "string",
"description": "URL to or asset name of the image. If the URL is used, it is highly recommended that the dimensions is set (either with width/height or other means) to prevent the UI jerkiness while loading."
Expand Down
76 changes: 58 additions & 18 deletions lib/widget/image.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'dart:io';
import 'dart:math';

import 'package:cached_network_image/cached_network_image.dart';
import 'package:ensemble/action/haptic_action.dart';
Expand All @@ -11,14 +10,15 @@ import 'package:ensemble/screen_controller.dart';
import 'package:ensemble/util/utils.dart';
import 'package:ensemble/widget/helpers/controllers.dart';
import 'package:ensemble/widget/helpers/widgets.dart';
import 'package:ensemble/widget/widget_util.dart';
import 'package:ensemble_ts_interpreter/invokables/invokable.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:flutter_svg/svg.dart';
import 'package:http_parser/http_parser.dart';
import 'package:mime/mime.dart';
import 'package:http/http.dart' as http;

class EnsembleImage extends StatefulWidget
with Invokable, HasController<ImageController, ImageState> {
Expand Down Expand Up @@ -51,6 +51,8 @@ class EnsembleImage extends StatefulWidget
@override
Map<String, Function> setters() {
return {
'cache': (value) =>
_controller.cache = Utils.getBool(value, fallback: true),
'source': (value) =>
_controller.source = Utils.getString(value, fallback: ''),
'fit': (value) => _controller.fit = Utils.getBoxFit(value),
Expand All @@ -75,6 +77,7 @@ class ImageController extends BoxController {
/// the image will bleed through the borderRadius
clipContent = true;
}
DateTime? lastModifiedCache;
String source = '';
BoxFit? fit;
Color? placeholderColor;
Expand All @@ -86,6 +89,7 @@ class ImageController extends BoxController {
int? resizedWidth;
int? resizedHeight;
dynamic fallback;
bool cache = true;
}

class ImageState extends WidgetState<EnsembleImage> {
Expand Down Expand Up @@ -135,6 +139,20 @@ class ImageState extends WidgetState<EnsembleImage> {
return rtn;
}

Future<String> fetch(String url) async {
final http.Response response = await http
.get(Uri.parse("${url}timeStamp=${DateTime.now().toString()}"));
vusters marked this conversation as resolved.
Show resolved Hide resolved
DateTime lastModifiedDateTime =
parseHttpDate("${response.headers['last-modified']}");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if the last-modified header is not present. You will end up sending "null" as the parameter.

How will that work?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fullstackctp please see this comment as well

if (widget._controller.lastModifiedCache == null ||
lastModifiedDateTime.compareTo(widget._controller.lastModifiedCache!) ==
1) {
widget._controller.lastModifiedCache = lastModifiedDateTime;
await EnsembleImageCacheManager.instance.emptyCache();
}
return "${widget.controller.source}timeStamp=$lastModifiedDateTime";
vusters marked this conversation as resolved.
Show resolved Hide resolved
}

Widget buildNonSvgImage(String source, BoxFit? fit) {
if (source.startsWith('https://') || source.startsWith('http://')) {
int? cachedWidth = widget._controller.resizedWidth;
Expand All @@ -147,24 +165,46 @@ class ImageState extends WidgetState<EnsembleImage> {
cachedWidth = 800;
}

return CachedNetworkImage(
imageUrl: source,
width: widget._controller.width?.toDouble(),
height: widget._controller.height?.toDouble(),
fit: fit,

// we auto resize and cap these values so loading lots of
// gigantic images won't run out of memory
memCacheWidth: cachedWidth,
memCacheHeight: cachedHeight,
cacheManager: EnsembleImageCacheManager.instance,
errorWidget: (context, error, stacktrace) => errorFallback(),
placeholder: (context, url) => ColoredBoxPlaceholder(
color: widget._controller.placeholderColor,
Widget cacheImage(String url) {
return CachedNetworkImage(
imageUrl: url,
width: widget._controller.width?.toDouble(),
height: widget._controller.height?.toDouble(),
),
);
fit: fit,
// we auto resize and cap these values so loading lots of
// gigantic images won't run out of memory
memCacheWidth: cachedWidth,
memCacheHeight: cachedHeight,
cacheManager: EnsembleImageCacheManager.instance,
errorWidget: (context, error, stacktrace) => errorFallback(),
placeholder: (context, url) => ColoredBoxPlaceholder(
color: widget._controller.placeholderColor,
width: widget._controller.width?.toDouble(),
height: widget._controller.height?.toDouble(),
),
);
}

return (widget.controller.cache)
? FutureBuilder(
future: fetch(widget.controller.source),
initialData: widget._controller.source,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
return cacheImage(snapshot.data!);
} else {
return cacheImage(widget.controller.source);
}
} else {
return ColoredBoxPlaceholder(
color: widget._controller.placeholderColor,
width: widget._controller.width?.toDouble(),
height: widget._controller.height?.toDouble(),
);
}
})
: cacheImage(widget._controller.source);
} else if (Utils.isMemoryPath(widget._controller.source)) {
return kIsWeb
? Image.network(widget._controller.source,
Expand Down