Add Resource Loader for iOS

This commit is contained in:
pengfei.zhou 2021-10-25 16:01:44 +08:00 committed by osborn
parent 4bd4f42f52
commit 235549eea4
40 changed files with 979 additions and 242 deletions

View File

@ -15,6 +15,7 @@
*/
package pub.doric.resource;
import java.io.IOException;
import java.io.InputStream;
import pub.doric.DoricContext;
@ -34,14 +35,30 @@ public class DoricAndroidResource extends DoricResource {
}
@Override
public AsyncResult<InputStream> asInputStream() {
AsyncResult<InputStream> result = new AsyncResult<>();
public AsyncResult<byte[]> fetchRaw() {
AsyncResult<byte[]> result = new AsyncResult<>();
int resId = doricContext.getContext().getResources().getIdentifier(
identifier,
defType,
doricContext.getContext().getPackageName());
if (resId > 0) {
result.setResult(doricContext.getContext().getResources().openRawResource(resId));
InputStream inputStream = null;
try {
inputStream = doricContext.getContext().getResources().openRawResource(resId);
byte[] data = new byte[inputStream.available()];
inputStream.read(data);
result.setResult(data);
} catch (Exception e) {
result.setError(e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} else {
result.setError(new Throwable("Cannot find resource for :" + identifier + ",type = " + defType));
}

View File

@ -32,13 +32,24 @@ public class DoricAssetsResource extends DoricResource {
}
@Override
public AsyncResult<InputStream> asInputStream() {
AsyncResult<InputStream> result = new AsyncResult<>();
public AsyncResult<byte[]> fetchRaw() {
AsyncResult<byte[]> result = new AsyncResult<>();
InputStream inputStream = null;
try {
InputStream inputStream = doricContext.getContext().getAssets().open(identifier);
result.setResult(inputStream);
inputStream = doricContext.getContext().getAssets().open(identifier);
byte[] data = new byte[inputStream.available()];
inputStream.read(data);
result.setResult(data);
} catch (IOException e) {
result.setError(e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}

View File

@ -19,9 +19,6 @@ import android.text.TextUtils;
import android.util.Base64;
import android.util.Pair;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import pub.doric.DoricContext;
import pub.doric.async.AsyncResult;
import pub.doric.utils.DoricUtils;
@ -38,8 +35,8 @@ class DoricBase64Resource extends DoricResource {
}
@Override
public AsyncResult<InputStream> asInputStream() {
AsyncResult<InputStream> ret = new AsyncResult<>();
public AsyncResult<byte[]> fetchRaw() {
AsyncResult<byte[]> ret = new AsyncResult<>();
Pair<String, String> result = DoricUtils.translateBase64(identifier);
if (result != null) {
String imageType = result.first;
@ -48,7 +45,7 @@ class DoricBase64Resource extends DoricResource {
if (!TextUtils.isEmpty(imageType) && !TextUtils.isEmpty(base64)) {
try {
byte[] data = Base64.decode(base64, Base64.DEFAULT);
ret.setResult(new ByteArrayInputStream(data));
ret.setResult(data);
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -16,8 +16,7 @@
package pub.doric.resource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import pub.doric.DoricContext;
import pub.doric.async.AsyncResult;
@ -34,12 +33,24 @@ public class DoricLocalResource extends DoricResource {
}
@Override
public AsyncResult<InputStream> asInputStream() {
AsyncResult<InputStream> result = new AsyncResult<>();
public AsyncResult<byte[]> fetchRaw() {
AsyncResult<byte[]> result = new AsyncResult<>();
FileInputStream fis = null;
try {
result.setResult(new FileInputStream(identifier));
} catch (FileNotFoundException e) {
fis = new FileInputStream(identifier);
byte[] data = new byte[fis.available()];
fis.read(data);
result.setResult(data);
} catch (Exception e) {
result.setError(e);
}finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}

View File

@ -23,8 +23,7 @@ import com.bumptech.glide.request.target.Target;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import androidx.annotation.Nullable;
import pub.doric.DoricContext;
@ -42,8 +41,8 @@ public class DoricRemoteResource extends DoricResource {
}
@Override
public AsyncResult<InputStream> asInputStream() {
final AsyncResult<InputStream> result = new AsyncResult<>();
public AsyncResult<byte[]> fetchRaw() {
final AsyncResult<byte[]> result = new AsyncResult<>();
Glide.with(doricContext.getContext()).download(identifier)
.listener(new RequestListener<File>() {
@Override
@ -54,10 +53,22 @@ public class DoricRemoteResource extends DoricResource {
@Override
public boolean onResourceReady(File resource, Object model, Target<File> target, DataSource dataSource, boolean isFirstResource) {
FileInputStream fis = null;
try {
result.setResult(new FileInputStream(resource));
} catch (FileNotFoundException e) {
fis = new FileInputStream(resource);
byte[] data = new byte[fis.available()];
fis.read(data);
result.setResult(data);
} catch (Exception e) {
result.setError(e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}

View File

@ -35,5 +35,5 @@ public abstract class DoricResource {
this.identifier = identifier;
}
public abstract AsyncResult<InputStream> asInputStream();
public abstract AsyncResult<byte[]> fetchRaw();
}

View File

@ -57,7 +57,6 @@ import java.io.InputStream;
import jp.wasabeef.glide.transformations.BlurTransformation;
import pub.doric.DoricContext;
import pub.doric.DoricSingleton;
import pub.doric.async.AsyncResult;
import pub.doric.extension.bridge.DoricMethod;
import pub.doric.extension.bridge.DoricPlugin;
@ -371,22 +370,10 @@ public class ImageNode extends ViewNode<ImageView> {
final String identifier = resource.getProperty("identifier").asString().value();
DoricResource doricResource = getDoricContext().getDriver().getRegistry().getResourceManager().load(getDoricContext(), type, identifier);
if (doricResource != null) {
doricResource.asInputStream().setCallback(new AsyncResult.Callback<InputStream>() {
doricResource.fetchRaw().setCallback(new AsyncResult.Callback<byte[]>() {
@Override
public void onResult(InputStream result) {
try {
byte[] imageData = new byte[result.available()];
result.read(imageData, 0, result.available());
loadIntoTarget(Glide.with(getContext()).load(imageData));
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
result.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void onResult(byte[] imageData) {
loadIntoTarget(Glide.with(getContext()).load(imageData));
}
@Override

View File

@ -1,4 +1,4 @@
import { Group, Panel, coordinator, text, gravity, Color, LayoutSpec, log, vlayout, scroller, layoutConfig, image, ScaleType, Image, modal } from "doric";
import { Base64Resource, Group, Panel, coordinator, text, gravity, Color, LayoutSpec, log, vlayout, scroller, layoutConfig, image, ScaleType, Image, modal, RemoteResource, MainBundleResource } from "doric";
import { colors, label } from "./utils";
import { img_base64 } from "./image_base64";
@ -6,6 +6,7 @@ const imageUrl = 'https://img.zcool.cn/community/01e75b5da933daa801209e1ffa4649.
import logo from "./images/logo_w.png"
import button from "./images/button.png"
import { DrawableResource } from "doric/lib/src/util/resource";
@Entry
class ImageDemo extends Panel {
@ -26,157 +27,156 @@ class ImageDemo extends Panel {
label('Button'),
image({
imageBase64: button,
scaleType: ScaleType.ScaleToFill,
layoutConfig: {
widthSpec: LayoutSpec.FIT,
heightSpec: LayoutSpec.FIT,
},
imageScale: 2,
image: Environment.platform === 'Android'
? new DrawableResource("doric_icon_back")
: new MainBundleResource("Hanabi.ttf"),
}),
image({
imageBase64: button,
image: new RemoteResource("https://p.upyun.com/demo/webp/webp/jpg-0.webp"),
}),
image({
image: new Base64Resource(img_base64[0]),
scaleType: ScaleType.ScaleToFill,
layoutConfig: {
widthSpec: LayoutSpec.FIT,
heightSpec: LayoutSpec.FIT,
},
}),
image({
imageBase64: button,
scaleType: ScaleType.ScaleToFill,
layoutConfig: {
widthSpec: LayoutSpec.JUST,
heightSpec: LayoutSpec.JUST,
},
width: 200,
height: 150 / 2.75,
stretchInset: {
left: 100,
top: 0,
right: 100,
bottom: 0
},
imageScale: 2.75,
}),
image({
imageBase64: button,
scaleType: ScaleType.ScaleToFill,
layoutConfig: {
widthSpec: LayoutSpec.JUST,
heightSpec: LayoutSpec.JUST,
},
width: 200,
height: 75,
stretchInset: {
left: 100,
top: 0,
right: 100,
bottom: 0
},
imageScale: 2,
// image({
// imageBase64: button,
// scaleType: ScaleType.ScaleToFill,
// layoutConfig: {
// widthSpec: LayoutSpec.JUST,
// heightSpec: LayoutSpec.JUST,
// },
// width: 200,
// height: 150 / 2.75,
// stretchInset: {
// left: 100,
// top: 0,
// right: 100,
// bottom: 0
// },
// imageScale: 2.75,
// }),
// image({
// imageBase64: button,
// scaleType: ScaleType.ScaleToFill,
// layoutConfig: {
// widthSpec: LayoutSpec.JUST,
// heightSpec: LayoutSpec.JUST,
// },
// width: 200,
// height: 75,
// stretchInset: {
// left: 100,
// top: 0,
// right: 100,
// bottom: 0
// },
// imageScale: 2,
}),
label('Gif '),
image({
imageUrl: "https://www.w3.org/People/mimasa/test/imgformat/img/w3c_home_animation.gif",
scaleType: ScaleType.ScaleToFill,
imageScale: 3,
}),
label('APNG'),
image({
imageUrl: "https://upload.wikimedia.org/wikipedia/commons/1/14/Animated_PNG_example_bouncing_beach_ball.png",
}),
label('Animated WebP'),
image({
imageUrl: "https://p.upyun.com/demo/webp/webp/animated-gif-0.webp",
// }),
// label('Gif '),
// image({
// imageUrl: "https://www.w3.org/People/mimasa/test/imgformat/img/w3c_home_animation.gif",
// scaleType: ScaleType.ScaleToFill,
// imageScale: 3,
// }),
// label('APNG'),
// image({
// imageUrl: "https://upload.wikimedia.org/wikipedia/commons/1/14/Animated_PNG_example_bouncing_beach_ball.png",
// }),
// label('Animated WebP'),
// image({
// imageUrl: "https://p.upyun.com/demo/webp/webp/animated-gif-0.webp",
}),
label('WebP'),
imageView = image({
imageUrl: "https://p.upyun.com/demo/webp/webp/jpg-0.webp",
layoutConfig: layoutConfig().just(),
width: 200,
height: 200,
loadCallback: (ret) => {
if (ret) {
imageView.width = ret.width
imageView.height = ret.height
}
}
}),
label('ScaleToFill'),
image({
imageUrl,
width: 300,
height: 300,
isBlur: true,
border: {
width: 2,
color: Color.GRAY,
},
scaleType: ScaleType.ScaleToFill,
layoutConfig: layoutConfig().just(),
loadCallback: (ret) => {
}
}),
label('ScaleAspectFit'),
image({
imageUrl,
width: 300,
height: 300,
border: {
width: 2,
color: Color.GRAY,
},
scaleType: ScaleType.ScaleAspectFit,
layoutConfig: layoutConfig().just(),
}),
label('ScaleAspectFill'),
image({
imageUrl,
width: 300,
height: 300,
border: {
width: 2,
color: Color.GRAY,
},
scaleType: ScaleType.ScaleAspectFill,
layoutConfig: layoutConfig().just(),
}),
label('ImageBase64'),
image({
imageBase64: img_base64[0],
width: 300,
height: 300,
border: {
width: 2,
color: Color.GRAY,
},
scaleType: ScaleType.ScaleAspectFill,
layoutConfig: layoutConfig().just(),
}),
label('StretchInset'),
image({
imageBase64: img_base64[1],
height: 60,
width: 134,
scaleType: ScaleType.ScaleAspectFill,
layoutConfig: layoutConfig().just(),
}),
image({
imageBase64: img_base64[1],
height: 60,
width: 294,
scaleType: ScaleType.ScaleToFill,
layoutConfig: layoutConfig().just(),
stretchInset: {
left: 0.85,
top: 0,
right: 0.149,
bottom: 0
}
}),
// }),
// label('WebP'),
// imageView = image({
// imageUrl: "https://p.upyun.com/demo/webp/webp/jpg-0.webp",
// layoutConfig: layoutConfig().just(),
// width: 200,
// height: 200,
// loadCallback: (ret) => {
// if (ret) {
// imageView.width = ret.width
// imageView.height = ret.height
// }
// }
// }),
// label('ScaleToFill'),
// image({
// imageUrl,
// width: 300,
// height: 300,
// isBlur: true,
// border: {
// width: 2,
// color: Color.GRAY,
// },
// scaleType: ScaleType.ScaleToFill,
// layoutConfig: layoutConfig().just(),
// loadCallback: (ret) => {
// }
// }),
// label('ScaleAspectFit'),
// image({
// imageUrl,
// width: 300,
// height: 300,
// border: {
// width: 2,
// color: Color.GRAY,
// },
// scaleType: ScaleType.ScaleAspectFit,
// layoutConfig: layoutConfig().just(),
// }),
// label('ScaleAspectFill'),
// image({
// imageUrl,
// width: 300,
// height: 300,
// border: {
// width: 2,
// color: Color.GRAY,
// },
// scaleType: ScaleType.ScaleAspectFill,
// layoutConfig: layoutConfig().just(),
// }),
// label('ImageBase64'),
// image({
// imageBase64: img_base64[0],
// width: 300,
// height: 300,
// border: {
// width: 2,
// color: Color.GRAY,
// },
// scaleType: ScaleType.ScaleAspectFill,
// layoutConfig: layoutConfig().just(),
// }),
// label('StretchInset'),
// image({
// imageBase64: img_base64[1],
// height: 60,
// width: 134,
// scaleType: ScaleType.ScaleAspectFill,
// layoutConfig: layoutConfig().just(),
// }),
// image({
// imageBase64: img_base64[1],
// height: 60,
// width: 294,
// scaleType: ScaleType.ScaleToFill,
// layoutConfig: layoutConfig().just(),
// stretchInset: {
// left: 0.85,
// top: 0,
// right: 0.149,
// bottom: 0
// }
// }),
],
{
layoutConfig: layoutConfig().most().configHeight(LayoutSpec.FIT),

View File

@ -23,6 +23,7 @@
#import <Foundation/Foundation.h>
#import "DoricMonitorProtocol.h"
#import <UIKit/UIKit.h>
#import "DoricResourceLoaderManager.h"
NS_ASSUME_NONNULL_BEGIN
@class DoricLibrary;
@ -33,6 +34,7 @@ NS_ASSUME_NONNULL_BEGIN
@property(nonatomic, strong) UIImage *defaultPlaceHolderImage;
@property(nonatomic, strong) UIImage *defaultErrorImage;
@property(nonatomic, strong) id <DoricPerformanceGlobalAnchorHookProtocol> globalPerformanceAnchorHook;
@property(nonatomic, strong) DoricResourceLoaderManager *loaderManager;
- (instancetype)initWithJSEngine:(DoricJSEngine *)jsEngine;

View File

@ -56,6 +56,10 @@
#import "DoricJSEngine.h"
#import "DoricSingleton.h"
#import "DoricGestureContainerNode.h"
#import "DoricBundleResourceLoader.h"
#import "DoricBase64ResourceLoader.h"
#import "DoricLocalResourceLoader.h"
#import "DoricRemoteResourceLoader.h"
@interface DoricRegistry ()
@ -83,6 +87,7 @@ - (instancetype)initWithJSEngine:(DoricJSEngine *)jsEngine {
_plugins = [NSMutableDictionary new];
_nodes = [NSMutableDictionary new];
_monitors = [NSMutableSet new];
_loaderManager = [DoricResourceLoaderManager new];
[self innerRegister];
[DoricSingleton.instance.libraries enumerateObjectsUsingBlock:^(DoricLibrary *obj, BOOL *stop) {
[obj load:self];
@ -127,6 +132,13 @@ - (void)innerRegister {
[self registerViewNode:DoricSwitchNode.class withName:@"Switch"];
[self registerViewNode:DoricFlexNode.class withName:@"FlexLayout"];
[self registerViewNode:DoricGestureContainerNode.class withName:@"GestureContainer"];
[self.loaderManager registerLoader:[[DoricBundleResourceLoader alloc]
initWithResourceType:@"mainBundle"
bundle:[NSBundle mainBundle]]];
[self.loaderManager registerLoader:[DoricLocalResourceLoader new]];
[self.loaderManager registerLoader:[DoricRemoteResourceLoader new]];
[self.loaderManager registerLoader:[DoricBase64ResourceLoader new]];
}
- (void)registerJSBundle:(NSString *)bundle withName:(NSString *)name {

View File

@ -0,0 +1,25 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import <Foundation/Foundation.h>
#import "DoricResource.h"
@interface DoricBase64Resource : DoricResource
@end

View File

@ -0,0 +1,35 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import "DoricBase64Resource.h"
@implementation DoricBase64Resource
- (DoricAsyncResult <NSData *> *)fetchRaw {
DoricAsyncResult *result = [DoricAsyncResult new];
NSString *inString = nil;
if ([self.identifier hasPrefix:@"data:image"]) {
inString = [self.identifier componentsSeparatedByString:@","].lastObject;
}
NSData *data = [[NSData alloc] initWithBase64EncodedString:inString
options:NSDataBase64DecodingIgnoreUnknownCharacters];
[result setupResult:data];
return result;
}
@end

View File

@ -0,0 +1,25 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import <Foundation/Foundation.h>
#import "DoricResourceLoader.h"
@interface DoricBase64ResourceLoader : NSObject <DoricResourceLoader>
@end

View File

@ -0,0 +1,31 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import "DoricBase64ResourceLoader.h"
#import "DoricBase64Resource.h"
@implementation DoricBase64ResourceLoader
- (NSString *)resourceType {
return @"base64";
}
- (__kindof DoricResource *)load:(NSString *)identifier withContext:(DoricContext *)context {
return [[DoricBase64Resource alloc] initWithContext:context identifier:identifier];
}
@end

View File

@ -0,0 +1,26 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import <Foundation/Foundation.h>
#import "DoricResource.h"
#import "DoricContext.h"
@interface DoricBundleResource : DoricResource
@property(nonatomic, strong) NSBundle *bundle;
@end

View File

@ -0,0 +1,31 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import "DoricBundleResource.h"
@implementation DoricBundleResource
- (DoricAsyncResult <NSData *> *)fetchRaw {
DoricAsyncResult *result = [DoricAsyncResult new];
NSString *path = [self.bundle bundlePath];
NSString *fullPath = [path stringByAppendingPathComponent:self.identifier];
NSData *imgData = [[NSData alloc] initWithContentsOfFile:fullPath];
[result setupResult:imgData];
return result;
}
@end

View File

@ -0,0 +1,26 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import <Foundation/Foundation.h>
#import "DoricResourceLoader.h"
@interface DoricBundleResourceLoader : NSObject <DoricResourceLoader>
- (instancetype)initWithResourceType:(NSString *)resourceType bundle:(NSBundle *)bundle;
@end

View File

@ -0,0 +1,45 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import <DoricExtensions.h>
#import "DoricBundleResourceLoader.h"
#import "DoricBundleResource.h"
@interface DoricBundleResourceLoader ()
@property(nonatomic, strong) NSBundle *bundle;
@property(nonatomic, copy) NSString *resourceType;
@end
@implementation DoricBundleResourceLoader
- (instancetype)initWithResourceType:(NSString *)resourceType bundle:(NSBundle *)bundle {
if (self = [super init]) {
_resourceType = resourceType;
_bundle = bundle;
}
return self;
}
- (__kindof DoricResource *)load:(NSString *)identifier withContext:(DoricContext *)context {
return [[[DoricBundleResource alloc] initWithContext:context identifier:identifier]
also:^(DoricBundleResource *it) {
it.bundle = self.bundle;
}];
}
@end

View File

@ -0,0 +1,24 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import <Foundation/Foundation.h>
#import "DoricResource.h"
@interface DoricLocalResource : DoricResource
@end

View File

@ -0,0 +1,30 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import "DoricLocalResource.h"
@implementation DoricLocalResource
- (DoricAsyncResult <NSData *> *)fetchRaw {
DoricAsyncResult *result = [DoricAsyncResult new];
NSData *imgData = [[NSData alloc] initWithContentsOfFile:self.identifier];
[result setupResult:imgData];
return result;
}
@end

View File

@ -0,0 +1,24 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import <Foundation/Foundation.h>
#import "DoricResourceLoader.h"
@interface DoricLocalResourceLoader : NSObject <DoricResourceLoader>
@end

View File

@ -0,0 +1,32 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import "DoricLocalResourceLoader.h"
#import "DoricLocalResource.h"
@implementation DoricLocalResourceLoader
- (NSString *)resourceType {
return @"local";
}
- (__kindof DoricResource *)load:(NSString *)identifier withContext:(DoricContext *)context {
return [[DoricLocalResource alloc] initWithContext:context identifier:identifier];
}
@end

View File

@ -0,0 +1,24 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import <Foundation/Foundation.h>
#import "DoricResource.h"
@interface DoricRemoteResource : DoricResource
@end

View File

@ -0,0 +1,33 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import "DoricRemoteResource.h"
@implementation DoricRemoteResource
- (DoricAsyncResult <NSData *> *)fetchRaw {
DoricAsyncResult *result = [DoricAsyncResult new];
NSURL *url = [NSURL URLWithString:self.identifier];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *urlData = [NSData dataWithContentsOfURL:url];
[result setupResult:urlData];
});
return result;
}
@end

View File

@ -0,0 +1,25 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import <Foundation/Foundation.h>
#import "DoricResourceLoader.h"
@interface DoricRemoteResourceLoader : NSObject <DoricResourceLoader>
@end

View File

@ -0,0 +1,31 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/25.
//
#import "DoricRemoteResourceLoader.h"
#import "DoricRemoteResource.h"
@implementation DoricRemoteResourceLoader
- (NSString *)resourceType {
return @"remote";
}
- (__kindof DoricResource *)load:(NSString *)identifier withContext:(DoricContext *)context {
return [[DoricRemoteResource alloc] initWithContext:context identifier:identifier];
}
@end

View File

@ -0,0 +1,32 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/22.
//
#import <Foundation/Foundation.h>
#import "DoricAsyncResult.h"
@class DoricContext;
@interface DoricResource : NSObject
@property(nonatomic, weak) DoricContext *context;
@property(nonatomic, copy) NSString *identifier;
- (instancetype)initWithContext:(DoricContext *)context identifier:(NSString *)identifier;
- (DoricAsyncResult <NSData *> *)fetchRaw;
@end

View File

@ -0,0 +1,33 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/22.
//
#import "DoricResource.h"
@implementation DoricResource
- (instancetype)initWithContext:(DoricContext *)context identifier:(NSString *)identifier {
if (self = [super init]) {
_context = context;
_identifier = identifier;
}
return self;
}
- (DoricAsyncResult<NSData *> *)fetchRaw {
return nil;
}
@end

View File

@ -0,0 +1,27 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/22.
//
#import <Foundation/Foundation.h>
#import "DoricResource.h"
@protocol DoricResourceLoader
@property(nonatomic, readonly) NSString *resourceType;
- (__kindof DoricResource *)load:(NSString *)identifier withContext:(DoricContext *)context;
@end

View File

@ -0,0 +1,31 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/22.
//
#import <Foundation/Foundation.h>
#import "DoricResourceLoader.h"
@interface DoricResourceLoaderManager : NSObject
- (void)registerLoader:(id <DoricResourceLoader>)loader;
- (void)unRegisterLoader:(id <DoricResourceLoader>)loader;
- (__kindof DoricResource *)load:(NSString *)identifier
withResourceType:(NSString *)resourceType
withContext:(DoricContext *)context;
@end

View File

@ -0,0 +1,49 @@
/*
* Copyright [2021] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2021/10/22.
//
#import "DoricResourceLoaderManager.h"
@interface DoricResourceLoaderManager ()
@property(nonatomic, strong) NSMutableDictionary <NSString *, id <DoricResourceLoader>> *loaders;
@end
@implementation DoricResourceLoaderManager
- (instancetype)init {
if (self = [super init]) {
_loaders = [NSMutableDictionary new];
}
return self;
}
- (void)registerLoader:(id <DoricResourceLoader>)loader {
self.loaders[loader.resourceType] = loader;
}
- (void)unRegisterLoader:(id <DoricResourceLoader>)loader {
[self.loaders removeObjectForKey:loader.resourceType];
}
- (__kindof DoricResource *)load:(NSString *)identifier
withResourceType:(NSString *)resourceType
withContext:(DoricContext *)context {
id <DoricResourceLoader> loader = self.loaders[resourceType];
return [loader load:identifier withContext:context];
}
@end

View File

@ -233,7 +233,57 @@ - (UIImage *)currentErrorImage {
}
- (void)blendView:(UIImageView *)view forPropName:(NSString *)name propValue:(id)prop {
if ([@"imageUrl" isEqualToString:name]) {
if ([@"image" isEqualToString:name]) {
NSString *type = prop[@"type"];
NSString *identifier = prop[@"identifier"];
DoricAsyncResult <NSData *> *asyncResult = [[self.doricContext.driver.registry.loaderManager
load:identifier withResourceType:type withContext:self.doricContext] fetchRaw];
[asyncResult setResultCallback:^(NSData *imageData) {
[self.doricContext dispatchToMainQueue:^{
#if DORIC_USE_YYWEBIMAGE
YYImage *image = [YYImage imageWithData:imageData scale:self.imageScale];
#elif DORIC_USE_SDWEBIMAGE
UIImage *image = [SDAnimatedImage imageWithData:imageData scale:self.imageScale];
if (!image) {
image = [UIImage imageWithData:imageData scale:self.imageScale];
}
#else
UIImage *image = [UIImage imageWithData:imageData scale:self.imageScale];
#endif
view.image = image;
DoricSuperNode *node = self.superNode;
while (node.superNode != nil) {
node = node.superNode;
}
[node requestLayout];
if (self.loadCallbackId.length > 0) {
if (image) {
[self callJSResponse:self.loadCallbackId,
@{
@"width": @(image.size.width),
@"height": @(image.size.height),
#if DORIC_USE_YYWEBIMAGE
@"animated": (image.animatedImageData != nil) ? @(YES) : @(NO),
#elif DORIC_USE_SDWEBIMAGE
@"animated": ([image isKindOfClass:SDAnimatedImage.class]
&& ((SDAnimatedImage *) image).animatedImageFrameCount > 0)
? @(YES)
: @(NO),
#else
@"animated": @(NO),
#endif
},
nil];
} else {
[self callJSResponse:self.loadCallbackId, nil];
}
}
}];
}];
[asyncResult setExceptionCallback:^(NSException *e) {
DoricLog(@"Cannot load resource type = %@, identifier = %@, %@", type, identifier, e.reason);
}];
} else if ([@"imageUrl" isEqualToString:name]) {
__weak typeof(self) _self = self;
__block BOOL async = NO;
view.doricLayout.undefined = YES;

View File

@ -2147,12 +2147,12 @@ var Resource = /** @class */ (function () {
};
return Resource;
}());
var FileResource = /** @class */ (function (_super) {
__extends$e(FileResource, _super);
function FileResource(path) {
return _super.call(this, "file", path) || this;
var LocalResource = /** @class */ (function (_super) {
__extends$e(LocalResource, _super);
function LocalResource(path) {
return _super.call(this, "local", path) || this;
}
return FileResource;
return LocalResource;
}(Resource));
var RemoteResource = /** @class */ (function (_super) {
__extends$e(RemoteResource, _super);
@ -2163,8 +2163,8 @@ var RemoteResource = /** @class */ (function (_super) {
}(Resource));
var Base64Resource = /** @class */ (function (_super) {
__extends$e(Base64Resource, _super);
function Base64Resource(url) {
return _super.call(this, "base64", url) || this;
function Base64Resource(content) {
return _super.call(this, "base64", content) || this;
}
return Base64Resource;
}(Resource));
@ -2173,15 +2173,15 @@ var Base64Resource = /** @class */ (function (_super) {
*/
var DrawableResource = /** @class */ (function (_super) {
__extends$e(DrawableResource, _super);
function DrawableResource(url) {
return _super.call(this, "drawable", url) || this;
function DrawableResource(name) {
return _super.call(this, "drawable", name) || this;
}
return DrawableResource;
}(Resource));
var RawResource = /** @class */ (function (_super) {
__extends$e(RawResource, _super);
function RawResource(url) {
return _super.call(this, "raw", url) || this;
function RawResource(name) {
return _super.call(this, "raw", name) || this;
}
return RawResource;
}(Resource));
@ -4395,7 +4395,6 @@ exports.CENTER_Y = CENTER_Y;
exports.Color = Color;
exports.Draggable = Draggable;
exports.DrawableResource = DrawableResource;
exports.FileResource = FileResource;
exports.FlexLayout = FlexLayout;
exports.FlexTypedValue = FlexTypedValue;
exports.FlowLayout = FlowLayout;
@ -4411,6 +4410,7 @@ exports.LEFT = LEFT;
exports.LayoutConfigImpl = LayoutConfigImpl;
exports.List = List;
exports.ListItem = ListItem;
exports.LocalResource = LocalResource;
exports.MainBundleResource = MainBundleResource;
exports.ModularPanel = ModularPanel;
exports.Module = Module;

View File

@ -1615,9 +1615,9 @@ class Resource {
};
}
}
class FileResource extends Resource {
class LocalResource extends Resource {
constructor(path) {
super("file", path);
super("local", path);
}
}
class RemoteResource extends Resource {
@ -1626,21 +1626,21 @@ class RemoteResource extends Resource {
}
}
class Base64Resource extends Resource {
constructor(url) {
super("base64", url);
constructor(content) {
super("base64", content);
}
}
/**
* This is for android platform
*/
class DrawableResource extends Resource {
constructor(url) {
super("drawable", url);
constructor(name) {
super("drawable", name);
}
}
class RawResource extends Resource {
constructor(url) {
super("raw", url);
constructor(name) {
super("raw", name);
}
}
class AssetResource extends Resource {
@ -3378,7 +3378,6 @@ exports.CENTER_Y = CENTER_Y;
exports.Color = Color;
exports.Draggable = Draggable;
exports.DrawableResource = DrawableResource;
exports.FileResource = FileResource;
exports.FlexLayout = FlexLayout;
exports.FlexTypedValue = FlexTypedValue;
exports.FlowLayout = FlowLayout;
@ -3394,6 +3393,7 @@ exports.LEFT = LEFT;
exports.LayoutConfigImpl = LayoutConfigImpl;
exports.List = List;
exports.ListItem = ListItem;
exports.LocalResource = LocalResource;
exports.MainBundleResource = MainBundleResource;
exports.ModularPanel = ModularPanel;
exports.Module = Module;

View File

@ -3136,9 +3136,9 @@ class Resource {
};
}
}
class FileResource extends Resource {
class LocalResource extends Resource {
constructor(path) {
super("file", path);
super("local", path);
}
}
class RemoteResource extends Resource {
@ -3147,21 +3147,21 @@ class RemoteResource extends Resource {
}
}
class Base64Resource extends Resource {
constructor(url) {
super("base64", url);
constructor(content) {
super("base64", content);
}
}
/**
* This is for android platform
*/
class DrawableResource extends Resource {
constructor(url) {
super("drawable", url);
constructor(name) {
super("drawable", name);
}
}
class RawResource extends Resource {
constructor(url) {
super("raw", url);
constructor(name) {
super("raw", name);
}
}
class AssetResource extends Resource {
@ -5140,7 +5140,6 @@ exports.CENTER_Y = CENTER_Y;
exports.Color = Color;
exports.Draggable = Draggable;
exports.DrawableResource = DrawableResource;
exports.FileResource = FileResource;
exports.FlexLayout = FlexLayout;
exports.FlexTypedValue = FlexTypedValue;
exports.FlowLayout = FlowLayout;
@ -5156,6 +5155,7 @@ exports.LEFT = LEFT;
exports.LayoutConfigImpl = LayoutConfigImpl;
exports.List = List;
exports.ListItem = ListItem;
exports.LocalResource = LocalResource;
exports.MainBundleResource = MainBundleResource;
exports.ModularPanel = ModularPanel;
exports.Module = Module;

8
doric-js/index.d.ts vendored
View File

@ -1635,23 +1635,23 @@ declare module 'doric/lib/src/util/resource' {
identifier: string;
};
}
export class FileResource extends Resource {
export class LocalResource extends Resource {
constructor(path: string);
}
export class RemoteResource extends Resource {
constructor(url: string);
}
export class Base64Resource extends Resource {
constructor(url: string);
constructor(content: string);
}
/**
* This is for android platform
*/
export class DrawableResource extends Resource {
constructor(url: string);
constructor(name: string);
}
export class RawResource extends Resource {
constructor(url: string);
constructor(name: string);
}
export class AssetResource extends Resource {
constructor(path: string);

View File

@ -8,23 +8,23 @@ export declare abstract class Resource implements Modeling {
identifier: string;
};
}
export declare class FileResource extends Resource {
export declare class LocalResource extends Resource {
constructor(path: string);
}
export declare class RemoteResource extends Resource {
constructor(url: string);
}
export declare class Base64Resource extends Resource {
constructor(url: string);
constructor(content: string);
}
/**
* This is for android platform
*/
export declare class DrawableResource extends Resource {
constructor(url: string);
constructor(name: string);
}
export declare class RawResource extends Resource {
constructor(url: string);
constructor(name: string);
}
export declare class AssetResource extends Resource {
constructor(path: string);

View File

@ -10,9 +10,9 @@ export class Resource {
};
}
}
export class FileResource extends Resource {
export class LocalResource extends Resource {
constructor(path) {
super("file", path);
super("local", path);
}
}
export class RemoteResource extends Resource {
@ -21,21 +21,21 @@ export class RemoteResource extends Resource {
}
}
export class Base64Resource extends Resource {
constructor(url) {
super("base64", url);
constructor(content) {
super("base64", content);
}
}
/**
* This is for android platform
*/
export class DrawableResource extends Resource {
constructor(url) {
super("drawable", url);
constructor(name) {
super("drawable", name);
}
}
export class RawResource extends Resource {
constructor(url) {
super("raw", url);
constructor(name) {
super("raw", name);
}
}
export class AssetResource extends Resource {

View File

@ -15,9 +15,9 @@ export abstract class Resource implements Modeling {
}
}
export class FileResource extends Resource {
export class LocalResource extends Resource {
constructor(path: string) {
super("file", path);
super("local", path);
}
}

View File

@ -3190,9 +3190,9 @@ class Resource {
};
}
}
class FileResource extends Resource {
class LocalResource extends Resource {
constructor(path) {
super("file", path);
super("local", path);
}
}
class RemoteResource extends Resource {
@ -3201,21 +3201,21 @@ class RemoteResource extends Resource {
}
}
class Base64Resource extends Resource {
constructor(url) {
super("base64", url);
constructor(content) {
super("base64", content);
}
}
/**
* This is for android platform
*/
class DrawableResource extends Resource {
constructor(url) {
super("drawable", url);
constructor(name) {
super("drawable", name);
}
}
class RawResource extends Resource {
constructor(url) {
super("raw", url);
constructor(name) {
super("raw", name);
}
}
class AssetResource extends Resource {
@ -4953,7 +4953,6 @@ exports.CENTER_Y = CENTER_Y;
exports.Color = Color;
exports.Draggable = Draggable;
exports.DrawableResource = DrawableResource;
exports.FileResource = FileResource;
exports.FlexLayout = FlexLayout;
exports.FlexTypedValue = FlexTypedValue;
exports.FlowLayout = FlowLayout;
@ -4969,6 +4968,7 @@ exports.LEFT = LEFT;
exports.LayoutConfigImpl = LayoutConfigImpl;
exports.List = List;
exports.ListItem = ListItem;
exports.LocalResource = LocalResource;
exports.MainBundleResource = MainBundleResource;
exports.ModularPanel = ModularPanel;
exports.Module = Module;