UNPKG

@angelengineering/filepicker

Version:
172 lines 7.2 kB
import * as platform from '@nativescript/core/platform'; import * as application from '@nativescript/core/application'; import * as appSettings from '@nativescript/core/application-settings'; import { File, knownFolders } from '@nativescript/core'; const PATH_LIST_KEY = 'TempFile::deletePathLater'; function getPathList() { const pathListJSON = appSettings.getString(PATH_LIST_KEY, '[]'); let pathList = []; try { pathList = JSON.parse(pathListJSON); } catch (e) { console.warn('Failed to parse path list: ' + pathListJSON); } return pathList; } function setPathList(pathList) { appSettings.setString(PATH_LIST_KEY, JSON.stringify(pathList)); } export class TempFile { // return the absolute path to a temporary file, also registering it to // be deleted later (e.g. when the app closes) static getPath(prefix, suffix) { let path = null; if (platform.isAndroid) { const context = application.android.context; //The system will automatically delete files in the cache directory as disk space is needed elsewhere on the device. // we'll attempt to get an external sd card first if one is available const dir = context.getExternalCacheDir() || context.getCacheDir(); const file = java.io.File.createTempFile(prefix, suffix, dir); path = file.getAbsolutePath(); } else if (platform.isIOS) { const name = NSUUID.UUID().UUIDString; path = knownFolders.temp().getFile(prefix + name + suffix).path; } TempFile.deletePathLater(path); // console.log('TempFile returning path', path); return path; } // add the given path to a list to be deleted later static deletePathLater(path) { const pathList = getPathList(); pathList.push(path); setPathList(pathList); // NOTE: this only deletes the file on VM exit, which does not cover all // app exit scenarios: https://developer.android.com/reference/java/io/File.html#deleteOnExit() // So, we will call cleanup() on app init as well if (platform.isAndroid) { const file = new java.io.File(path); file.deleteOnExit(); } } // delete stored paths static cleanup() { const pathList = getPathList(); for (const path of pathList) { if (!path) continue; try { if (!File.exists(path)) continue; } catch (e) { console.warn('Failed while looking for file at ' + path + ': ' + e.toString()); continue; } const file = File.fromPath(path); // console.log('removing temporary file ', path); file.remove().catch((reason) => { console.warn('Failed to delete file at ' + path + ' : ' + reason.toString()); TempFile.deletePathLater(path); }); } setPathList([]); } } export class AssetDownloader { constructor(asset) { this.asset = asset; this._path = null; } download() { return new Promise((resolve, reject) => { // try to get a local resource of the appropriate type for the asset const resource = this.getResource(); if (resource) this.fetchResource(resource, resolve); // if there are no resources, we may need to use an export session // for videos stored on iCloud else if (this.asset.mediaType == 2 /* PHAssetMediaType.Video */) { this.exportVideo(resolve); } else { console.warn('Unable to convert media asset to a file'); resolve(null); } }); } get path() { if (!this._path) { // make a temp file but ensure it doesn't exist so iOS will write to it this._path = TempFile.getPath('asset', '.tmp'); File.fromPath(this._path).removeSync(); } return this._path; } getResource() { // get the media type we're looking for let expectedType = 1 /* PHAssetResourceType.Photo */; if (this.asset.mediaType == 2 /* PHAssetMediaType.Video */) expectedType = 2 /* PHAssetResourceType.Video */; if (this.asset.mediaType == 3 /* PHAssetMediaType.Audio */) expectedType = 3 /* PHAssetResourceType.Audio */; // look through resources for one of the desired type const resources = PHAssetResource.assetResourcesForAsset(this.asset); for (const resource of resources) { if (resource.type === expectedType) return resource; } return null; } fetchResource(resource, resolve) { const options = PHAssetResourceRequestOptions.alloc().init(); options.networkAccessAllowed = true; const toURL = NSURL.fileURLWithPath(this.path); PHAssetResourceManager.defaultManager().writeDataForAssetResourceToFileOptionsCompletionHandler(resource, toURL, options, (e) => { if (e) { console.error('Failed to copy asset: ' + e.description); resolve(null); } else { const file = File.fromPath(this.path); file['originalFilename'] = resource.originalFilename; resolve(file); } }); } exportVideo(resolve) { const options = new PHVideoRequestOptions(); options.networkAccessAllowed = true; options.deliveryMode = 3 /* PHVideoRequestOptionsDeliveryMode.FastFormat */; PHImageManager.defaultManager().requestExportSessionForVideoOptionsExportPresetResultHandler(this.asset, options, AVAssetExportPresetLowQuality, (session, info) => { // export the video to our temp file session.outputURL = NSURL.fileURLWithPath(this.path); session.outputFileType = AVFileTypeMPEG4; session.exportAsynchronouslyWithCompletionHandler(() => { const status = session.status; try { if (status == 3 /* AVAssetExportSessionStatus.Completed */) { resolve(File.fromPath(this.path)); return; } else if (status == 4 /* AVAssetExportSessionStatus.Failed */) { throw new Error('Failed to export asset: ' + (session.error ? session.error.description : '(no message)')); } else if (status == 5 /* AVAssetExportSessionStatus.Cancelled */) { // "cancelled" is valid } else { throw new Error('Asset export did not complete for unknown reasons - status: ' + status); } } catch (e) { console.error(e); } resolve(null); }); }); } } //# sourceMappingURL=files.js.map