mirror of
https://github.com/igorski/bitmappery.git
synced 2026-06-16 19:25:38 +02:00
Save dialog now auto selects last used storage provider
This commit is contained in:
@@ -211,6 +211,7 @@ export default {
|
||||
...mapMutations([
|
||||
"openDialog",
|
||||
"closeModal",
|
||||
"setStorageType",
|
||||
"showNotification",
|
||||
"setLoading",
|
||||
"unsetLoading",
|
||||
@@ -275,6 +276,7 @@ export default {
|
||||
const blob = await this._downloadFile( node );
|
||||
blob.name = node.name;
|
||||
this.loadDocument( blob );
|
||||
this.setStorageType( this.STORAGE_PROVIDER );
|
||||
this.closeModal();
|
||||
break;
|
||||
case "file":
|
||||
@@ -286,6 +288,7 @@ export default {
|
||||
await this.loadThirdPartyDocuments([ blob ]);
|
||||
} else {
|
||||
const { image, size } = await loader.loadImage( url );
|
||||
this.setStorageType( this.STORAGE_PROVIDER );
|
||||
await this.addLoadedFile({ type: this.STORAGE_PROVIDER, name: node.name }, { image, size });
|
||||
}
|
||||
disposeResource( url ); // Blob has been converted to internal resource
|
||||
@@ -490,7 +493,8 @@ $actionsHeight: 74px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.entry__icon {
|
||||
.entry__icon--folder,
|
||||
.entry__icon--document {
|
||||
background-color: $color-1;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
@@ -22,8 +22,9 @@
|
||||
*/
|
||||
<script>
|
||||
import CloudFileSelector from "../cloud-file-selector";
|
||||
import DropboxImagePreview from "./dropbox-image-preview";
|
||||
import { mapMutations } from "vuex";
|
||||
import { STORAGE_TYPES } from "@/definitions/storage-types";
|
||||
import DropboxImagePreview from "./dropbox-image-preview";
|
||||
import { listFolder, createFolder, downloadFileAsBlob, deleteEntry } from "@/services/dropbox-service";
|
||||
import { PROJECT_FILE_EXTENSION } from "@/definitions/file-types";
|
||||
|
||||
@@ -34,7 +35,7 @@ export default {
|
||||
},
|
||||
data: () => ({
|
||||
LAST_FOLDER_STORAGE_KEY: "bpy_dropboxDb",
|
||||
STORAGE_PROVIDER : "dropbox",
|
||||
STORAGE_PROVIDER : STORAGE_TYPES.DROPBOX,
|
||||
}),
|
||||
computed: {
|
||||
imagePreviewComponent() {
|
||||
|
||||
@@ -90,10 +90,6 @@ export default {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
&__loader {
|
||||
width: $spacing-xxlarge;
|
||||
height: $spacing-xxlarge;
|
||||
@@ -104,6 +100,11 @@ export default {
|
||||
object-fit: cover;
|
||||
width: calc(100% - #{$spacing-small});
|
||||
height: calc(100% - #{$spacing-small});
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
transform-origin: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -22,9 +22,10 @@
|
||||
*/
|
||||
<script>
|
||||
import CloudFileSelector from "../cloud-file-selector";
|
||||
import GoogleDriveImagePreview from "./google-drive-image-preview";
|
||||
import { PROJECT_FILE_EXTENSION } from "@/definitions/file-types";
|
||||
import { mapMutations } from "vuex";
|
||||
import { PROJECT_FILE_EXTENSION } from "@/definitions/file-types";
|
||||
import { STORAGE_TYPES } from "@/definitions/storage-types";
|
||||
import GoogleDriveImagePreview from "./google-drive-image-preview";
|
||||
import {
|
||||
ROOT_FOLDER, listFolder, createFolder, downloadFileAsBlob, deleteEntry
|
||||
} from "@/services/google-drive-service";
|
||||
@@ -33,7 +34,7 @@
|
||||
extends: CloudFileSelector,
|
||||
data: () => ({
|
||||
LAST_FOLDER_STORAGE_KEY: "bpy_driveDb",
|
||||
STORAGE_PROVIDER: "drive",
|
||||
STORAGE_PROVIDER: STORAGE_TYPES.DRIVE,
|
||||
}),
|
||||
computed: {
|
||||
imagePreviewComponent() {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"importedFileSuccessfully": "Imported \"{file}\" successfully.",
|
||||
"errorImportingFile": "An error occurred while trying to import \"{file}\"",
|
||||
"delete": "Delete",
|
||||
"deleteEntryWarning": "Are you sure you wish to delete \"{entry}\" ? You can recover files and folders deleted from your cloud storage, but only through the cloud providers app or site.",
|
||||
"deleteEntryWarning": "Are you sure you wish to delete \"{entry}\" ? You can recover files and folders deleted from your cloud storage through the cloud providers app or site.",
|
||||
"entryDeletedSuccessfully": "\"{entry}\" deleted successfully",
|
||||
"couldNotDeleteEntry": "An error occurred while attempting to delete \"{entry}\"",
|
||||
"newFolderName": "New folder name",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"connectingToDropbox": "Connecting to Dropbox",
|
||||
"connectedToDropbox": "Connected to Dropbox",
|
||||
"establishConnection": "Establish connection",
|
||||
"connectionExpl": "In order to import files from Dropbox you must first connect BitMappery to Dropbox. Dropbox connects directly to your machine without middleware, keeping your data private.",
|
||||
"connectionExpl": "In order to import files from or save projects to Dropbox you must first connect BitMappery to Dropbox and grant read and write permissions. Dropbox connects directly to your machine without middleware, keeping your data private.",
|
||||
"loginToDropbox": "Log into Dropbox",
|
||||
"login": "Login",
|
||||
"importFromDropbox": "Import from Dropbox"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"connectingToDrive": "Connecting to Google Drive",
|
||||
"connectedToDrive": "Connected to Google Drive",
|
||||
"establishConnection": "Establish connection",
|
||||
"connectionExpl": "In order to import files from Google Drive you must first connect BitMappery to Google Drive. Google Drive connects directly to your machine without middleware, keeping your data private.",
|
||||
"connectionExpl": "In order to import files from or save projects to Google Drive you must first connect BitMappery to Google Drive and grant read and write permissions. Google Drive connects directly to your machine without middleware, keeping your data private.",
|
||||
"loginToDrive": "Log into Google Drive",
|
||||
"login": "Login",
|
||||
"importFromDrive": "Import from Google Drive",
|
||||
|
||||
@@ -75,10 +75,9 @@
|
||||
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
|
||||
import Modal from "@/components/modal/modal";
|
||||
import SelectBox from "@/components/ui/select-box/select-box";
|
||||
import { STORAGE_TYPES } from "@/definitions/storage-types";
|
||||
import { focus } from "@/utils/environment-util";
|
||||
|
||||
const STORAGE_TYPES = [ "local", "dropbox", "drive" ];
|
||||
|
||||
import messages from "./messages.json";
|
||||
export default {
|
||||
i18n: { messages },
|
||||
@@ -87,13 +86,14 @@ export default {
|
||||
SelectBox,
|
||||
},
|
||||
data: () => ({
|
||||
name : "",
|
||||
storageLocation : STORAGE_TYPES[ 0 ] // TODO: set to whatever original document source is ?
|
||||
name : "",
|
||||
storageLocation : STORAGE_TYPES.LOCAL
|
||||
}),
|
||||
computed: {
|
||||
...mapState([
|
||||
"dropboxConnected",
|
||||
"driveConnected",
|
||||
"storageType",
|
||||
]),
|
||||
...mapGetters([
|
||||
"activeDocument",
|
||||
@@ -103,28 +103,31 @@ export default {
|
||||
return this.name.length > 0;
|
||||
},
|
||||
storageLocations() {
|
||||
const out = [{ label: this.$t( "local" ), value: STORAGE_TYPES[ 0 ] }];
|
||||
const out = [{ label: this.$t( "local" ), value: STORAGE_TYPES.LOCAL }];
|
||||
if ( this.dropboxConnected ) {
|
||||
out.push({ label: this.$t( "dropbox" ), value: STORAGE_TYPES[ 1 ] });
|
||||
out.push({ label: this.$t( "dropbox" ), value: STORAGE_TYPES.DROPBOX });
|
||||
}
|
||||
if ( this.driveConnected ) {
|
||||
out.push({ label: this.$t( "drive" ), value: STORAGE_TYPES[ 2 ] });
|
||||
out.push({ label: this.$t( "drive" ), value: STORAGE_TYPES.DRIVE });
|
||||
}
|
||||
return out;
|
||||
},
|
||||
dropboxSaveComponent() {
|
||||
if ( this.storageLocation === "dropbox" ) {
|
||||
if ( this.storageLocation === STORAGE_TYPES.DROPBOX ) {
|
||||
return () => import( "./dropbox/save-dropbox-document" );
|
||||
}
|
||||
return null;
|
||||
},
|
||||
driveSaveComponent() {
|
||||
if ( this.storageLocation === "drive" ) {
|
||||
if ( this.storageLocation === STORAGE_TYPES.DRIVE ) {
|
||||
return () => import( "./google-drive/save-google-drive-document" );
|
||||
}
|
||||
return null;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.storageLocation = this.storageType;
|
||||
},
|
||||
mounted() {
|
||||
this.name = this.activeDocument.name.split( "." )[ 0 ];
|
||||
focus( this.$refs.nameInput );
|
||||
@@ -155,11 +158,11 @@ export default {
|
||||
// by using refs we have tightly coupled these components
|
||||
// this however ensures we can separate the necessary SDK code
|
||||
// from the core bundle and minimize file size
|
||||
case "dropbox":
|
||||
case STORAGE_TYPES.DROPBOX:
|
||||
this.$refs.dropboxComponent.requestSave();
|
||||
break;
|
||||
|
||||
case "drive":
|
||||
case STORAGE_TYPES.DRIVE:
|
||||
this.$refs.driveComponent.requestSave();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
import { STORAGE_TYPES } from "@/definitions/storage-types";
|
||||
import { isSafari } from "@/utils/environment-util";
|
||||
|
||||
// 1. all image formats supported by BitMappery
|
||||
@@ -57,7 +58,7 @@ if ( !isSafari() ) {
|
||||
export const isCompressableFileType = type => COMPRESSABLE_TYPES.some(({ mime }) => mime === type );
|
||||
|
||||
export const isTransparent = ({ name, type }) => {
|
||||
if ( type === "dropbox" ) {
|
||||
if ( type === STORAGE_TYPES.DROPBOX ) {
|
||||
// files imported from Dropbox don't list their mime type, derive from filename instead
|
||||
return TRANSPARENT_TYPES.some(({ ext }) => name.includes( ext ));
|
||||
}
|
||||
|
||||
27
src/definitions/storage-types.js
Normal file
27
src/definitions/storage-types.js
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Igor Zinken 2022 - https://www.igorski.nl
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
export const STORAGE_TYPES = {
|
||||
LOCAL : "local",
|
||||
DROPBOX : "dropbox",
|
||||
DRIVE : "drive"
|
||||
};
|
||||
@@ -98,11 +98,7 @@ export const requestLogout = () => {
|
||||
gapi.auth2.getAuthInstance().signOut();
|
||||
};
|
||||
|
||||
export const validateScopes = grantedScopes => {
|
||||
const hasRequiredScopes = ACCESS_SCOPES.split( "," ).every( scope => grantedScopes.includes( scope ));
|
||||
console.warn("heb ik die scopes ?"+hasRequiredScopes, grantedScopes);
|
||||
return hasRequiredScopes;
|
||||
};
|
||||
export const validateScopes = grantedScopes => ACCESS_SCOPES.split( "," ).every( scope => grantedScopes.includes( scope ));
|
||||
|
||||
export const disconnect = () => gapi.auth2.getAuthInstance().disconnect();
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import { getCanvasInstance, getSpriteForLayer } from "@/factories/sprite-factory
|
||||
import { PROJECT_FILE_EXTENSION } from "@/definitions/file-types";
|
||||
import { LAYER_GRAPHIC } from "@/definitions/layer-types";
|
||||
import { PANEL_TOOL_OPTIONS, PANEL_LAYERS } from "@/definitions/panel-types";
|
||||
import { STORAGE_TYPES } from "@/definitions/storage-types";
|
||||
import { runSpriteFn } from "@/factories/sprite-factory";
|
||||
import canvasModule from "./modules/canvas-module";
|
||||
import documentModule from "./modules/document-module";
|
||||
@@ -69,6 +70,7 @@ export default {
|
||||
modal: null, // currently opened modal
|
||||
loadingStates: [], // wether one or more long running operations are running
|
||||
notifications: [], // notification message queue
|
||||
storageType: STORAGE_TYPES.LOCAL,
|
||||
dropboxConnected: false,
|
||||
driveConnected: false,
|
||||
windowSize: {
|
||||
@@ -163,6 +165,9 @@ export default {
|
||||
setWindowSize( state, { width, height }) {
|
||||
state.windowSize = { width, height };
|
||||
},
|
||||
setStorageType( state, value ) {
|
||||
state.storageType = value;
|
||||
},
|
||||
setDropboxConnected( state, value ) {
|
||||
state.dropboxConnected = value;
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { JPEG, PNG, GIF, WEBP, isCompressableFileType, isTransparent } from "@/definitions/image-types";
|
||||
import { STORAGE_TYPES } from "@/definitions/storage-types";
|
||||
|
||||
describe( "image types", () => {
|
||||
it( "should recognize the compressable file types", () => {
|
||||
@@ -16,7 +17,7 @@ describe( "image types", () => {
|
||||
});
|
||||
|
||||
it( "should recognize the file types supporting transparency by their extension, for Dropbox import", () => {
|
||||
const type = "dropbox"; // Dropbox imports have no MIME type associated with the file
|
||||
const type = STORAGE_TYPES.DROPBOX; // Dropbox imports have no MIME type associated with the file
|
||||
|
||||
expect( isTransparent({ name: `file_${PNG.ext}`, type })).toBe( true );
|
||||
expect( isTransparent({ name: `file_${GIF.ext}`, type })).toBe( true );
|
||||
|
||||
@@ -217,6 +217,12 @@ describe( "Vuex store", () => {
|
||||
expect( state.windowSize ).toEqual({ width, height });
|
||||
});
|
||||
|
||||
it( "should be able to set the storage type", () => {
|
||||
const state = { storageType: "foo" };
|
||||
mutations.setStorageType( state, "bar" );
|
||||
expect( state.storageType ).toEqual( "bar" );
|
||||
});
|
||||
|
||||
it( "should be able to set the Dropbox connection status", () => {
|
||||
const state = { dropboxConnected: false };
|
||||
mutations.setDropboxConnected( state, true );
|
||||
|
||||
Reference in New Issue
Block a user