create-expo-cljs-app
Version:
Create a react native application with Expo and Shadow-CLJS!
115 lines (105 loc) • 3.21 kB
text/typescript
import { Platform, UnavailabilityError } from 'expo-modules-core';
import invariant from 'invariant';
import { Dimensions } from 'react-native';
type PackagerAsset = {
__packager_asset: boolean;
fileSystemLocation: string;
httpServerLocation: string;
width?: number;
height?: number;
scales: number[];
hash: string;
name: string;
type: string;
};
function getBasePath({ httpServerLocation }: PackagerAsset): string {
if (httpServerLocation[0] === '/') {
return httpServerLocation.substr(1);
}
return httpServerLocation;
}
export type ResolvedAssetSource = {
__packager_asset: boolean;
width?: number;
height?: number;
uri: string;
scale: number;
};
function getScale(): number {
return Dimensions.get('window').scale;
}
function getScaledAssetPath(asset): string {
const scale = AssetSourceResolver.pickScale(asset.scales, getScale());
const scaleSuffix = scale === 1 ? '' : '@' + scale + 'x';
const assetDir = getBasePath(asset);
return assetDir + '/' + asset.name + scaleSuffix + (asset.type ? `.${asset.type}` : '');
}
export default class AssetSourceResolver {
serverUrl?: string | null;
// where the jsbundle is being run from
jsbundleUrl?: string | null;
// the asset to resolve
asset: PackagerAsset;
constructor(
serverUrl: string | undefined | null,
jsbundleUrl: string | undefined | null,
asset: PackagerAsset
) {
this.serverUrl = serverUrl;
this.jsbundleUrl = jsbundleUrl;
this.asset = asset;
}
isLoadedFromServer(): boolean {
return !!this.serverUrl;
}
isLoadedFromFileSystem(): boolean {
return !!(this.jsbundleUrl && this.jsbundleUrl.startsWith('file://'));
}
defaultAsset(): ResolvedAssetSource {
if (this.isLoadedFromServer()) {
return this.assetServerURL();
}
return this.scaledAssetURLNearBundle();
}
assetServerURL(): ResolvedAssetSource {
invariant(!!this.serverUrl, 'need server to load from');
return this.fromSource(
this.serverUrl +
getScaledAssetPath(this.asset) +
'?platform=' +
Platform.OS +
'&hash=' +
this.asset.hash
);
}
scaledAssetPath(): ResolvedAssetSource {
return this.fromSource(getScaledAssetPath(this.asset));
}
scaledAssetURLNearBundle(): ResolvedAssetSource {
const path = this.jsbundleUrl || '';
return this.fromSource(path + getScaledAssetPath(this.asset));
}
resourceIdentifierWithoutScale(): ResolvedAssetSource {
throw new UnavailabilityError('react-native', 'resourceIdentifierWithoutScale()');
}
drawableFolderInBundle(): ResolvedAssetSource {
throw new UnavailabilityError('react-native', 'drawableFolderInBundle()');
}
fromSource(source: string): ResolvedAssetSource {
return {
__packager_asset: true,
width: this.asset.width,
height: this.asset.height,
uri: source,
scale: AssetSourceResolver.pickScale(this.asset.scales, getScale()),
};
}
static pickScale(scales: number[], deviceScale: number): number {
for (let i = 0; i < scales.length; i++) {
if (scales[i] >= deviceScale) {
return scales[i];
}
}
return scales[scales.length - 1] || 1;
}
}