+ You should return to PhotoMound shortly. If not, an authentication
+ error has occurred with the external API.
+
+
+
+
diff --git a/src/components/dialog-window/dialog-window.vue b/src/components/dialog-window/dialog-window.vue
index 3d193d4..2c1c300 100644
--- a/src/components/dialog-window/dialog-window.vue
+++ b/src/components/dialog-window/dialog-window.vue
@@ -72,11 +72,11 @@ export default {
'closeDialog',
]),
handleConfirm() {
- this?.confirmHandler();
+ this.confirmHandler?.();
this.close();
},
handleCancel() {
- this?.cancelHandler();
+ this.cancelHandler?.();
this.close();
},
close() {
diff --git a/src/components/dropbox-file-browser/dropbox-file-browser.vue b/src/components/dropbox-file-browser/dropbox-file-browser.vue
new file mode 100644
index 0000000..03d7466
--- /dev/null
+++ b/src/components/dropbox-file-browser/dropbox-file-browser.vue
@@ -0,0 +1,165 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Igor Zinken 2020 - 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.
+ */
+
+
+
+
+
+
+ {{ leaf.name }}
+
+
+
+
+
+
+
+
+
diff --git a/src/components/dropbox-file-browser/messages.json b/src/components/dropbox-file-browser/messages.json
new file mode 100644
index 0000000..7af9504
--- /dev/null
+++ b/src/components/dropbox-file-browser/messages.json
@@ -0,0 +1,7 @@
+{
+ "en-US": {
+ "files": "Files",
+ "loading": "Loading...",
+ "couldNotRetrieveFilesForPath": "Could not retrieve files for \"{path}\""
+ }
+}
diff --git a/src/components/options-panel/components/dropbox-file-selector/dropbox-file-selector.vue b/src/components/options-panel/components/dropbox-file-selector/dropbox-file-selector.vue
new file mode 100644
index 0000000..f173032
--- /dev/null
+++ b/src/components/options-panel/components/dropbox-file-selector/dropbox-file-selector.vue
@@ -0,0 +1,98 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Igor Zinken 2020 - 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.
+ */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/options-panel/components/dropbox-file-selector/messages.json b/src/components/options-panel/components/dropbox-file-selector/messages.json
new file mode 100644
index 0000000..1f03633
--- /dev/null
+++ b/src/components/options-panel/components/dropbox-file-selector/messages.json
@@ -0,0 +1,9 @@
+{
+ "en-US": {
+ "connectingToDropbox": "Connecting to Dropbox",
+ "loginToDropbox": "Log into Dropbox",
+ "connectedToDropbox": "Connected to Dropbox",
+ "login": "Login",
+ "selectFiles": "Select files"
+ }
+}
diff --git a/src/components/options-panel/components/file-selector/file-selector.vue b/src/components/options-panel/components/file-selector/file-selector.vue
index 17a9e46..2b72979 100644
--- a/src/components/options-panel/components/file-selector/file-selector.vue
+++ b/src/components/options-panel/components/file-selector/file-selector.vue
@@ -42,9 +42,9 @@
diff --git a/src/components/options-panel/options-panel.vue b/src/components/options-panel/options-panel.vue
index a5bae7e..b24b0b2 100644
--- a/src/components/options-panel/options-panel.vue
+++ b/src/components/options-panel/options-panel.vue
@@ -33,6 +33,11 @@
class="content"
>
+
+
@@ -48,6 +53,9 @@ export default {
components: {
FileSelector,
},
+ data: () => ({
+ dropbox: false,
+ }),
computed: {
...mapState([
"optionsPanelOpened",
@@ -63,6 +71,14 @@ export default {
this.setOptionsPanelOpened( !value );
}
},
+ importType() {
+ switch ( this.dropbox ) {
+ default:
+ return null;
+ case true:
+ return () => import( "./components/dropbox-file-selector/dropbox-file-selector" );
+ }
+ },
activeToolOptions() {
switch ( this.activeTool ) {
default:
diff --git a/src/definitions/modal-windows.js b/src/definitions/modal-windows.js
index 03de793..9394990 100644
--- a/src/definitions/modal-windows.js
+++ b/src/definitions/modal-windows.js
@@ -20,4 +20,5 @@
* 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 RESIZE_DOCUMENT = 1;
+export const RESIZE_DOCUMENT = 1;
+export const DROPBOX_FILE_BROWSER = 2;
diff --git a/src/mixins/image-to-document-manager.js b/src/mixins/image-to-document-manager.js
new file mode 100644
index 0000000..3d4fe91
--- /dev/null
+++ b/src/mixins/image-to-document-manager.js
@@ -0,0 +1,70 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Igor Zinken 2020 - 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.
+ */
+import{ mapGetters, mapMutations, mapActions } from "vuex";
+
+export default {
+ computed: {
+ ...mapGetters([
+ "activeDocument",
+ "layers",
+ ])
+ },
+ methods: {
+ ...mapMutations([
+ "setActiveDocumentSize",
+ "addNewDocument",
+ "addLayer",
+ "addGraphicToLayer",
+ ]),
+ ...mapActions([
+ "addImage",
+ ]),
+ async addLoadedFile( file, { image, size }) {
+ const { source } = await this.addImage({ file, image, size });
+
+ image.src = source;
+
+ const currentDocumentIsEmpty = this.layers?.length === 1 && !this.layers[ 0 ].graphics.length;
+
+ switch ( this.fileTarget) {
+ default:
+ case "layer":
+ // if this is the first content of an existing document, scale document to image size
+ if ( currentDocumentIsEmpty ) {
+ this.setActiveDocumentSize( size );
+ } else if ( !this.activeDocument ) {
+ this.addNewDocument( file.name );
+ }
+ this.addLayer();
+ break;
+ case "document":
+ if ( !currentDocumentIsEmpty ) {
+ this.addNewDocument( file.name );
+ }
+ this.setActiveDocumentSize( size );
+ break;
+ }
+ this.addGraphicToLayer({ index: this.layers.length - 1, bitmap: image, size });
+ },
+ }
+};
diff --git a/src/photomound.vue b/src/photomound.vue
index b34259e..0800ad9 100644
--- a/src/photomound.vue
+++ b/src/photomound.vue
@@ -68,10 +68,12 @@ import DocumentCanvas from "@/components/document-canvas/document-canvas";
import OptionsPanel from "@/components/options-panel/options-panel";
import Toolbox from "@/components/toolbox/toolbox";
import DialogWindow from "@/components/dialog-window/dialog-window";
-import { RESIZE_DOCUMENT } from "@/definitions/modal-windows";
import { isMobile } from "@/utils/environment-util";
import store from "./store";
import messages from "./messages.json";
+import {
+ RESIZE_DOCUMENT, DROPBOX_FILE_BROWSER
+} from "@/definitions/modal-windows";
Vue.use( Vuex );
Vue.use( VueI18n );
@@ -109,6 +111,8 @@ export default {
return null;
case RESIZE_DOCUMENT:
return () => import( "@/components/edit-menu/resize-document/resize-document" );
+ case DROPBOX_FILE_BROWSER:
+ return () => import( "@/components/dropbox-file-browser/dropbox-file-browser" );
}
},
},
diff --git a/src/services/dropbox-service.js b/src/services/dropbox-service.js
new file mode 100644
index 0000000..29a3fc7
--- /dev/null
+++ b/src/services/dropbox-service.js
@@ -0,0 +1,69 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Igor Zinken 2020 - 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.
+ */
+import { Dropbox } from "dropbox";
+
+let accessToken;
+let dbx;
+
+/**
+ * Authentication step 1: for interacting with Dropbox : request access token
+ * by opening an authentication page
+ */
+export const requestLogin = ( clientId, loginUrl ) => {
+ dbx = new Dropbox({ clientId });
+ return dbx.auth.getAuthenticationUrl( loginUrl );
+}
+
+/**
+ * Authentication step 2: user has received access token, register it in the
+ * service and in Session storage so we can instantly authenticate on reload
+ */
+export const registerAccessToken = token => {
+ accessToken = token;
+ sessionStorage?.setItem( "dropboxToken", token );
+ dbx = new Dropbox({ accessToken });
+};
+
+export const isAuthenticated = async () => {
+ dbx = new Dropbox({ accessToken: accessToken ?? sessionStorage?.getItem( "dropboxToken" ) });
+ try {
+ // this is a bit daft but does the trick, can we use a different method though?
+ await listFolder();
+ return true;
+ } catch ( error ) {
+ return false;
+ }
+}
+
+export const listFolder = ( path = "" ) => {
+ return dbx.filesListFolder({ path });
+}
+
+export const downloadFileAsBlob = async path => {
+ try {
+ const { result } = await dbx.filesDownload({ path });
+ return URL.createObjectURL( result.fileBlob );
+ } catch {
+ return null;
+ }
+};