feat: add files popover in note toolbar (#913)
This commit is contained in:
@@ -26,6 +26,7 @@ import {
|
||||
} from 'mobx';
|
||||
import { ActionsMenuState } from './actions_menu_state';
|
||||
import { FeaturesState } from './features_state';
|
||||
import { FilesState } from './files_state';
|
||||
import { NotesState } from './notes_state';
|
||||
import { NotesViewState } from './notes_view_state';
|
||||
import { NoteTagsState } from './note_tags_state';
|
||||
@@ -89,6 +90,7 @@ export class AppState {
|
||||
readonly tags: TagsState;
|
||||
readonly notesView: NotesViewState;
|
||||
readonly subscription: SubscriptionState;
|
||||
readonly files: FilesState;
|
||||
|
||||
isSessionsModalVisible = false;
|
||||
|
||||
@@ -139,6 +141,7 @@ export class AppState {
|
||||
this,
|
||||
this.appEventObserverRemovers
|
||||
);
|
||||
this.files = new FilesState(application);
|
||||
this.addAppEventObserver();
|
||||
this.streamNotesAndTags();
|
||||
this.onVisibilityChange = () => {
|
||||
|
||||
142
app/assets/javascripts/ui_models/app_state/files_state.ts
Normal file
142
app/assets/javascripts/ui_models/app_state/files_state.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import {
|
||||
ClassicFileReader,
|
||||
StreamingFileReader,
|
||||
StreamingFileSaver,
|
||||
ClassicFileSaver,
|
||||
} from '@standardnotes/filepicker';
|
||||
import { SNFile } from '@standardnotes/snjs';
|
||||
import { addToast, dismissToast, ToastType } from '@standardnotes/stylekit';
|
||||
|
||||
import { WebApplication } from '../application';
|
||||
|
||||
export class FilesState {
|
||||
constructor(private application: WebApplication) {}
|
||||
|
||||
public async downloadFile(file: SNFile): Promise<void> {
|
||||
let downloadingToastId = '';
|
||||
|
||||
try {
|
||||
const saver = StreamingFileSaver.available()
|
||||
? new StreamingFileSaver(file.nameWithExt)
|
||||
: new ClassicFileSaver();
|
||||
|
||||
const isUsingStreamingSaver = saver instanceof StreamingFileSaver;
|
||||
|
||||
if (isUsingStreamingSaver) {
|
||||
await saver.selectFileToSaveTo();
|
||||
}
|
||||
|
||||
downloadingToastId = addToast({
|
||||
type: ToastType.Loading,
|
||||
message: `Downloading file...`,
|
||||
});
|
||||
|
||||
await this.application.files.downloadFile(
|
||||
file,
|
||||
async (decryptedBytes: Uint8Array) => {
|
||||
if (isUsingStreamingSaver) {
|
||||
await saver.pushBytes(decryptedBytes);
|
||||
} else {
|
||||
saver.saveFile(file.nameWithExt, decryptedBytes);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (isUsingStreamingSaver) {
|
||||
await saver.finish();
|
||||
}
|
||||
|
||||
addToast({
|
||||
type: ToastType.Success,
|
||||
message: 'Successfully downloaded file',
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
addToast({
|
||||
type: ToastType.Error,
|
||||
message: 'There was an error while downloading the file',
|
||||
});
|
||||
}
|
||||
|
||||
if (downloadingToastId.length > 0) {
|
||||
dismissToast(downloadingToastId);
|
||||
}
|
||||
}
|
||||
|
||||
public async uploadNewFile(fileOrHandle?: File | FileSystemFileHandle) {
|
||||
let toastId = '';
|
||||
|
||||
try {
|
||||
const minimumChunkSize = this.application.files.minimumChunkSize();
|
||||
|
||||
const picker = StreamingFileReader.available()
|
||||
? StreamingFileReader
|
||||
: ClassicFileReader;
|
||||
|
||||
const selectedFiles =
|
||||
fileOrHandle instanceof File
|
||||
? [fileOrHandle]
|
||||
: StreamingFileReader.available() &&
|
||||
fileOrHandle instanceof FileSystemFileHandle
|
||||
? await StreamingFileReader.getFilesFromHandles([fileOrHandle])
|
||||
: await picker.selectFiles();
|
||||
|
||||
const uploadedFiles: SNFile[] = [];
|
||||
|
||||
for (const file of selectedFiles) {
|
||||
const operation = await this.application.files.beginNewFileUpload();
|
||||
|
||||
const onChunk = async (
|
||||
chunk: Uint8Array,
|
||||
index: number,
|
||||
isLast: boolean
|
||||
) => {
|
||||
await this.application.files.pushBytesForUpload(
|
||||
operation,
|
||||
chunk,
|
||||
index,
|
||||
isLast
|
||||
);
|
||||
};
|
||||
|
||||
toastId = addToast({
|
||||
type: ToastType.Loading,
|
||||
message: `Uploading file "${file.name}"...`,
|
||||
});
|
||||
|
||||
const fileResult = await picker.readFile(
|
||||
file,
|
||||
minimumChunkSize,
|
||||
onChunk
|
||||
);
|
||||
|
||||
const uploadedFile = await this.application.files.finishUpload(
|
||||
operation,
|
||||
fileResult.name,
|
||||
fileResult.ext
|
||||
);
|
||||
|
||||
uploadedFiles.push(uploadedFile);
|
||||
|
||||
dismissToast(toastId);
|
||||
addToast({
|
||||
type: ToastType.Success,
|
||||
message: `Uploaded file "${uploadedFile.nameWithExt}"`,
|
||||
});
|
||||
}
|
||||
|
||||
return uploadedFiles;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
if (toastId.length > 0) {
|
||||
dismissToast(toastId);
|
||||
}
|
||||
addToast({
|
||||
type: ToastType.Error,
|
||||
message: 'There was an error while uploading the file',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user