diff options
author | Louis Chemineau <louis@chmn.me> | 2024-03-20 14:21:18 +0100 |
---|---|---|
committer | Louis Chemineau <louis@chmn.me> | 2024-03-20 14:25:39 +0100 |
commit | 8de134984cd13336f60f1bec3f9771d00a435962 (patch) | |
tree | 1e5a905f43c82fed00ffe184c82479260549f9bd | |
parent | c297a2d3deb428dfb5b600228d8e327fb29314d7 (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.php | 2 | ||||
-rw-r--r-- | lib/Dashboard/OnThisDay.php | 63 | ||||
-rw-r--r-- | src/components/Dashboard/DashboardOnThisDay.vue | 88 | ||||
-rw-r--r-- | src/components/File.vue | 6 | ||||
-rw-r--r-- | src/dashboard.js | 53 | ||||
-rw-r--r-- | src/services/PhotoSearch.js | 1 | ||||
-rw-r--r-- | webpack.js | 1 |
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 @@ -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([ |