Allow to set a primary color background

Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
Julius Härtl 2020-08-17 21:29:29 +02:00
parent fa2072e36b
commit 5661775568
No known key found for this signature in database
GPG Key ID: 4C614C6ED2CDE6DF
7 changed files with 151 additions and 75 deletions

View File

@ -29,6 +29,6 @@ return [
['name' => 'dashboard#index', 'url' => '/', 'verb' => 'GET'], ['name' => 'dashboard#index', 'url' => '/', 'verb' => 'GET'],
['name' => 'dashboard#updateLayout', 'url' => '/layout', 'verb' => 'POST'], ['name' => 'dashboard#updateLayout', 'url' => '/layout', 'verb' => 'POST'],
['name' => 'dashboard#getBackground', 'url' => '/background', 'verb' => 'GET'], ['name' => 'dashboard#getBackground', 'url' => '/background', 'verb' => 'GET'],
['name' => 'dashboard#setBackground', 'url' => '/background', 'verb' => 'POST'], ['name' => 'dashboard#setBackground', 'url' => '/background/{type}', 'verb' => 'POST'],
] ]
]; ];

View File

@ -108,6 +108,7 @@ class DashboardController extends Controller {
$this->inititalStateService->provideInitialState('dashboard', 'firstRun', $this->config->getUserValue($this->userId, 'dashboard', 'firstRun', '1') === '1'); $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', 'shippedBackgrounds', BackgroundService::SHIPPED_BACKGROUNDS);
$this->inititalStateService->provideInitialState('dashboard', 'background', $this->config->getUserValue($this->userId, 'dashboard', 'background', 'default')); $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'); $this->config->setUserValue($this->userId, 'dashboard', 'firstRun', '0');
return new TemplateResponse('dashboard', 'index'); return new TemplateResponse('dashboard', 'index');
@ -126,18 +127,35 @@ class DashboardController extends Controller {
/** /**
* @NoAdminRequired * @NoAdminRequired
*/ */
public function setBackground($path = null, $url = null, $shipped = null): JSONResponse { public function setBackground(string $type = 'default', $value): JSONResponse {
if ($shipped !== null) { $currentVersion = $this->config->getUserValue($this->userId, 'dashboard', 'backgroundVersion', 0);
$this->backgroundService->setShippedBackground($shipped); try {
} else if ($path !== null) { switch ($type) {
$this->backgroundService->setFileBackground($path); case 'shipped':
} else if ($url !== null) { $this->backgroundService->setShippedBackground($value);
$this->backgroundService->setUrlBackground($url); break;
} else { case 'custom':
$this->backgroundService->setDefaultBackground(); $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);
} }
$currentVersion++;
return new JSONResponse([]); $this->config->setUserValue($this->userId, 'dashboard', 'backgroundVersion', $currentVersion);
return new JSONResponse([
'type' => $type,
'value' => $value,
'version' => $this->config->getUserValue($this->userId, 'dashboard', 'backgroundVersion', $currentVersion)
]);
} }
/** /**

View File

@ -74,19 +74,17 @@ class BackgroundService {
} }
public function setShippedBackground($fileName) { 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); $this->config->setUserValue($this->userId, 'dashboard', 'background', $fileName);
} }
public function setUrlBackground($url) { public function setColorBackground(string $color) {
$this->config->setUserValue($this->userId, 'dashboard', 'background', 'custom'); if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $color)) {
if (substr($url, 0, 1) === '/') { throw new \InvalidArgumentException('The given color is invalid');
$url = \OC::$server->getURLGenerator()->getAbsoluteURL($url);
} }
$this->config->setUserValue($this->userId, 'dashboard', 'background', $color);
$client = \OC::$server->getHTTPClientService()->newClient();
$response = $client->get($url);
$content = $response->getBody();
$newFile = $this->dashboardUserFolder->newFile('background.jpg', $content);
} }
public function getBackground() { public function getBackground() {

View File

@ -1,5 +1,5 @@
<template> <template>
<div id="app-dashboard" :style="{ backgroundImage: `url(${backgroundImage})` }"> <div id="app-dashboard" :style="backgroundStyle">
<h2>{{ greeting.text }}</h2> <h2>{{ greeting.text }}</h2>
<div class="statuses"> <div class="statuses">
<div v-for="status in registeredStatus" <div v-for="status in registeredStatus"
@ -73,28 +73,16 @@ import { getCurrentUser } from '@nextcloud/auth'
import { Modal } from '@nextcloud/vue' import { Modal } from '@nextcloud/vue'
import Draggable from 'vuedraggable' import Draggable from 'vuedraggable'
import axios from '@nextcloud/axios' import axios from '@nextcloud/axios'
import { generateUrl, generateFilePath } from '@nextcloud/router' import { generateUrl } from '@nextcloud/router'
import isMobile from './mixins/isMobile' import isMobile from './mixins/isMobile'
import BackgroundSettings from './components/BackgroundSettings' import BackgroundSettings from './components/BackgroundSettings'
import getBackgroundUrl from './helpers/getBackgroundUrl'
import prefixWithBaseUrl from './helpers/prefixWithBaseUrl'
const panels = loadState('dashboard', 'panels') const panels = loadState('dashboard', 'panels')
const firstRun = loadState('dashboard', 'firstRun') const firstRun = loadState('dashboard', 'firstRun')
const background = loadState('dashboard', 'background') const background = loadState('dashboard', 'background')
const version = loadState('dashboard', 'version')
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)
}
export default { export default {
name: 'App', name: 'App',
@ -121,13 +109,21 @@ export default {
appStoreUrl: generateUrl('/settings/apps/dashboard'), appStoreUrl: generateUrl('/settings/apps/dashboard'),
statuses: {}, statuses: {},
background, 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'), defaultBackground: window.OCA.Accessibility.theme === 'dark' ? prefixWithBaseUrl('flickr-148302424@N05-36591009215.jpg?v=1') : prefixWithBaseUrl('flickr-paszczak000-8715851521.jpg?v=1'),
} }
}, },
computed: { computed: {
backgroundImage() { 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() { tooltip() {
if (!this.firstRun) { if (!this.firstRun) {
@ -269,8 +265,9 @@ export default {
this.firstRun = false this.firstRun = false
}, 1000) }, 1000)
}, },
updateBackground(backgroundType) { updateBackground(data) {
this.background = backgroundType this.background = data.type === 'custom' || data.type === 'default' ? data.type : data.value
this.version = data.version
}, },
}, },
} }

View File

@ -41,6 +41,15 @@
{{ t('dashboard', 'Default images') }} {{ t('dashboard', 'Default images') }}
</div> </div>
</a> </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" <a v-for="background in shippedBackgrounds"
:key="background.name" :key="background.name"
tabindex="0" tabindex="0"
@ -56,24 +65,12 @@
<script> <script>
import axios from '@nextcloud/axios' import axios from '@nextcloud/axios'
import { generateUrl, generateFilePath } from '@nextcloud/router' import { generateUrl } from '@nextcloud/router'
import { loadState } from '@nextcloud/initial-state' import { loadState } from '@nextcloud/initial-state'
import getBackgroundUrl from './../helpers/getBackgroundUrl'
const prefixWithBaseUrl = (url) => generateFilePath('dashboard', '', 'img/') + url import prefixWithBaseUrl from './../helpers/prefixWithBaseUrl'
const shippedBackgroundList = loadState('dashboard', 'shippedBackgrounds') 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 { export default {
name: 'BackgroundSettings', name: 'BackgroundSettings',
data() { data() {
@ -93,35 +90,36 @@ export default {
}, },
}, },
methods: { methods: {
async update(state) { async update(data) {
const date = Date.now() const background = data.type === 'custom' || data.type === 'default' ? data.type : data.value
this.backgroundImage = getBackgroundUrl(state, date) this.backgroundImage = getBackgroundUrl(background, data.version)
const image = new Image() const image = new Image()
image.onload = () => { image.onload = () => {
this.$emit('updateBackground', state) this.$emit('updateBackground', data)
this.loading = false this.loading = false
} }
image.src = this.backgroundImage image.src = this.backgroundImage
}, },
async setDefault() { async setDefault() {
console.debug('SetDefault') this.loading = 'default'
await axios.post(generateUrl('/apps/dashboard/background')) const result = await axios.post(generateUrl('/apps/dashboard/background/default'))
this.update('default') this.update(result.data)
}, },
async setShipped(shipped) { async setShipped(shipped) {
this.loading = shipped this.loading = shipped
await axios.post(generateUrl('/apps/dashboard/background'), { shipped }) const result = await axios.post(generateUrl('/apps/dashboard/background/shipped'), { value: shipped })
this.update(shipped) this.update(result.data)
},
async setUrl(url) {
this.loading = true
await axios.post(generateUrl('/apps/dashboard/background'), { url })
this.update('custom')
}, },
async setFile(path) { async setFile(path) {
this.loading = true this.loading = 'custom'
await axios.post(generateUrl('/apps/dashboard/background'), { path }) const result = await axios.post(generateUrl('/apps/dashboard/background/custom'), { value: path })
this.update('custom') 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() { pickFile() {
window.OC.dialogs.filepicker(t('dashboard', 'Insert from {productName}', { productName: OC.theme.name }), (path, type) => { window.OC.dialogs.filepicker(t('dashboard', 'Insert from {productName}', { productName: OC.theme.name }), (path, type) => {
@ -161,13 +159,18 @@ export default {
background-position: center center; background-position: center center;
} }
&.filepicker, &.default { &.filepicker, &.default, &.color {
border: 2px solid var(--color-border); border: 2px solid var(--color-border);
.background--preview { .background--preview {
line-height: 100px; line-height: 100px;
} }
} }
&.color .background--preview {
background-color: var(--color-primary);
color: var(--color-primary-text);
}
&:hover, &:hover,
&:focus { &:focus {
border: 2px solid var(--color-primary); border: 2px solid var(--color-primary);

View File

@ -0,0 +1,36 @@
/*
* @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)
}

View File

@ -0,0 +1,24 @@
/*
* @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