Skip to content

Commit 18bba2b

Browse files
feat(file-system): allow copy when opening a File (#10274)
* feat: add copy file to file-system * feat(file-system): allow temp copy of files opened with File.fromPath * chore: remove log * chore: remove log * fix: only copy if true --------- Co-authored-by: Nathan Walker <walkerrunpdx@gmail.com>
1 parent 4551da0 commit 18bba2b

File tree

7 files changed

+103
-33
lines changed

7 files changed

+103
-33
lines changed

apps/automated/src/file-system/file-system-tests.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,3 +698,24 @@ export function test_FolderClear_RemovesEmptySubfolders(done) {
698698
})
699699
.catch(done);
700700
}
701+
702+
export function test_FileCopy(done) {
703+
const now = Date.now();
704+
const tempFile = fs.File.fromPath(fs.path.join(fs.knownFolders.temp().path, `${now}.txt`));
705+
const content = 'Hello World: ' + now;
706+
tempFile.writeTextSync(content);
707+
const tempCopy = fs.File.fromPath(fs.path.join(fs.knownFolders.temp().path, `${now}-copy.txt`));
708+
tempFile
709+
.copy(tempCopy.path)
710+
.then(() => {
711+
TKUnit.assert(tempCopy.size === tempFile.size);
712+
return tempCopy.readText();
713+
})
714+
.then((value) => {
715+
TKUnit.assert(value === content);
716+
717+
return Promise.allSettled([tempFile.remove(), tempCopy.remove()]);
718+
})
719+
.then(() => done())
720+
.catch(done);
721+
}

apps/toolbox/src/pages/fs-helper.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,12 @@ export function pickFile() {
110110
//const file = File.fromPath(args.intent.getData().toString());
111111
//console.log(file);
112112
//readFile(file);
113-
copyFile(file);
113+
//copyFile(file);
114+
console.time('fromPath: copy');
115+
const f = File.fromPath(file, true);
116+
console.timeEnd('fromPath: copy');
117+
console.log('old path: ', file);
118+
console.log('new path: ', f.path, f.extension, f.size);
114119
}
115120
});
116121
const Intent = android.content.Intent;

packages/core/file-system/file-system-access.android.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ function getApplicationContext() {
1515
}
1616

1717
function getOrSetHelper(path: string): org.nativescript.widgets.FileHelper {
18-
return org.nativescript.widgets.FileHelper.fromString(applicationContext, path);
18+
return org.nativescript.widgets.FileHelper.fromString(getApplicationContext(), path);
1919
}
2020

2121
function isContentUri(path: string): boolean {
@@ -766,6 +766,7 @@ export class FileSystemAccess29 extends FileSystemAccess {
766766
if (isContentUri(path)) {
767767
try {
768768
const file = getOrSetHelper(path);
769+
769770
return {
770771
path,
771772
name: file.getName(),

packages/core/file-system/index.d.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,27 @@ export class File extends FileSystemEntity {
8080
*/
8181
isLocked: boolean;
8282

83+
/**
84+
* Copies a file to a given path.
85+
* @param dest The path to the destination file.
86+
* Returns a Promise with a boolean.
87+
*/
88+
copy(dest: string): Promise<boolean>;
89+
90+
/**
91+
* Copies a file to a given path.
92+
* @param dest The path to the destination file.
93+
* @param onError (optional) A callback function to use if any error occurs.
94+
* Returns a Promise with a boolean.
95+
*/
96+
copySync(dest: string, onError?: (error: any) => any): any;
97+
8398
/**
8499
* Gets or creates a File entity at the specified path.
85100
* @param path The path to get/create the file at.
101+
* @param copy An optional value when set, copies the content-uri to a temp file enabling the legacy behaviour
86102
*/
87-
static fromPath(path: string): File;
103+
static fromPath(path: string, copy?: boolean): File;
88104

89105
/**
90106
* Reads the content of the file as a string using the specified encoding (defaults to UTF-8).

packages/core/file-system/index.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { IFileSystemAccess, FileSystemAccess, FileSystemAccess29 } from './file-system-access';
22
import { SDK_VERSION } from '../utils/constants';
3+
import { getNativeApplication } from '../application';
34
// The FileSystemAccess implementation, used through all the APIs.
45
let fileAccess: IFileSystemAccess;
56

@@ -180,12 +181,39 @@ export class FileSystemEntity {
180181
}
181182
}
182183

184+
let applicationContext;
185+
function getApplicationContext() {
186+
if (!applicationContext) {
187+
applicationContext = (<android.app.Application>getNativeApplication()).getApplicationContext();
188+
}
189+
190+
return applicationContext;
191+
}
192+
183193
export class File extends FileSystemEntity {
184-
public static fromPath(path: string) {
194+
public static fromPath(path: string, copy: boolean = false) {
185195
const onError = function (error) {
186196
throw error;
187197
};
188198

199+
if (global.isAndroid && copy) {
200+
if (path.startsWith('content:')) {
201+
const fileInfo = getFileAccess().getFile(path, onError);
202+
// falls back to creating a temp file without a known extension.
203+
if (!fileInfo) {
204+
const tempFile = `${knownFolders.temp().path}/${java.util.UUID.randomUUID().toString()}`;
205+
org.nativescript.widgets.Async.File.copySync(path, tempFile, getApplicationContext());
206+
path = tempFile;
207+
} else {
208+
const ext = fileInfo.extension;
209+
const name = `${fileInfo.name.replace(`.${ext}`, '')}.${ext}`;
210+
const tempFile = `${knownFolders.temp().path}/${name}`;
211+
getFileAccess().copySync(path, tempFile);
212+
path = tempFile;
213+
}
214+
}
215+
}
216+
189217
const fileInfo = getFileAccess().getFile(path, onError);
190218
if (!fileInfo) {
191219
return undefined;
Binary file not shown.

packages/ui-mobile-base/android/widgets/src/main/java/org/nativescript/widgets/FileHelper.java

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,8 @@ public interface Callback {
5353
}
5454

5555
private static boolean isExternalStorageDocument(Uri uri) {
56-
return false;
57-
// return "com.android.externalstorage.documents".equals(uri
58-
// .getAuthority());
56+
return "com.android.externalstorage.documents".equals(uri
57+
.getAuthority());
5958
}
6059

6160
private static @Nullable
@@ -132,7 +131,9 @@ File getFile(Context context, Uri uri) {
132131
String path = split[1];
133132

134133
if ("primary".equals(type)) {
135-
String[] parts = Uri.decode(uri.toString()).split(":" + path + "/");
134+
int nameIndex = path.lastIndexOf("/");
135+
String seg = path.substring(0, nameIndex);
136+
String[] parts = Uri.decode(uri.toString()).split(":" + seg);
136137
String file = Environment.getExternalStorageDirectory() + "/" + path + "/" + parts[1];
137138
return new File(file);
138139
} else {
@@ -178,22 +179,21 @@ FileHelper fromUri(Context context, Uri contentUri) {
178179
return null;
179180
}
180181

181-
int sizeIndex = cursor.getColumnIndex(
182-
MediaStore.MediaColumns.SIZE
183-
);
184-
185-
int nameIndex = cursor.getColumnIndex(
186-
MediaStore.MediaColumns.DISPLAY_NAME
187-
);
188-
189-
int lastModifiedIndex = cursor.getColumnIndex(
190-
MediaStore.MediaColumns.DATE_MODIFIED
191-
);
192-
193-
194182
boolean moved = cursor.moveToFirst();
195183
FileHelper helper = null;
196184
if (moved) {
185+
int sizeIndex = cursor.getColumnIndex(
186+
MediaStore.MediaColumns.SIZE
187+
);
188+
189+
int nameIndex = cursor.getColumnIndex(
190+
MediaStore.MediaColumns.DISPLAY_NAME
191+
);
192+
193+
int lastModifiedIndex = cursor.getColumnIndex(
194+
MediaStore.MediaColumns.DATE_MODIFIED
195+
);
196+
197197
helper = new FileHelper(uri);
198198
helper.size = cursor.getLong(sizeIndex);
199199
helper.name = cursor.getString(nameIndex);
@@ -244,22 +244,21 @@ private void updateInternal(Context context, boolean force) {
244244
return;
245245
}
246246

247-
int sizeIndex = cursor.getColumnIndex(
248-
MediaStore.MediaColumns.SIZE
249-
);
250-
251-
int nameIndex = cursor.getColumnIndex(
252-
MediaStore.MediaColumns.DISPLAY_NAME
253-
);
247+
boolean moved = cursor.moveToFirst();
254248

255-
int lastModifiedIndex = cursor.getColumnIndex(
256-
MediaStore.MediaColumns.DATE_MODIFIED
257-
);
249+
if (moved) {
250+
int sizeIndex = cursor.getColumnIndex(
251+
MediaStore.MediaColumns.SIZE
252+
);
258253

254+
int nameIndex = cursor.getColumnIndex(
255+
MediaStore.MediaColumns.DISPLAY_NAME
256+
);
259257

260-
boolean moved = cursor.moveToFirst();
258+
int lastModifiedIndex = cursor.getColumnIndex(
259+
MediaStore.MediaColumns.DATE_MODIFIED
260+
);
261261

262-
if (moved) {
263262
size = cursor.getLong(sizeIndex);
264263
name = cursor.getString(nameIndex);
265264
mime = context.getContentResolver().getType(uri);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy