From 12eb302bcc93405f81b676b1a29a9731a5fec9be Mon Sep 17 00:00:00 2001
From: pacien
Date: Sun, 30 Oct 2022 17:40:33 +0100
Subject: viewer/command: add item download button

This adds a download button which allows the user to save the current
item as a file.

This is necessary because some item viewers do not expose a download
option on their own.

The download icon appears together with the other command buttons at the
top-left corner of the screen, replacing the listing sorting menu which
is only relevant for item lists (directory and search views).

GitHub: closes #308
---
 viewer/src/views/layout/top/LayoutCommand.vue | 46 ++++++++++++++++++++++++---
 1 file changed, 42 insertions(+), 4 deletions(-)

(limited to 'viewer/src/views/layout/top/LayoutCommand.vue')

diff --git a/viewer/src/views/layout/top/LayoutCommand.vue b/viewer/src/views/layout/top/LayoutCommand.vue
index 8919da3..d930fd2 100644
--- a/viewer/src/views/layout/top/LayoutCommand.vue
+++ b/viewer/src/views/layout/top/LayoutCommand.vue
@@ -2,7 +2,7 @@
 --             pictures into a searchable web gallery.
 --
 -- Copyright (C) 2019-2022  Guillaume FOUET
---               2020       Pacien TRAN-GIRARD
+--               2020-2022  Pacien TRAN-GIRARD
 --
 -- This program is free software: you can redistribute it and/or modify
 -- it under the terms of the GNU Affero General Public License as
@@ -33,7 +33,24 @@
         size="lg"
       />
     </LdLink>
-    <LayoutCommandSort :tabindex="20" />
+
+    <LayoutCommandSort
+      v-if="isListing"
+      :tabindex="20"
+    />
+    <a
+      v-else
+      :title="t('command.download')"
+      :download="itemFileName"
+      :href="itemResourceUrl"
+      :tabindex="20"
+    >
+      <fa-icon
+        :icon="faFileDownload"
+        size="lg"
+      />
+    </a>
+
     <LdLink
       :class="{ disabled: isEntryPoint(), [$style.commandSecondary]: true }"
       :title="t('command.back')"
@@ -67,21 +84,42 @@
 import { Item } from '@/@types/gallery';
 import LdLink from '@/components/LdLink.vue';
 import { useUiStore } from '@/store/uiStore';
-import { faAngleDoubleLeft, faArrowLeft, faFolder, faLevelUpAlt, faSearch } from '@fortawesome/free-solid-svg-icons';
+import { useGalleryStore } from '@/store/galleryStore';
+import { useNavigation } from '@/services/navigation';
+import { isDirectory, isDownloadableItem } from '@/services/itemGuards';
+import {
+  faAngleDoubleLeft,
+  faArrowLeft,
+  faFolder,
+  faLevelUpAlt,
+  faSearch,
+  faFileDownload,
+} from '@fortawesome/free-solid-svg-icons';
 import { computedEager } from '@vueuse/shared';
-import { computed } from 'vue';
+import { computed, PropType } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRoute, useRouter } from 'vue-router';
 import LayoutCommandSort from './LayoutCommandSort.vue';
 
 const props = defineProps({
   currentItemPath: { type: Array<Item>, required: true },
+  item: { type: Object as PropType<Item>, required: true },
 });
 
 const { t } = useI18n();
 const route = useRoute();
 const router = useRouter();
 const uiStore = useUiStore();
+const galleryStore = useGalleryStore();
+const navigation = useNavigation();
+
+const isListing = computedEager(() => !props.item || isDirectory(props.item));
+const itemFileName = computed(() => navigation.getFileName(props.item));
+const itemResourceUrl = computed(() =>
+  isDownloadableItem(props.item)
+    ? galleryStore.resourceRoot + props.item.properties.resource
+    : '',
+);
 
 const commandToggleSearchPanelIcon = computed(() => uiStore.fullWidth ? faSearch : faAngleDoubleLeft);
 const isRoot = computedEager(() => props.currentItemPath.length <= 1 && !uiStore.searchMode);
-- 
cgit v1.2.3


From cfbff75f78963e3d24326f731590e78a4d719e9e Mon Sep 17 00:00:00 2001
From: Zéro~Informatique
Date: Sun, 6 Nov 2022 19:34:26 +0100
Subject: viewer/command: add item download button

Fixed a reactivity issue with props used in a composition function (useItemResource)
Fixed crash with null items in LayoutTop
Changed how downloadable items are identified: We use the fact they are materialized in the gallery instead of a hardly defined "listing condition". This also simplifies the code.
---
 viewer/src/views/layout/top/LayoutCommand.vue | 35 ++++++++++-----------------
 1 file changed, 13 insertions(+), 22 deletions(-)

(limited to 'viewer/src/views/layout/top/LayoutCommand.vue')

diff --git a/viewer/src/views/layout/top/LayoutCommand.vue b/viewer/src/views/layout/top/LayoutCommand.vue
index d930fd2..85d47b6 100644
--- a/viewer/src/views/layout/top/LayoutCommand.vue
+++ b/viewer/src/views/layout/top/LayoutCommand.vue
@@ -34,14 +34,10 @@
       />
     </LdLink>
 
-    <LayoutCommandSort
-      v-if="isListing"
-      :tabindex="20"
-    />
-    <a
-      v-else
+    <LdLink
+      v-if="itemResourceUrl"
       :title="t('command.download')"
-      :download="itemFileName"
+      :download="navigation.getFileName(props.item)"
       :href="itemResourceUrl"
       :tabindex="20"
     >
@@ -49,7 +45,11 @@
         :icon="faFileDownload"
         size="lg"
       />
-    </a>
+    </LdLink>
+    <LayoutCommandSort
+      v-else
+      :tabindex="20"
+    />
 
     <LdLink
       :class="{ disabled: isEntryPoint(), [$style.commandSecondary]: true }"
@@ -83,20 +83,19 @@
 <script setup lang="ts">
 import { Item } from '@/@types/gallery';
 import LdLink from '@/components/LdLink.vue';
-import { useUiStore } from '@/store/uiStore';
-import { useGalleryStore } from '@/store/galleryStore';
 import { useNavigation } from '@/services/navigation';
-import { isDirectory, isDownloadableItem } from '@/services/itemGuards';
+import { useItemResource } from '@/services/ui/ldItemResourceUrl';
+import { useUiStore } from '@/store/uiStore';
 import {
   faAngleDoubleLeft,
   faArrowLeft,
+  faFileDownload,
   faFolder,
   faLevelUpAlt,
   faSearch,
-  faFileDownload,
 } from '@fortawesome/free-solid-svg-icons';
 import { computedEager } from '@vueuse/shared';
-import { computed, PropType } from 'vue';
+import { computed, PropType, toRef } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRoute, useRouter } from 'vue-router';
 import LayoutCommandSort from './LayoutCommandSort.vue';
@@ -110,16 +109,8 @@ const { t } = useI18n();
 const route = useRoute();
 const router = useRouter();
 const uiStore = useUiStore();
-const galleryStore = useGalleryStore();
 const navigation = useNavigation();
-
-const isListing = computedEager(() => !props.item || isDirectory(props.item));
-const itemFileName = computed(() => navigation.getFileName(props.item));
-const itemResourceUrl = computed(() =>
-  isDownloadableItem(props.item)
-    ? galleryStore.resourceRoot + props.item.properties.resource
-    : '',
-);
+const { itemResourceUrl } = useItemResource(toRef(props, 'item'));
 
 const commandToggleSearchPanelIcon = computed(() => uiStore.fullWidth ? faSearch : faAngleDoubleLeft);
 const isRoot = computedEager(() => props.currentItemPath.length <= 1 && !uiStore.searchMode);
-- 
cgit v1.2.3

