['name' => 'dashboard#index', 'url' => '/', 'verb' => 'GET'],
['name' => 'dashboard#updateLayout', 'url' => '/layout', 'verb' => 'POST'],
['name' => 'dashboard#getBackground', 'url' => '/background', 'verb' => 'GET'],
- ['name' => 'dashboard#setBackground', 'url' => '/background', 'verb' => 'POST'],
+ ['name' => 'dashboard#setBackground', 'url' => '/background/{type}', 'verb' => 'POST'],
]
];
$this->inititalStateService->provideInitialState('dashboard', 'firstRun', $this->config->getUserValue($this->userId, 'dashboard', 'firstRun', '1') === '1');
$this->inititalStateService->provideInitialState('dashboard', 'shippedBackgrounds', BackgroundService::SHIPPED_BACKGROUNDS);
$this->inititalStateService->provideInitialState('dashboard', 'background', $this->config->getUserValue($this->userId, 'dashboard', 'background', 'default'));
+ $this->inititalStateService->provideInitialState('dashboard', 'version', $this->config->getUserValue($this->userId, 'dashboard', 'backgroundVersion', 0));
$this->config->setUserValue($this->userId, 'dashboard', 'firstRun', '0');
return new TemplateResponse('dashboard', 'index');
/**
* @NoAdminRequired
*/
- public function setBackground($path = null, $url = null, $shipped = null): JSONResponse {
- if ($shipped !== null) {
- $this->backgroundService->setShippedBackground($shipped);
- } else if ($path !== null) {
- $this->backgroundService->setFileBackground($path);
- } else if ($url !== null) {
- $this->backgroundService->setUrlBackground($url);
- } else {
- $this->backgroundService->setDefaultBackground();
+ public function setBackground(string $type = 'default', $value): JSONResponse {
+ $currentVersion = $this->config->getUserValue($this->userId, 'dashboard', 'backgroundVersion', 0);
+ try {
+ switch ($type) {
+ case 'shipped':
+ $this->backgroundService->setShippedBackground($value);
+ break;
+ case 'custom':
+ $this->backgroundService->setFileBackground($value);
+ break;
+ case 'color':
+ $this->backgroundService->setColorBackground($value);
+ break;
+ case 'default':
+ $this->backgroundService->setDefaultBackground();
+ break;
+ default:
+ return new JSONResponse(['error' => 'Invalid type provided'], Http::STATUS_BAD_REQUEST);
+ }
+ } catch (\InvalidArgumentException $e) {
+ return new JSONResponse(['error' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
}
-
- return new JSONResponse([]);
+ $currentVersion++;
+ $this->config->setUserValue($this->userId, 'dashboard', 'backgroundVersion', $currentVersion);
+ return new JSONResponse([
+ 'type' => $type,
+ 'value' => $value,
+ 'version' => $this->config->getUserValue($this->userId, 'dashboard', 'backgroundVersion', $currentVersion)
+ ]);
}
/**
}
public function setShippedBackground($fileName) {
+ if (!in_array($fileName, self::SHIPPED_BACKGROUNDS)) {
+ throw new \InvalidArgumentException('The given file name is invalid');
+ }
$this->config->setUserValue($this->userId, 'dashboard', 'background', $fileName);
}
- public function setUrlBackground($url) {
- $this->config->setUserValue($this->userId, 'dashboard', 'background', 'custom');
- if (substr($url, 0, 1) === '/') {
- $url = \OC::$server->getURLGenerator()->getAbsoluteURL($url);
+ public function setColorBackground(string $color) {
+ if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $color)) {
+ throw new \InvalidArgumentException('The given color is invalid');
}
-
- $client = \OC::$server->getHTTPClientService()->newClient();
- $response = $client->get($url);
- $content = $response->getBody();
- $newFile = $this->dashboardUserFolder->newFile('background.jpg', $content);
+ $this->config->setUserValue($this->userId, 'dashboard', 'background', $color);
}
public function getBackground() {
<template>
- <div id="app-dashboard" :style="{ backgroundImage: `url(${backgroundImage})` }">
+ <div id="app-dashboard" :style="backgroundStyle">
<h2>{{ greeting.text }}</h2>
<div class="statuses">
<div v-for="status in registeredStatus"
import { Modal } from '@nextcloud/vue'
import Draggable from 'vuedraggable'
import axios from '@nextcloud/axios'
-import { generateUrl, generateFilePath } from '@nextcloud/router'
+import { generateUrl } from '@nextcloud/router'
import isMobile from './mixins/isMobile'
import BackgroundSettings from './components/BackgroundSettings'
+import getBackgroundUrl from './helpers/getBackgroundUrl'
+import prefixWithBaseUrl from './helpers/prefixWithBaseUrl'
const panels = loadState('dashboard', 'panels')
const firstRun = loadState('dashboard', 'firstRun')
const background = loadState('dashboard', 'background')
-
-const prefixWithBaseUrl = (url) => generateFilePath('dashboard', '', 'img/') + url
-
-// FIXME: move out duplicate
-const getBackgroundUrl = (background, time = 0) => {
- if (background === 'default') {
- if (window.OCA.Accessibility.theme === 'dark') {
- return prefixWithBaseUrl('eduardo-neves-pedra-azul.jpg')
- }
- return prefixWithBaseUrl('kamil-porembinski-clouds.jpg')
- } else if (background === 'custom') {
- return generateUrl('/apps/dashboard/background') + '?v=' + time
- }
- return prefixWithBaseUrl(background)
-}
+const version = loadState('dashboard', 'version')
export default {
name: 'App',
appStoreUrl: generateUrl('/settings/apps/dashboard'),
statuses: {},
background,
- backgroundTime: Date.now(),
+ version,
defaultBackground: window.OCA.Accessibility.theme === 'dark' ? prefixWithBaseUrl('flickr-148302424@N05-36591009215.jpg?v=1') : prefixWithBaseUrl('flickr-paszczak000-8715851521.jpg?v=1'),
}
},
computed: {
backgroundImage() {
- return getBackgroundUrl(this.background, this.backgroundTime)
+ return getBackgroundUrl(this.background, this.version)
+ },
+ backgroundStyle() {
+ if (this.background.match(/#[0-9A-Fa-f]{6}/g)) {
+ return null
+ }
+ return {
+ backgroundImage: `url(${this.backgroundImage})`,
+ }
},
tooltip() {
if (!this.firstRun) {
this.firstRun = false
}, 1000)
},
- updateBackground(backgroundType) {
- this.background = backgroundType
+ updateBackground(data) {
+ this.background = data.type === 'custom' || data.type === 'default' ? data.type : data.value
+ this.version = data.version
},
},
}
{{ t('dashboard', 'Default images') }}
</div>
</a>
+ <a class="background color"
+ tabindex="0"
+ @click="pickColor"
+ @keyup.enter="pickColor"
+ @keyup.space="pickColor">
+ <div class="background--preview">
+ {{ t('dashboard', 'Plain background') }}
+ </div>
+ </a>
<a v-for="background in shippedBackgrounds"
:key="background.name"
tabindex="0"
<script>
import axios from '@nextcloud/axios'
-import { generateUrl, generateFilePath } from '@nextcloud/router'
+import { generateUrl } from '@nextcloud/router'
import { loadState } from '@nextcloud/initial-state'
-
-const prefixWithBaseUrl = (url) => generateFilePath('dashboard', '', 'img/') + url
+import getBackgroundUrl from './../helpers/getBackgroundUrl'
+import prefixWithBaseUrl from './../helpers/prefixWithBaseUrl'
const shippedBackgroundList = loadState('dashboard', 'shippedBackgrounds')
-const getBackgroundUrl = (background, time = 0) => {
- if (background === 'default') {
- if (window.OCA.Accessibility.theme === 'dark') {
- return prefixWithBaseUrl('eduardo-neves-pedra-azul.jpg')
- }
- return prefixWithBaseUrl('kamil-porembinski-clouds.jpg')
- } else if (background === 'custom') {
- return generateUrl('/apps/dashboard/background') + '?v=' + time
- }
- return prefixWithBaseUrl(background)
-}
-
export default {
name: 'BackgroundSettings',
data() {
},
},
methods: {
- async update(state) {
- const date = Date.now()
- this.backgroundImage = getBackgroundUrl(state, date)
+ async update(data) {
+ const background = data.type === 'custom' || data.type === 'default' ? data.type : data.value
+ this.backgroundImage = getBackgroundUrl(background, data.version)
const image = new Image()
image.onload = () => {
- this.$emit('updateBackground', state)
+ this.$emit('updateBackground', data)
this.loading = false
}
image.src = this.backgroundImage
},
async setDefault() {
- console.debug('SetDefault')
- await axios.post(generateUrl('/apps/dashboard/background'))
- this.update('default')
+ this.loading = 'default'
+ const result = await axios.post(generateUrl('/apps/dashboard/background/default'))
+ this.update(result.data)
},
async setShipped(shipped) {
this.loading = shipped
- await axios.post(generateUrl('/apps/dashboard/background'), { shipped })
- this.update(shipped)
- },
- async setUrl(url) {
- this.loading = true
- await axios.post(generateUrl('/apps/dashboard/background'), { url })
- this.update('custom')
+ const result = await axios.post(generateUrl('/apps/dashboard/background/shipped'), { value: shipped })
+ this.update(result.data)
},
async setFile(path) {
- this.loading = true
- await axios.post(generateUrl('/apps/dashboard/background'), { path })
- this.update('custom')
+ this.loading = 'custom'
+ const result = await axios.post(generateUrl('/apps/dashboard/background/custom'), { value: path })
+ this.update(result.data)
+ },
+ async pickColor() {
+ this.loading = 'color'
+ const color = OCA && OCA.Theming ? OCA.Theming.color : '#0082c9'
+ const result = await axios.post(generateUrl('/apps/dashboard/background/color'), { value: color })
+ this.update(result.data)
},
pickFile() {
window.OC.dialogs.filepicker(t('dashboard', 'Insert from {productName}', { productName: OC.theme.name }), (path, type) => {
background-position: center center;
}
- &.filepicker, &.default {
+ &.filepicker, &.default, &.color {
border: 2px solid var(--color-border);
.background--preview {
line-height: 100px;
}
}
+ &.color .background--preview {
+ background-color: var(--color-primary);
+ color: var(--color-primary-text);
+ }
+
&:hover,
&:focus {
border: 2px solid var(--color-primary);
--- /dev/null
+/*
+ * @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * 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 { generateUrl } from '@nextcloud/router'
+import prefixWithBaseUrl from './prefixWithBaseUrl'
+
+export default (background, time = 0) => {
+ if (background === 'default') {
+ if (window.OCA.Accessibility.theme === 'dark') {
+ return prefixWithBaseUrl('eduardo-neves-pedra-azul.jpg')
+ }
+ return prefixWithBaseUrl('kamil-porembinski-clouds.jpg')
+ } else if (background === 'custom') {
+ return generateUrl('/apps/dashboard/background') + '?v=' + time
+ }
+ return prefixWithBaseUrl(background)
+}
--- /dev/null
+/*
+ * @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * 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'
+
+export default (url) => generateFilePath('dashboard', '', 'img/') + url