summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLouis Chemineau <louis@chmn.me>2024-03-20 14:21:18 +0100
committerLouis Chemineau <louis@chmn.me>2024-03-20 14:25:39 +0100
commit8de134984cd13336f60f1bec3f9771d00a435962 (patch)
tree1e5a905f43c82fed00ffe184c82479260549f9bd
parentc297a2d3deb428dfb5b600228d8e327fb29314d7 (diff)
Add dashboard widget: On this day
Signed-off-by: Marcel Klehr <mklehr@gmx.net> Signed-off-by: Louis Chemineau <louis@chmn.me>
-rw-r--r--lib/AppInfo/Application.php2
-rw-r--r--lib/Dashboard/OnThisDay.php63
-rw-r--r--src/components/Dashboard/DashboardOnThisDay.vue88
-rw-r--r--src/components/File.vue6
-rw-r--r--src/dashboard.js53
-rw-r--r--src/services/PhotoSearch.js1
-rw-r--r--webpack.js1
7 files changed, 210 insertions, 4 deletions
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 80c9935b..ecf30fcf 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -28,6 +28,7 @@ namespace OCA\Photos\AppInfo;
use OCA\DAV\Connector\Sabre\Principal;
use OCA\DAV\Events\SabrePluginAuthInitEvent;
use OCA\Files\Event\LoadSidebar;
+use OCA\Photos\Dashboard\OnThisDay;
use OCA\Photos\Listener\AlbumsManagementEventListener;
use OCA\Photos\Listener\CSPListener;
use OCA\Photos\Listener\ExifMetadataProvider;
@@ -80,6 +81,7 @@ class Application extends App implements IBootstrap {
}
public function register(IRegistrationContext $context): void {
+ $context->registerDashboardWidget(OnThisDay::class);
/** Register $principalBackend for the DAV collection */
$context->registerServiceAlias('principalBackend', Principal::class);
diff --git a/lib/Dashboard/OnThisDay.php b/lib/Dashboard/OnThisDay.php
new file mode 100644
index 00000000..187648b3
--- /dev/null
+++ b/lib/Dashboard/OnThisDay.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace OCA\Photos\Dashboard;
+
+use OCA\Photos\AppInfo\Application;
+use OCP\AppFramework\Services\IInitialState;
+use OCP\Dashboard\IWidget;
+use OCP\IL10N;
+use OCP\IURLGenerator;
+use OCP\Util;
+
+class OnThisDay implements IWidget {
+ public function __construct(
+ private IL10N $l,
+ private IURLGenerator $url,
+ private IInitialState $initialState
+ ) {
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getId(): string {
+ return 'photos.onthisday';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getTitle(): string {
+ return $this->l->t('On This Day');
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getOrder(): int {
+ return 20;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getIconClass(): string {
+ return 'icon-calendar-dark';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getUrl(): ?string {
+ return $this->url->linkToRoute('photos.page.indexthisday');
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function load(): void {
+ Util::addScript('photos', 'photos-dashboard');
+ $this->initialState->provideInitialState('image-mimes', Application::IMAGE_MIMES);
+ $this->initialState->provideInitialState('video-mimes', Application::VIDEO_MIMES);
+ }
+}
diff --git a/src/components/Dashboard/DashboardOnThisDay.vue b/src/components/Dashboard/DashboardOnThisDay.vue
new file mode 100644
index 00000000..7b69badf
--- /dev/null
+++ b/src/components/Dashboard/DashboardOnThisDay.vue
@@ -0,0 +1,88 @@
+<!--
+ - Copyright (c) 2020. The Nextcloud Bookmarks contributors.
+ -
+ - This file is licensed under the Affero General Public License version 3 or later. See the COPYING file.
+ -->
+
+<template>
+ <div class="on-this-day-dashboard">
+ <NcLoadingIcon v-if="loading" :size="48" />
+ <NcEmptyContent v-else-if="items.length === 0"
+ :name="t('photos', 'No picture for this day')"
+ :description="t('photos', 'Picture taken on this day will show up here.')">
+ <template #icon>
+ <ImageIcon />
+ </template>
+ </NcEmptyContent>
+ <template v-else>
+ <File class="on-this-day-dashboard__file"
+ :file="items[0]"
+ :allow-selection="false" />
+ <NcButton :href="moreUrl">
+ {{ t('photos', 'More photos from this day') }}
+ </NcButton>
+ </template>
+ </div>
+</template>
+
+<script>
+import Image from 'vue-material-design-icons/Image.vue'
+
+import { generateUrl } from '@nextcloud/router'
+import { NcButton, NcLoadingIcon, NcEmptyContent } from '@nextcloud/vue'
+
+import getPhotos from '../../services/PhotoSearch.js'
+import { allMimes } from '../../services/AllowedMimes.js'
+import File from '../File.vue'
+import logger from '../../services/logger.js'
+
+export default {
+ name: 'DashboardOnThisDay',
+ components: {
+ File,
+ NcButton,
+ NcLoadingIcon,
+ NcEmptyContent,
+ ImageIcon: Image,
+ },
+ data() {
+ return {
+ loading: true,
+ items: [],
+ }
+ },
+ computed: {
+ moreUrl() {
+ return generateUrl('/apps/photos/thisday')
+ },
+ },
+ async created() {
+ try {
+ this.items = await getPhotos({
+ firstResult: 0,
+ nbResults: 1,
+ mimesType: allMimes,
+ onThisDay: true,
+ })
+ } catch (error) {
+ logger.error('Failed to load on this day pictures', { error })
+ } finally {
+ this.loading = false
+ }
+ },
+}
+</script>
+<style lang="scss" scoped>
+.on-this-day-dashboard {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ height: 100%;
+ gap: 16px;
+
+ .file-container {
+ flex-grow: 1;
+ border: none;
+ }
+}
+</style>
diff --git a/src/components/File.vue b/src/components/File.vue
index 8758c5cc..b5f186ba 100644
--- a/src/components/File.vue
+++ b/src/components/File.vue
@@ -107,7 +107,7 @@ export default {
},
selected: {
type: Boolean,
- required: true,
+ default: false,
},
allowSelection: {
type: Boolean,
@@ -115,7 +115,7 @@ export default {
},
distance: {
type: Number,
- required: true,
+ default: 0,
},
},
@@ -221,7 +221,7 @@ export default {
},
getItemURL(size) {
- const token = this.$route.params.token
+ const token = this.$route?.params.token
if (token) {
return generateUrl(`/apps/photos/api/v1/publicPreview/${this.file.fileid}?etag=${this.decodedEtag}&x=${size}&y=${size}&token=${token}`)
} else {
diff --git a/src/dashboard.js b/src/dashboard.js
new file mode 100644
index 00000000..40c8dee4
--- /dev/null
+++ b/src/dashboard.js
@@ -0,0 +1,53 @@
+/**
+ * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+import { generateFilePath } from '@nextcloud/router'
+import { getRequestToken } from '@nextcloud/auth'
+import { translate, translatePlural } from '@nextcloud/l10n'
+import Vue from 'vue'
+
+import store from './store/index.js'
+import DashboardOnThisDay from './components/Dashboard/DashboardOnThisDay.vue'
+
+// CSP config for webpack dynamic chunk loading
+// eslint-disable-next-line
+__webpack_nonce__ = btoa(getRequestToken())
+
+// Correct the root of the app for chunk loading
+// OC.linkTo matches the apps folders
+// OC.generateUrl ensure the index.php (or not)
+// We do not want the index.php since we're loading files
+// eslint-disable-next-line
+__webpack_public_path__ = generateFilePath('photos', '', 'js/')
+
+Vue.prototype.t = translate
+Vue.prototype.n = translatePlural
+
+window.addEventListener('DOMContentLoaded', () => {
+ OCA.Dashboard.register('photos.onthisday', (el) => {
+ global.PhotosOnThisDay = new Vue({
+ el,
+ store,
+ render: h => h(DashboardOnThisDay),
+ })
+ })
+})
diff --git a/src/services/PhotoSearch.js b/src/services/PhotoSearch.js
index 61d46f93..435297da 100644
--- a/src/services/PhotoSearch.js
+++ b/src/services/PhotoSearch.js
@@ -31,7 +31,6 @@ import store from '../store/index.js'
/**
* List files from a folder and filter out unwanted mimes
*
- * @param {object} path the lookup path
* @param {object} [options] used for the cancellable requests
* @param {number} [options.firstResult=0] Index of the first result that we want (starts at 0)
* @param {number} [options.nbResults=200] The number of file to fetch
diff --git a/webpack.js b/webpack.js
index 0c28d66d..7c550260 100644
--- a/webpack.js
+++ b/webpack.js
@@ -13,6 +13,7 @@ webpackConfig.entry = {
main: path.join(__dirname, 'src', 'main.js'),
public: path.join(__dirname, 'src', 'public.js'),
sidebar: path.join(__dirname, 'src', 'sidebar.js'),
+ dashboard: path.join(__dirname, 'src', 'dashboard.js'),
}
webpackRules.RULE_JS.exclude = BabelLoaderExcludeNodeModulesExcept([