Skip to content

Commit 24eb4e4

Browse files
committed
Added: Checking Local asset availability before using firebase asset url
1 parent 481d72a commit 24eb4e4

File tree

12 files changed

+197
-12
lines changed

12 files changed

+197
-12
lines changed

modules/ensemble/lib/action/audio_player.dart

+11-5
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,17 @@ class PlayAudio extends EnsembleAction {
120120
Future<dynamic> execute(
121121
BuildContext context, ScopeManager scopeManager) async {
122122
AudioCache.instance = AudioCache(prefix: '');
123-
124-
final parsedSource =
125-
source.startsWith('https://') || source.startsWith('http://')
126-
? UrlSource(source)
127-
: AssetSource(Utils.getLocalAssetFullPath(source));
123+
var parsedSource; // Source
124+
if (source.startsWith('https://') || source.startsWith('http://')) {
125+
String assetName = Utils.getAssetName(source);
126+
if (Utils.isAssetAvailableLocally(assetName)) {
127+
parsedSource = AssetSource(Utils.getLocalAssetFullPath(assetName));
128+
} else {
129+
parsedSource = UrlSource(source);
130+
}
131+
} else {
132+
parsedSource = AssetSource(Utils.getLocalAssetFullPath(source));
133+
}
128134

129135
await SingletonAudioPlayer.instance.play(
130136
id: id,

modules/ensemble/lib/ensemble.dart

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'dart:math' as math;
66
import 'package:ensemble/ensemble_app.dart';
77
import 'package:ensemble/firebase_options.dart';
88
import 'package:ensemble/framework/apiproviders/api_provider.dart';
9+
import 'package:ensemble/framework/assets_service.dart';
910
import 'package:ensemble/framework/bindings.dart';
1011
import 'package:ensemble/framework/definition_providers/ensemble_provider.dart';
1112
import 'package:ensemble/framework/device.dart';
@@ -200,7 +201,10 @@ class Ensemble extends WithEnsemble with EnsembleRouteObserver {
200201
services: Services.fromYaml(yamlMap['services']),
201202
signInServices: SignInServices.fromYaml(yamlMap['services']),
202203
envOverrides: envOverrides);
203-
204+
// Initializing Local Assets Service to store available local assets names
205+
if(!LocalAssetsService.isInitialized){
206+
await LocalAssetsService.initialize(_instance.getConfig()?.definitionProvider.getAppConfig()?.envVariables, yamlMap);
207+
}
204208
AppInfo().initPackageInfo(_config);
205209
await initializeAPIProviders(_config!);
206210
return _config!;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import 'package:ensemble/util/utils.dart';
2+
import 'package:flutter/services.dart';
3+
import 'package:yaml/yaml.dart';
4+
5+
class LocalAssetsService {
6+
static List<String> localAssets = [];
7+
static bool _isInitialized = false;
8+
9+
static Future<void> initialize(Map<String, dynamic>? envVariables, YamlMap definations) async {
10+
List<String> foundAssets = [];
11+
12+
for (var entry in envVariables!.entries) {
13+
String assetName = Utils.getAssetName(entry.value); // Get the asset name
14+
String provider = definations['definitions']?['from'];
15+
String path= definations['definitions']?['local']['path'];
16+
String assetPath = provider == 'local' ? "$path/assets/$assetName" : "ensemble/assets/$assetName"; // Construct the full path
17+
18+
bool exists = await _assetExists(assetPath); // Check if asset exists
19+
20+
if (exists) {
21+
foundAssets.add(assetName); // Store only existing assets
22+
}
23+
}
24+
25+
localAssets = foundAssets;
26+
_isInitialized = true;
27+
}
28+
29+
static Future<bool> _assetExists(String path) async {
30+
try {
31+
await rootBundle.load(path);
32+
return true;
33+
} catch (e) {
34+
return false; // Asset does not exist
35+
}
36+
}
37+
38+
static bool get isInitialized => _isInitialized;
39+
}

modules/ensemble/lib/framework/model.dart

+17-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,13 @@ class BackgroundImage {
3131
DecorationImage getImageAsDecorated() {
3232
ImageProvider imageProvider;
3333
if (Utils.isUrl(_source)) {
34-
imageProvider = NetworkImage(_source);
34+
// If the asset is available locally, then use local path
35+
String assetName = Utils.getAssetName(_source);
36+
if (Utils.isAssetAvailableLocally(assetName)) {
37+
imageProvider = AssetImage(Utils.getLocalAssetFullPath(assetName));
38+
} else {
39+
imageProvider = NetworkImage(_source);
40+
}
3541
} else {
3642
imageProvider = AssetImage(Utils.getLocalAssetFullPath(_source));
3743
}
@@ -48,6 +54,16 @@ class BackgroundImage {
4854
: null;
4955

5056
if (Utils.isUrl(_source)) {
57+
String assetName = Utils.getAssetName(_source);
58+
if (Utils.isAssetAvailableLocally(assetName)) {
59+
return Image.asset(
60+
Utils.getLocalAssetFullPath(assetName),
61+
fit: _fit,
62+
alignment: _alignment,
63+
errorBuilder:
64+
fallbackWidget != null ? (_, __, ___) => fallbackWidget : null,
65+
);
66+
}
5167
return CachedNetworkImage(
5268
imageUrl: _source,
5369
fit: _fit,

modules/ensemble/lib/framework/widget/image.dart

+19-4
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,21 @@ class Image extends StatelessWidget {
3434

3535
@override
3636
Widget build(BuildContext context) {
37-
return source.startsWith('https://') || source.startsWith('http://')
38-
? CachedNetworkImage(
37+
if (source.startsWith('https://') || source.startsWith('http://')) {
38+
// If the asset is available locally, then use local path
39+
String assetName = Utils.getAssetName(source);
40+
if (Utils.isAssetAvailableLocally(assetName)) {
41+
return flutter.Image.asset(
42+
Utils.getLocalAssetFullPath(assetName),
43+
width: width,
44+
height: height,
45+
fit: fit,
46+
errorBuilder: errorBuilder != null
47+
? (context, error, stackTrace) => errorBuilder!(error.toString())
48+
: null,
49+
);
50+
}
51+
return CachedNetworkImage(
3952
imageUrl: source,
4053
width: width,
4154
height: height,
@@ -46,8 +59,9 @@ class Image extends StatelessWidget {
4659
errorWidget: errorBuilder != null
4760
? (context, url, error) => errorBuilder!(error.toString())
4861
: null,
49-
cacheManager: networkCacheManager)
50-
: flutter.Image.asset(
62+
cacheManager: networkCacheManager);
63+
} else {
64+
return flutter.Image.asset(
5165
Utils.getLocalAssetFullPath(source),
5266
width: width,
5367
height: height,
@@ -57,5 +71,6 @@ class Image extends StatelessWidget {
5771
errorBuilder!(error.toString())
5872
: null,
5973
);
74+
}
6075
}
6176
}

modules/ensemble/lib/util/utils.dart

+19
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'dart:ui';
44
import 'package:ensemble/ensemble.dart';
55
import 'package:ensemble/ensemble_app.dart';
66
import 'package:ensemble/framework/action.dart';
7+
import 'package:ensemble/framework/assets_service.dart';
78
import 'package:ensemble/framework/ensemble_config_service.dart';
89
import 'package:ensemble/framework/stub/location_manager.dart';
910
import 'package:ensemble/framework/theme/theme_manager.dart';
@@ -249,6 +250,20 @@ class Utils {
249250
return source.startsWith('https://') || source.startsWith('http://');
250251
}
251252

253+
static String getAssetName(String source) {
254+
try {
255+
Uri uri = Uri.parse(source);
256+
String path = uri.pathSegments!.last; // Get the last segment with encoding
257+
return Uri.decodeFull(path)
258+
.split('/')
259+
.last
260+
.split('?')
261+
.first; // Decode and extract the file name
262+
} catch (e) {
263+
return '';
264+
}
265+
}
266+
252267
static LocationData? getLatLng(dynamic value) {
253268
if (value is String) {
254269
List<String> tokens = value.split(RegExp('\\s+'));
@@ -1010,6 +1025,10 @@ class Utils {
10101025
}
10111026
}
10121027

1028+
static bool isAssetAvailableLocally(String? fileName) {
1029+
return LocalAssetsService.localAssets.contains(fileName);
1030+
}
1031+
10131032
static bool isMemoryPath(String path) {
10141033
if (kIsWeb) {
10151034
return path.contains('blob:');

modules/ensemble/lib/widget/image.dart

+19-1
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,15 @@ class ImageState extends EWidgetState<EnsembleImage> {
189189

190190
Widget buildNonSvgImage(String source, BoxFit? fit) {
191191
if (source.startsWith('https://') || source.startsWith('http://')) {
192+
// If the asset is available locally, then use local path
193+
String assetName = Utils.getAssetName(source);
194+
if (Utils.isAssetAvailableLocally(assetName)) {
195+
return Image.asset(Utils.getLocalAssetFullPath(assetName),
196+
width: widget._controller.width?.toDouble(),
197+
height: widget._controller.height?.toDouble(),
198+
fit: fit,
199+
errorBuilder: (context, error, stacktrace) => errorFallback());
200+
}
192201
int? cachedWidth = widget._controller.resizedWidth;
193202
int? cachedHeight = widget._controller.resizedHeight;
194203

@@ -273,9 +282,18 @@ class ImageState extends EWidgetState<EnsembleImage> {
273282
fit: fit ?? BoxFit.contain,
274283
);
275284
}
276-
285+
277286
// if is URL
278287
if (source.startsWith('https://') || source.startsWith('http://')) {
288+
// If the asset is available locally, then use local path
289+
String assetName = Utils.getAssetName(source);
290+
if (Utils.isAssetAvailableLocally(assetName)) {
291+
return SvgPicture.asset(
292+
Utils.getLocalAssetFullPath(assetName),
293+
width: widget._controller.width?.toDouble(),
294+
height: widget._controller.height?.toDouble(),
295+
fit: fit ?? BoxFit.contain);
296+
}
279297
return SvgPicture.network(
280298
widget._controller.source,
281299
width: widget._controller.width?.toDouble(),

modules/ensemble/lib/widget/image_cropper.dart

+18
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,16 @@ class EnsembleImageCropperState extends EWidgetState<EnsembleImageCropper>
290290

291291
ImageProvider buildNonSvgImageProvider(String source, BoxFit? fit) {
292292
if (source.startsWith('https://') || source.startsWith('http://')) {
293+
// If the asset is available locally, then use local path
294+
String assetName = Utils.getAssetName(source);
295+
if (Utils.isAssetAvailableLocally(assetName)) {
296+
return Image.asset(
297+
Utils.getLocalAssetFullPath(assetName),
298+
width: widget._controller.width?.toDouble(),
299+
height: widget._controller.height?.toDouble(),
300+
fit: fit,
301+
).image;
302+
}
293303
return Image.network(
294304
source,
295305
width: widget._controller.width?.toDouble(),
@@ -315,6 +325,14 @@ class EnsembleImageCropperState extends EWidgetState<EnsembleImageCropper>
315325
Svg buildSvgImageProvider(String source, BoxFit? fit) {
316326
// if is URL
317327
if (source.startsWith('https://') || source.startsWith('http://')) {
328+
// If the asset is available locally, then use local path
329+
String assetName = Utils.getAssetName(source);
330+
if (Utils.isAssetAvailableLocally(assetName)) {
331+
return Svg(
332+
Utils.getLocalAssetFullPath(widget._controller.source),
333+
source: SvgSource.asset,
334+
);
335+
}
318336
return Svg(widget._controller.source, source: SvgSource.network);
319337
}
320338
// attempt local assets

modules/ensemble/lib/widget/lottie/native/lottiestate.dart

+16
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,22 @@ class LottieState extends EWidgetState<EnsembleLottie>
6969
if (source.isNotEmpty) {
7070
// if is URL
7171
if (source.startsWith('https://') || source.startsWith('http://')) {
72+
// If the asset is available locally, then use local path
73+
String assetName = Utils.getAssetName(source);
74+
if (Utils.isAssetAvailableLocally(assetName)) {
75+
return Lottie.asset(
76+
Utils.getLocalAssetFullPath(assetName),
77+
controller: widget.controller.lottieController,
78+
onLoaded: (composition) {
79+
widget.controller.initializeLottieController(composition);
80+
},
81+
width: widget.controller.width?.toDouble(),
82+
height: widget.controller.height?.toDouble(),
83+
repeat: widget.controller.repeat,
84+
fit: fit,
85+
errorBuilder: (context, error, stacktrace) => placeholderImage(),
86+
);
87+
}
7288
return Lottie.network(widget.controller.source,
7389
controller: widget.controller.lottieController,
7490
onLoaded: (composition) {

modules/ensemble/lib/widget/lottie/web/lottiestate.dart

+14
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,20 @@ class LottieState extends EWidgetState<EnsembleLottie>
246246
if (source.isNotEmpty) {
247247
// if is URL
248248
if (source.startsWith('https://') || source.startsWith('http://')) {
249+
// If the asset is available locally, then use local path
250+
String assetName = Utils.getAssetName(source);
251+
if (Utils.isAssetAvailableLocally(assetName)) {
252+
return Lottie.asset(Utils.getLocalAssetFullPath(assetName),
253+
controller: widget.controller.lottieController,
254+
onLoaded: (LottieComposition composition) {
255+
widget.controller.initializeLottieController(composition);
256+
},
257+
width: widget.controller.width?.toDouble(),
258+
height: widget.controller.height?.toDouble(),
259+
repeat: widget.controller.repeat,
260+
fit: fit,
261+
errorBuilder: (context, error, stacktrace) => placeholderImage());
262+
}
249263
// image binding is tricky. When the URL has not been resolved
250264
// the image will throw exception. We have to use a permanent placeholder
251265
// until the binding engages

modules/ensemble/lib/widget/video.dart

+14
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,27 @@ class MyController extends WidgetController {
103103
}
104104

105105
if (value.startsWith('https://') || value.startsWith('http://')) {
106+
// If the asset is available locally, then use local path
107+
String assetName = Utils.getAssetName(value);
108+
if (Utils.isAssetAvailableLocally(assetName)) {
109+
_playerController = VideoPlayerController.asset(
110+
Utils.getLocalAssetFullPath(assetName))
111+
..initialize().then((_) {
112+
VideoPlayerValue value = _playerController!.value;
113+
log(value.toString());
114+
setupPlayer();
115+
notifyListeners();
116+
});
117+
}
118+
else{
106119
_playerController = VideoPlayerController.networkUrl(Uri.parse(value))
107120
..initialize().then((_) {
108121
VideoPlayerValue value = _playerController!.value;
109122
log(value.toString());
110123
setupPlayer();
111124
notifyListeners();
112125
});
126+
}
113127
} else if (Utils.isMemoryPath(value)) {
114128
_playerController = VideoPlayerController.file(File(value))
115129
..initialize().then((_) {

modules/location/lib/widget/maps/maps_utils.dart

+6
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ class MapsUtils {
3838
/// for device with high device pixel ratio.
3939
if (Utils.isUrl(asset)) {
4040
try {
41+
// If the asset is available locally, then use local path
42+
String assetName = Utils.getAssetName(asset);
43+
if (Utils.isAssetAvailableLocally(assetName)) {
44+
return BitmapDescriptor.fromAssetImage(
45+
ImageConfiguration.empty, Utils.getLocalAssetFullPath(asset));
46+
}
4147
// use cache manager
4248
final File file = await DefaultCacheManager().getSingleFile(asset);
4349
final Uint8List imageBytes = await file.readAsBytes();

0 commit comments

Comments
 (0)