diff options
author | Simon L <szaimen@e.mail.de> | 2022-09-15 00:36:51 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-15 00:36:51 +0200 |
commit | 009d5e93f71badf761144c15bcce7382dd579391 (patch) | |
tree | d6668a5a9834f70d300d0e3384ed7293dbd9b0c7 /apps | |
parent | bd03c7978537334822f1fc05049045d89cc56533 (diff) | |
parent | 02cc42d40ae7334609a3270ee1d16eec75098aa6 (diff) | |
download | nextcloud-server-009d5e93f71badf761144c15bcce7382dd579391.tar.gz nextcloud-server-009d5e93f71badf761144c15bcce7382dd579391.zip |
Merge pull request #33733 from nextcloud/change/appearance-accessibility-settings
Move background settings from dashboard app to Appearance and accessibility settings
Diffstat (limited to 'apps')
-rw-r--r-- | apps/dashboard/appinfo/routes.php | 2 | ||||
-rw-r--r-- | apps/dashboard/lib/Controller/DashboardController.php | 72 | ||||
-rw-r--r-- | apps/dashboard/src/DashboardApp.vue | 76 | ||||
-rw-r--r-- | apps/dashboard/src/helpers/getBackgroundUrl.js | 6 | ||||
-rw-r--r-- | apps/dashboard/src/helpers/prefixWithBaseUrl.js | 2 | ||||
-rw-r--r-- | apps/theming/appinfo/routes.php | 10 | ||||
-rw-r--r-- | apps/theming/img/background/anatoly-mikhaltsov-butterfly-wing-scale.jpg (renamed from apps/dashboard/img/anatoly-mikhaltsov-butterfly-wing-scale.jpg) | bin | 1064500 -> 1064500 bytes | |||
-rw-r--r-- | apps/theming/img/background/bernard-spragg-new-zealand-fern.jpg (renamed from apps/dashboard/img/bernard-spragg-new-zealand-fern.jpg) | bin | 1168815 -> 1168815 bytes | |||
-rw-r--r-- | apps/theming/img/background/bernie-cetonia-aurata-take-off-composition.jpg (renamed from apps/dashboard/img/bernie-cetonia-aurata-take-off-composition.jpg) | bin | 254916 -> 254916 bytes | |||
-rw-r--r-- | apps/theming/img/background/dejan-krsmanovic-ribbed-red-metal.jpg (renamed from apps/dashboard/img/dejan-krsmanovic-ribbed-red-metal.jpg) | bin | 1704506 -> 1704506 bytes | |||
-rw-r--r-- | apps/theming/img/background/eduardo-neves-pedra-azul.jpg (renamed from apps/dashboard/img/eduardo-neves-pedra-azul.jpg) | bin | 1809404 -> 1809404 bytes | |||
-rw-r--r-- | apps/theming/img/background/european-space-agency-barents-bloom.jpg (renamed from apps/dashboard/img/european-space-agency-barents-bloom.jpg) | bin | 535280 -> 535280 bytes | |||
-rw-r--r-- | apps/theming/img/background/hannes-fritz-flippity-floppity.jpg (renamed from apps/dashboard/img/hannes-fritz-flippity-floppity.jpg) | bin | 1191267 -> 1191267 bytes | |||
-rw-r--r-- | apps/theming/img/background/hannes-fritz-roulette.jpg (renamed from apps/dashboard/img/hannes-fritz-roulette.jpg) | bin | 1050114 -> 1050114 bytes | |||
-rw-r--r-- | apps/theming/img/background/hannes-fritz-sea-spray.jpg (renamed from apps/dashboard/img/hannes-fritz-sea-spray.jpg) | bin | 1305834 -> 1305834 bytes | |||
-rw-r--r-- | apps/theming/img/background/kamil-porembinski-clouds.jpg (renamed from apps/dashboard/img/kamil-porembinski-clouds.jpg) | bin | 190294 -> 190294 bytes | |||
-rw-r--r-- | apps/theming/img/background/lali-masriera-yellow-bricks.jpg (renamed from apps/dashboard/img/lali-masriera-yellow-bricks.jpg) | bin | 956390 -> 956390 bytes | |||
-rw-r--r-- | apps/theming/img/background/nasa-waxing-crescent-moon.jpg (renamed from apps/dashboard/img/nasa-waxing-crescent-moon.jpg) | bin | 285509 -> 285509 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/anatoly-mikhaltsov-butterfly-wing-scale.jpg (renamed from apps/dashboard/img/previews/anatoly-mikhaltsov-butterfly-wing-scale.jpg) | bin | 21756 -> 21756 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/bernard-spragg-new-zealand-fern.jpg (renamed from apps/dashboard/img/previews/bernard-spragg-new-zealand-fern.jpg) | bin | 28944 -> 28944 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/bernie-cetonia-aurata-take-off-composition.jpg (renamed from apps/dashboard/img/previews/bernie-cetonia-aurata-take-off-composition.jpg) | bin | 6638 -> 6638 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/dejan-krsmanovic-ribbed-red-metal.jpg (renamed from apps/dashboard/img/previews/dejan-krsmanovic-ribbed-red-metal.jpg) | bin | 18011 -> 18011 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/eduardo-neves-pedra-azul.jpg (renamed from apps/dashboard/img/previews/eduardo-neves-pedra-azul.jpg) | bin | 14976 -> 14976 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/european-space-agency-barents-bloom.jpg (renamed from apps/dashboard/img/previews/european-space-agency-barents-bloom.jpg) | bin | 14909 -> 14909 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/hannes-fritz-flippity-floppity.jpg (renamed from apps/dashboard/img/previews/hannes-fritz-flippity-floppity.jpg) | bin | 23780 -> 23780 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/hannes-fritz-roulette.jpg (renamed from apps/dashboard/img/previews/hannes-fritz-roulette.jpg) | bin | 21367 -> 21367 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/hannes-fritz-sea-spray.jpg (renamed from apps/dashboard/img/previews/hannes-fritz-sea-spray.jpg) | bin | 14859 -> 14859 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/kamil-porembinski-clouds.jpg (renamed from apps/dashboard/img/previews/kamil-porembinski-clouds.jpg) | bin | 6554 -> 6554 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/lali-masriera-yellow-bricks.jpg (renamed from apps/dashboard/img/previews/lali-masriera-yellow-bricks.jpg) | bin | 18140 -> 18140 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/nasa-waxing-crescent-moon.jpg (renamed from apps/dashboard/img/previews/nasa-waxing-crescent-moon.jpg) | bin | 4499 -> 4499 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/rawpixel-pink-tapioca-bubbles.jpg (renamed from apps/dashboard/img/previews/rawpixel-pink-tapioca-bubbles.jpg) | bin | 12960 -> 12960 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/tommy-chau-already.jpg (renamed from apps/dashboard/img/previews/tommy-chau-already.jpg) | bin | 18875 -> 18875 bytes | |||
-rw-r--r-- | apps/theming/img/background/preview/tommy-chau-lion-rock-hill.jpg (renamed from apps/dashboard/img/previews/tommy-chau-lion-rock-hill.jpg) | bin | 6446 -> 6446 bytes | |||
-rw-r--r-- | apps/theming/img/background/rawpixel-pink-tapioca-bubbles.jpg (renamed from apps/dashboard/img/rawpixel-pink-tapioca-bubbles.jpg) | bin | 464918 -> 464918 bytes | |||
-rw-r--r-- | apps/theming/img/background/tommy-chau-already.jpg (renamed from apps/dashboard/img/tommy-chau-already.jpg) | bin | 1245001 -> 1245001 bytes | |||
-rw-r--r-- | apps/theming/img/background/tommy-chau-lion-rock-hill.jpg (renamed from apps/dashboard/img/tommy-chau-lion-rock-hill.jpg) | bin | 244805 -> 244805 bytes | |||
-rw-r--r-- | apps/theming/lib/Controller/UserThemeController.php | 63 | ||||
-rw-r--r-- | apps/theming/lib/Listener/BeforeTemplateRenderedListener.php | 62 | ||||
-rw-r--r-- | apps/theming/lib/Service/BackgroundService.php (renamed from apps/dashboard/lib/Service/BackgroundService.php) | 39 | ||||
-rw-r--r-- | apps/theming/lib/Settings/Personal.php | 4 | ||||
-rw-r--r-- | apps/theming/lib/Themes/DefaultTheme.php | 19 | ||||
-rw-r--r-- | apps/theming/src/UserThemes.vue | 151 | ||||
-rw-r--r-- | apps/theming/src/components/BackgroundSettings.vue (renamed from apps/dashboard/src/components/BackgroundSettings.vue) | 42 | ||||
-rw-r--r-- | apps/theming/src/helpers/getBackgroundUrl.js | 51 | ||||
-rw-r--r-- | apps/theming/src/helpers/prefixWithBaseUrl.js | 27 | ||||
-rw-r--r-- | apps/theming/tests/Controller/UserThemeControllerTest.php | 9 | ||||
-rw-r--r-- | apps/theming/tests/Settings/PersonalTest.php | 4 |
47 files changed, 420 insertions, 219 deletions
diff --git a/apps/dashboard/appinfo/routes.php b/apps/dashboard/appinfo/routes.php index 76317b8daa7..2d930b2240d 100644 --- a/apps/dashboard/appinfo/routes.php +++ b/apps/dashboard/appinfo/routes.php @@ -29,8 +29,6 @@ return [ ['name' => 'dashboard#index', 'url' => '/', 'verb' => 'GET'], ['name' => 'dashboard#updateLayout', 'url' => '/layout', 'verb' => 'POST'], ['name' => 'dashboard#updateStatuses', 'url' => '/statuses', 'verb' => 'POST'], - ['name' => 'dashboard#getBackground', 'url' => '/background', 'verb' => 'GET'], - ['name' => 'dashboard#setBackground', 'url' => '/background/{type}', 'verb' => 'POST'], ], 'ocs' => [ ['name' => 'dashboardApi#getWidgetItems', 'url' => '/api/v1/widget-items', 'verb' => 'GET'], diff --git a/apps/dashboard/lib/Controller/DashboardController.php b/apps/dashboard/lib/Controller/DashboardController.php index 4d4f6a5f31c..6a7690b535c 100644 --- a/apps/dashboard/lib/Controller/DashboardController.php +++ b/apps/dashboard/lib/Controller/DashboardController.php @@ -28,16 +28,12 @@ declare(strict_types=1); */ namespace OCA\Dashboard\Controller; -use OCA\Dashboard\Service\BackgroundService; use OCA\Files\Event\LoadSidebar; use OCA\Viewer\Event\LoadViewer; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; -use OCP\AppFramework\Http\FileDisplayResponse; use OCP\AppFramework\Http\JSONResponse; -use OCP\AppFramework\Http\NotFoundResponse; use OCP\AppFramework\Http\TemplateResponse; -use OCP\App\IAppManager; use OCP\AppFramework\Services\IInitialState; use OCP\Dashboard\IManager; use OCP\Dashboard\IWidget; @@ -52,38 +48,28 @@ class DashboardController extends Controller { private $inititalState; /** @var IEventDispatcher */ private $eventDispatcher; - /** @var IAppManager */ - private $appManager; /** @var IManager */ private $dashboardManager; /** @var IConfig */ private $config; /** @var string */ private $userId; - /** - * @var BackgroundService - */ - private $backgroundService; public function __construct( string $appName, IRequest $request, IInitialState $initialState, IEventDispatcher $eventDispatcher, - IAppManager $appManager, IManager $dashboardManager, IConfig $config, - BackgroundService $backgroundService, $userId ) { parent::__construct($appName, $request); $this->inititalState = $initialState; $this->eventDispatcher = $eventDispatcher; - $this->appManager = $appManager; $this->dashboardManager = $dashboardManager; $this->config = $config; - $this->backgroundService = $backgroundService; $this->userId = $userId; } @@ -119,18 +105,10 @@ class DashboardController extends Controller { // It does not matter if some statuses are missing from the array, missing ones are considered enabled $statuses = ($statuses && count($statuses) > 0) ? $statuses : ['weather' => true]; - // if theming app is enabled and wants to override default, we pass it - $themingDefaultBackground = $this->appManager->isEnabledForUser('theming') - ? $this->config->getAppValue('theming', 'backgroundMime', '') - : ''; - $this->inititalState->provideInitialState('themingDefaultBackground', $themingDefaultBackground); $this->inititalState->provideInitialState('panels', $widgets); $this->inititalState->provideInitialState('statuses', $statuses); $this->inititalState->provideInitialState('layout', $userLayout); $this->inititalState->provideInitialState('firstRun', $this->config->getUserValue($this->userId, 'dashboard', 'firstRun', '1') === '1'); - $this->inititalState->provideInitialState('shippedBackgrounds', BackgroundService::SHIPPED_BACKGROUNDS); - $this->inititalState->provideInitialState('background', $this->config->getUserValue($this->userId, 'dashboard', 'background', 'default')); - $this->inititalState->provideInitialState('version', $this->config->getUserValue($this->userId, 'dashboard', 'backgroundVersion', 0)); $this->config->setUserValue($this->userId, 'dashboard', 'firstRun', '0'); $response = new TemplateResponse('dashboard', 'index', [ @@ -165,54 +143,4 @@ class DashboardController extends Controller { $this->config->setUserValue($this->userId, 'dashboard', 'statuses', $statuses); return new JSONResponse(['statuses' => $statuses]); } - - /** - * @NoAdminRequired - */ - public function setBackground(string $type = 'default', string $value = ''): JSONResponse { - $currentVersion = (int)$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); - } catch (\Throwable $e) { - return new JSONResponse(['error' => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR); - } - $currentVersion++; - $this->config->setUserValue($this->userId, 'dashboard', 'backgroundVersion', (string)$currentVersion); - return new JSONResponse([ - 'type' => $type, - 'value' => $value, - 'version' => $this->config->getUserValue($this->userId, 'dashboard', 'backgroundVersion', $currentVersion) - ]); - } - - /** - * @NoAdminRequired - * @NoCSRFRequired - */ - public function getBackground(): Http\Response { - $file = $this->backgroundService->getBackground(); - if ($file !== null) { - $response = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => $file->getMimeType()]); - $response->cacheFor(24 * 60 * 60); - return $response; - } - return new NotFoundResponse(); - } } diff --git a/apps/dashboard/src/DashboardApp.vue b/apps/dashboard/src/DashboardApp.vue index b9fce59268b..3c13278f0d4 100644 --- a/apps/dashboard/src/DashboardApp.vue +++ b/apps/dashboard/src/DashboardApp.vue @@ -73,11 +73,6 @@ <a v-if="isAdmin" :href="appStoreUrl" class="button">{{ t('dashboard', 'Get more widgets from the App Store') }}</a> - <h3>{{ t('dashboard', 'Change background image') }}</h3> - <BackgroundSettings :background="background" - :theming-default-background="themingDefaultBackground" - @update:background="updateBackground" /> - <h3>{{ t('dashboard', 'Weather service') }}</h3> <p> {{ t('dashboard', 'For your privacy, the weather data is requested by your Nextcloud server on your behalf so the weather service receives no personal information.') }} @@ -93,7 +88,7 @@ </template> <script> -import { generateUrl } from '@nextcloud/router' +import { generateUrl, imagePath } from '@nextcloud/router' import { getCurrentUser } from '@nextcloud/auth' import { loadState } from '@nextcloud/initial-state' import axios from '@nextcloud/axios' @@ -103,16 +98,16 @@ import NcModal from '@nextcloud/vue/dist/Components/NcModal' import Pencil from 'vue-material-design-icons/Pencil.vue' import Vue from 'vue' -import isMobile from './mixins/isMobile' -import BackgroundSettings from './components/BackgroundSettings' -import getBackgroundUrl from './helpers/getBackgroundUrl' +import isMobile from './mixins/isMobile.js' +import { getBackgroundUrl } from './helpers/getBackgroundUrl.js' const panels = loadState('dashboard', 'panels') const firstRun = loadState('dashboard', 'firstRun') -const background = loadState('dashboard', 'background') -const themingDefaultBackground = loadState('dashboard', 'themingDefaultBackground') -const version = loadState('dashboard', 'version') -const shippedBackgroundList = loadState('dashboard', 'shippedBackgrounds') + +const background = loadState('theming', 'background') +const backgroundVersion = loadState('theming', 'backgroundVersion') +const themingDefaultBackground = loadState('theming', 'themingDefaultBackground') +const shippedBackgroundList = loadState('theming', 'shippedBackgrounds') const statusInfo = { weather: { @@ -128,7 +123,6 @@ const statusInfo = { export default { name: 'DashboardApp', components: { - BackgroundSettings, NcButton, Draggable, NcModal, @@ -158,12 +152,11 @@ export default { statuses: {}, background, themingDefaultBackground, - version, } }, computed: { backgroundImage() { - return getBackgroundUrl(this.background, this.version, this.themingDefaultBackground) + return getBackgroundUrl(this.background, backgroundVersion, this.themingDefaultBackground) }, backgroundStyle() { if ((this.background === 'default' && this.themingDefaultBackground === 'backgroundColor') @@ -175,7 +168,6 @@ export default { backgroundImage: this.background === 'default' ? 'var(--image-main-background)' : `url('${this.backgroundImage}')`, } }, - greeting() { const time = this.timer.getHours() @@ -280,6 +272,32 @@ export default { }, methods: { + updateGlobalStyles() { + // Override primary-invert-if-bright and color-primary-text if background is set + const isBackgroundBright = shippedBackgroundList[this.background]?.theming === 'dark' + if (isBackgroundBright) { + document.querySelector('#header').style.setProperty('--primary-invert-if-bright', 'invert(100%)') + document.querySelector('#header').style.setProperty('--color-primary-text', '#000000') + // document.body.removeAttribute('data-theme-dark') + // document.body.setAttribute('data-theme-light', 'true') + } else { + document.querySelector('#header').style.setProperty('--primary-invert-if-bright', 'no') + document.querySelector('#header').style.setProperty('--color-primary-text', '#ffffff') + // document.body.removeAttribute('data-theme-light') + // document.body.setAttribute('data-theme-dark', 'true') + } + + const themeElements = [document.documentElement, document.querySelector('#header'), document.querySelector('body')] + for (const element of themeElements) { + if (this.background === 'default') { + element.style.setProperty('--image-main-background', `url('${imagePath('core', 'app-background.jpg')}')`) + } else if (this.background.match(/#[0-9A-Fa-f]{6}/g)) { + element.style.setProperty('--image-main-background', undefined) + } else { + element.style.setProperty('--image-main-background', this.backgroundStyle.backgroundImage) + } + } + }, /** * Method to register panels that will be called by the integrating apps * @@ -354,30 +372,6 @@ export default { this.firstRun = false }, 1000) }, - updateBackground(data) { - this.background = data.type === 'custom' || data.type === 'default' ? data.type : data.value - this.version = data.version - this.updateGlobalStyles() - }, - updateGlobalStyles() { - // Override primary-invert-if-bright and color-primary-text if background is set - const isBackgroundBright = shippedBackgroundList[this.background]?.theming === 'dark' - if (isBackgroundBright) { - document.querySelector('#header').style.setProperty('--primary-invert-if-bright', 'invert(100%)') - document.querySelector('#header').style.setProperty('--color-primary-text', '#000000') - // document.body.removeAttribute('data-theme-dark') - // document.body.setAttribute('data-theme-light', 'true') - } else { - document.querySelector('#header').style.setProperty('--primary-invert-if-bright', 'no') - document.querySelector('#header').style.setProperty('--color-primary-text', '#ffffff') - // document.body.removeAttribute('data-theme-light') - // document.body.setAttribute('data-theme-dark', 'true') - } - - document.documentElement.style.setProperty('--image-main-background', this.backgroundStyle.backgroundImage) - document.querySelector('#header').style.setProperty('--image-main-background', this.backgroundStyle.backgroundImage) - document.querySelector('body').style.setProperty('--image-main-background', this.backgroundStyle.backgroundImage) - }, updateSkipLink() { // Make sure "Skip to main content" link points to the app content document.getElementsByClassName('skip-navigation')[0].setAttribute('href', '#app-dashboard') diff --git a/apps/dashboard/src/helpers/getBackgroundUrl.js b/apps/dashboard/src/helpers/getBackgroundUrl.js index 4876fa77e86..88a3ab57291 100644 --- a/apps/dashboard/src/helpers/getBackgroundUrl.js +++ b/apps/dashboard/src/helpers/getBackgroundUrl.js @@ -23,9 +23,9 @@ */ import { generateUrl } from '@nextcloud/router' -import prefixWithBaseUrl from './prefixWithBaseUrl' +import { prefixWithBaseUrl } from './prefixWithBaseUrl.js' -export default (background, time = 0, themingDefaultBackground = '') => { +export const getBackgroundUrl = (background, time = 0, themingDefaultBackground = '') => { const enabledThemes = window.OCA?.Theming?.enabledThemes || [] const isDarkTheme = (enabledThemes.length === 0 || enabledThemes[0] === 'default') ? window.matchMedia('(prefers-color-scheme: dark)').matches @@ -42,7 +42,7 @@ export default (background, time = 0, themingDefaultBackground = '') => { return prefixWithBaseUrl('kamil-porembinski-clouds.jpg') } else if (background === 'custom') { - return generateUrl('/apps/dashboard/background') + '?v=' + time + return generateUrl('/apps/theming/background') + '?v=' + time } return prefixWithBaseUrl(background) diff --git a/apps/dashboard/src/helpers/prefixWithBaseUrl.js b/apps/dashboard/src/helpers/prefixWithBaseUrl.js index cd0cc6a9464..d2f42c93549 100644 --- a/apps/dashboard/src/helpers/prefixWithBaseUrl.js +++ b/apps/dashboard/src/helpers/prefixWithBaseUrl.js @@ -22,4 +22,4 @@ import { generateFilePath } from '@nextcloud/router' -export default (url) => generateFilePath('dashboard', '', 'img/') + url +export const prefixWithBaseUrl = (url) => generateFilePath('theming', '', 'img/background/') + url diff --git a/apps/theming/appinfo/routes.php b/apps/theming/appinfo/routes.php index fa8dde90786..0b51b22dbb7 100644 --- a/apps/theming/appinfo/routes.php +++ b/apps/theming/appinfo/routes.php @@ -78,6 +78,16 @@ return [ 'verb' => 'GET', 'requirements' => ['image' => '.+'] ], + [ + 'name' => 'userTheme#getBackground', + 'url' => '/background', + 'verb' => 'GET', + ], + [ + 'name' => 'userTheme#setBackground', + 'url' => '/background/{type}', + 'verb' => 'POST', + ], ], 'ocs' => [ [ diff --git a/apps/dashboard/img/anatoly-mikhaltsov-butterfly-wing-scale.jpg b/apps/theming/img/background/anatoly-mikhaltsov-butterfly-wing-scale.jpg Binary files differindex 36b0a0675de..36b0a0675de 100644 --- a/apps/dashboard/img/anatoly-mikhaltsov-butterfly-wing-scale.jpg +++ b/apps/theming/img/background/anatoly-mikhaltsov-butterfly-wing-scale.jpg diff --git a/apps/dashboard/img/bernard-spragg-new-zealand-fern.jpg b/apps/theming/img/background/bernard-spragg-new-zealand-fern.jpg Binary files differindex c4df0d673b0..c4df0d673b0 100644 --- a/apps/dashboard/img/bernard-spragg-new-zealand-fern.jpg +++ b/apps/theming/img/background/bernard-spragg-new-zealand-fern.jpg diff --git a/apps/dashboard/img/bernie-cetonia-aurata-take-off-composition.jpg b/apps/theming/img/background/bernie-cetonia-aurata-take-off-composition.jpg Binary files differindex a299a44ff8c..a299a44ff8c 100644 --- a/apps/dashboard/img/bernie-cetonia-aurata-take-off-composition.jpg +++ b/apps/theming/img/background/bernie-cetonia-aurata-take-off-composition.jpg diff --git a/apps/dashboard/img/dejan-krsmanovic-ribbed-red-metal.jpg b/apps/theming/img/background/dejan-krsmanovic-ribbed-red-metal.jpg Binary files differindex 586f6c13149..586f6c13149 100644 --- a/apps/dashboard/img/dejan-krsmanovic-ribbed-red-metal.jpg +++ b/apps/theming/img/background/dejan-krsmanovic-ribbed-red-metal.jpg diff --git a/apps/dashboard/img/eduardo-neves-pedra-azul.jpg b/apps/theming/img/background/eduardo-neves-pedra-azul.jpg Binary files differindex 937da4e2c5e..937da4e2c5e 100644 --- a/apps/dashboard/img/eduardo-neves-pedra-azul.jpg +++ b/apps/theming/img/background/eduardo-neves-pedra-azul.jpg diff --git a/apps/dashboard/img/european-space-agency-barents-bloom.jpg b/apps/theming/img/background/european-space-agency-barents-bloom.jpg Binary files differindex 700fa236052..700fa236052 100644 --- a/apps/dashboard/img/european-space-agency-barents-bloom.jpg +++ b/apps/theming/img/background/european-space-agency-barents-bloom.jpg diff --git a/apps/dashboard/img/hannes-fritz-flippity-floppity.jpg b/apps/theming/img/background/hannes-fritz-flippity-floppity.jpg Binary files differindex 73302a4ccc3..73302a4ccc3 100644 --- a/apps/dashboard/img/hannes-fritz-flippity-floppity.jpg +++ b/apps/theming/img/background/hannes-fritz-flippity-floppity.jpg diff --git a/apps/dashboard/img/hannes-fritz-roulette.jpg b/apps/theming/img/background/hannes-fritz-roulette.jpg Binary files differindex b2406d21cb6..b2406d21cb6 100644 --- a/apps/dashboard/img/hannes-fritz-roulette.jpg +++ b/apps/theming/img/background/hannes-fritz-roulette.jpg diff --git a/apps/dashboard/img/hannes-fritz-sea-spray.jpg b/apps/theming/img/background/hannes-fritz-sea-spray.jpg Binary files differindex adab409139e..adab409139e 100644 --- a/apps/dashboard/img/hannes-fritz-sea-spray.jpg +++ b/apps/theming/img/background/hannes-fritz-sea-spray.jpg diff --git a/apps/dashboard/img/kamil-porembinski-clouds.jpg b/apps/theming/img/background/kamil-porembinski-clouds.jpg Binary files differindex b9cc2cc5cd1..b9cc2cc5cd1 100644 --- a/apps/dashboard/img/kamil-porembinski-clouds.jpg +++ b/apps/theming/img/background/kamil-porembinski-clouds.jpg diff --git a/apps/dashboard/img/lali-masriera-yellow-bricks.jpg b/apps/theming/img/background/lali-masriera-yellow-bricks.jpg Binary files differindex b32c3e56168..b32c3e56168 100644 --- a/apps/dashboard/img/lali-masriera-yellow-bricks.jpg +++ b/apps/theming/img/background/lali-masriera-yellow-bricks.jpg diff --git a/apps/dashboard/img/nasa-waxing-crescent-moon.jpg b/apps/theming/img/background/nasa-waxing-crescent-moon.jpg Binary files differindex 281f1dc53f7..281f1dc53f7 100644 --- a/apps/dashboard/img/nasa-waxing-crescent-moon.jpg +++ b/apps/theming/img/background/nasa-waxing-crescent-moon.jpg diff --git a/apps/dashboard/img/previews/anatoly-mikhaltsov-butterfly-wing-scale.jpg b/apps/theming/img/background/preview/anatoly-mikhaltsov-butterfly-wing-scale.jpg Binary files differindex a749442979f..a749442979f 100644 --- a/apps/dashboard/img/previews/anatoly-mikhaltsov-butterfly-wing-scale.jpg +++ b/apps/theming/img/background/preview/anatoly-mikhaltsov-butterfly-wing-scale.jpg diff --git a/apps/dashboard/img/previews/bernard-spragg-new-zealand-fern.jpg b/apps/theming/img/background/preview/bernard-spragg-new-zealand-fern.jpg Binary files differindex 49844a6e243..49844a6e243 100644 --- a/apps/dashboard/img/previews/bernard-spragg-new-zealand-fern.jpg +++ b/apps/theming/img/background/preview/bernard-spragg-new-zealand-fern.jpg diff --git a/apps/dashboard/img/previews/bernie-cetonia-aurata-take-off-composition.jpg b/apps/theming/img/background/preview/bernie-cetonia-aurata-take-off-composition.jpg Binary files differindex 08fd5cf1c21..08fd5cf1c21 100644 --- a/apps/dashboard/img/previews/bernie-cetonia-aurata-take-off-composition.jpg +++ b/apps/theming/img/background/preview/bernie-cetonia-aurata-take-off-composition.jpg diff --git a/apps/dashboard/img/previews/dejan-krsmanovic-ribbed-red-metal.jpg b/apps/theming/img/background/preview/dejan-krsmanovic-ribbed-red-metal.jpg Binary files differindex b4430b2485c..b4430b2485c 100644 --- a/apps/dashboard/img/previews/dejan-krsmanovic-ribbed-red-metal.jpg +++ b/apps/theming/img/background/preview/dejan-krsmanovic-ribbed-red-metal.jpg diff --git a/apps/dashboard/img/previews/eduardo-neves-pedra-azul.jpg b/apps/theming/img/background/preview/eduardo-neves-pedra-azul.jpg Binary files differindex e62eb04f954..e62eb04f954 100644 --- a/apps/dashboard/img/previews/eduardo-neves-pedra-azul.jpg +++ b/apps/theming/img/background/preview/eduardo-neves-pedra-azul.jpg diff --git a/apps/dashboard/img/previews/european-space-agency-barents-bloom.jpg b/apps/theming/img/background/preview/european-space-agency-barents-bloom.jpg Binary files differindex d23a07e5364..d23a07e5364 100644 --- a/apps/dashboard/img/previews/european-space-agency-barents-bloom.jpg +++ b/apps/theming/img/background/preview/european-space-agency-barents-bloom.jpg diff --git a/apps/dashboard/img/previews/hannes-fritz-flippity-floppity.jpg b/apps/theming/img/background/preview/hannes-fritz-flippity-floppity.jpg Binary files differindex 2c6a91f1b2e..2c6a91f1b2e 100644 --- a/apps/dashboard/img/previews/hannes-fritz-flippity-floppity.jpg +++ b/apps/theming/img/background/preview/hannes-fritz-flippity-floppity.jpg diff --git a/apps/dashboard/img/previews/hannes-fritz-roulette.jpg b/apps/theming/img/background/preview/hannes-fritz-roulette.jpg Binary files differindex 4d69e579210..4d69e579210 100644 --- a/apps/dashboard/img/previews/hannes-fritz-roulette.jpg +++ b/apps/theming/img/background/preview/hannes-fritz-roulette.jpg diff --git a/apps/dashboard/img/previews/hannes-fritz-sea-spray.jpg b/apps/theming/img/background/preview/hannes-fritz-sea-spray.jpg Binary files differindex 08b24f5be91..08b24f5be91 100644 --- a/apps/dashboard/img/previews/hannes-fritz-sea-spray.jpg +++ b/apps/theming/img/background/preview/hannes-fritz-sea-spray.jpg diff --git a/apps/dashboard/img/previews/kamil-porembinski-clouds.jpg b/apps/theming/img/background/preview/kamil-porembinski-clouds.jpg Binary files differindex 8103148ba49..8103148ba49 100644 --- a/apps/dashboard/img/previews/kamil-porembinski-clouds.jpg +++ b/apps/theming/img/background/preview/kamil-porembinski-clouds.jpg diff --git a/apps/dashboard/img/previews/lali-masriera-yellow-bricks.jpg b/apps/theming/img/background/preview/lali-masriera-yellow-bricks.jpg Binary files differindex 01861cf001a..01861cf001a 100644 --- a/apps/dashboard/img/previews/lali-masriera-yellow-bricks.jpg +++ b/apps/theming/img/background/preview/lali-masriera-yellow-bricks.jpg diff --git a/apps/dashboard/img/previews/nasa-waxing-crescent-moon.jpg b/apps/theming/img/background/preview/nasa-waxing-crescent-moon.jpg Binary files differindex 8c46e372ad0..8c46e372ad0 100644 --- a/apps/dashboard/img/previews/nasa-waxing-crescent-moon.jpg +++ b/apps/theming/img/background/preview/nasa-waxing-crescent-moon.jpg diff --git a/apps/dashboard/img/previews/rawpixel-pink-tapioca-bubbles.jpg b/apps/theming/img/background/preview/rawpixel-pink-tapioca-bubbles.jpg Binary files differindex 483c710c1ed..483c710c1ed 100644 --- a/apps/dashboard/img/previews/rawpixel-pink-tapioca-bubbles.jpg +++ b/apps/theming/img/background/preview/rawpixel-pink-tapioca-bubbles.jpg diff --git a/apps/dashboard/img/previews/tommy-chau-already.jpg b/apps/theming/img/background/preview/tommy-chau-already.jpg Binary files differindex 46976b0292d..46976b0292d 100644 --- a/apps/dashboard/img/previews/tommy-chau-already.jpg +++ b/apps/theming/img/background/preview/tommy-chau-already.jpg diff --git a/apps/dashboard/img/previews/tommy-chau-lion-rock-hill.jpg b/apps/theming/img/background/preview/tommy-chau-lion-rock-hill.jpg Binary files differindex 59a3e131871..59a3e131871 100644 --- a/apps/dashboard/img/previews/tommy-chau-lion-rock-hill.jpg +++ b/apps/theming/img/background/preview/tommy-chau-lion-rock-hill.jpg diff --git a/apps/dashboard/img/rawpixel-pink-tapioca-bubbles.jpg b/apps/theming/img/background/rawpixel-pink-tapioca-bubbles.jpg Binary files differindex 3b96469ee2c..3b96469ee2c 100644 --- a/apps/dashboard/img/rawpixel-pink-tapioca-bubbles.jpg +++ b/apps/theming/img/background/rawpixel-pink-tapioca-bubbles.jpg diff --git a/apps/dashboard/img/tommy-chau-already.jpg b/apps/theming/img/background/tommy-chau-already.jpg Binary files differindex 8d9cc45101f..8d9cc45101f 100644 --- a/apps/dashboard/img/tommy-chau-already.jpg +++ b/apps/theming/img/background/tommy-chau-already.jpg diff --git a/apps/dashboard/img/tommy-chau-lion-rock-hill.jpg b/apps/theming/img/background/tommy-chau-lion-rock-hill.jpg Binary files differindex f1247dd9c62..f1247dd9c62 100644 --- a/apps/dashboard/img/tommy-chau-lion-rock-hill.jpg +++ b/apps/theming/img/background/tommy-chau-lion-rock-hill.jpg diff --git a/apps/theming/lib/Controller/UserThemeController.php b/apps/theming/lib/Controller/UserThemeController.php index 71d78db4b3d..327029b26cd 100644 --- a/apps/theming/lib/Controller/UserThemeController.php +++ b/apps/theming/lib/Controller/UserThemeController.php @@ -30,9 +30,15 @@ declare(strict_types=1); */ namespace OCA\Theming\Controller; +use OCA\Theming\AppInfo\Application; use OCA\Theming\ITheme; +use OCA\Theming\Service\BackgroundService; use OCA\Theming\Service\ThemesService; +use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\FileDisplayResponse; +use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\NotFoundResponse; use OCP\AppFramework\OCS\OCSBadRequestException; use OCP\AppFramework\OCS\OCSForbiddenException; use OCP\AppFramework\OCSController; @@ -47,6 +53,7 @@ class UserThemeController extends OCSController { private IConfig $config; private IUserSession $userSession; private ThemesService $themesService; + private BackgroundService $backgroundService; /** * Config constructor. @@ -55,11 +62,13 @@ class UserThemeController extends OCSController { IRequest $request, IConfig $config, IUserSession $userSession, - ThemesService $themesService) { + ThemesService $themesService, + BackgroundService $backgroundService) { parent::__construct($appName, $request); $this->config = $config; $this->userSession = $userSession; $this->themesService = $themesService; + $this->backgroundService = $backgroundService; $this->userId = $userSession->getUser()->getUID(); } @@ -91,7 +100,7 @@ class UserThemeController extends OCSController { */ public function disableTheme(string $themeId): DataResponse { $theme = $this->validateTheme($themeId); - + // Enable selected theme $this->themesService->disableTheme($theme); return new DataResponse(); @@ -124,4 +133,54 @@ class UserThemeController extends OCSController { return $themes[$themeId]; } + + /** + * @NoAdminRequired + * @NoCSRFRequired + */ + public function getBackground(): Http\Response { + $file = $this->backgroundService->getBackground(); + if ($file !== null) { + $response = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => $file->getMimeType()]); + $response->cacheFor(24 * 60 * 60, false, true); + return $response; + } + return new NotFoundResponse(); + } + + /** + * @NoAdminRequired + */ + public function setBackground(string $type = 'default', string $value = ''): JSONResponse { + $currentVersion = (int)$this->config->getUserValue($this->userId, Application::APP_ID, '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); + } catch (\Throwable $e) { + return new JSONResponse(['error' => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR); + } + $currentVersion++; + $this->config->setUserValue($this->userId, Application::APP_ID, 'backgroundVersion', (string)$currentVersion); + return new JSONResponse([ + 'type' => $type, + 'value' => $value, + 'version' => $this->config->getUserValue($this->userId, Application::APP_ID, 'backgroundVersion', $currentVersion) + ]); + } } diff --git a/apps/theming/lib/Listener/BeforeTemplateRenderedListener.php b/apps/theming/lib/Listener/BeforeTemplateRenderedListener.php index 185289f6ff8..d6e00b927ae 100644 --- a/apps/theming/lib/Listener/BeforeTemplateRenderedListener.php +++ b/apps/theming/lib/Listener/BeforeTemplateRenderedListener.php @@ -26,40 +26,72 @@ declare(strict_types=1); namespace OCA\Theming\Listener; use OCA\Theming\AppInfo\Application; +use OCA\Theming\Service\BackgroundService; use OCA\Theming\Service\JSDataService; use OCA\Theming\Service\ThemeInjectionService; -use OCA\Theming\Service\ThemesService; +use OCP\AppFramework\Services\IInitialState; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use OCP\IConfig; -use OCP\IInitialStateService; -use OCP\IServerContainer; -use OCP\IURLGenerator; +use OCP\IUserSession; +use Psr\Container\ContainerInterface; class BeforeTemplateRenderedListener implements IEventListener { - private IInitialStateService $initialStateService; - private IServerContainer $serverContainer; + private IInitialState $initialState; + private ContainerInterface $container; private ThemeInjectionService $themeInjectionService; + private IUserSession $userSession; + private IConfig $config; public function __construct( - IInitialStateService $initialStateService, - IServerContainer $serverContainer, - ThemeInjectionService $themeInjectionService + IInitialState $initialState, + ContainerInterface $container, + ThemeInjectionService $themeInjectionService, + IUserSession $userSession, + IConfig $config ) { - $this->initialStateService = $initialStateService; - $this->serverContainer = $serverContainer; + $this->initialState = $initialState; + $this->container = $container; $this->themeInjectionService = $themeInjectionService; + $this->userSession = $userSession; + $this->config = $config; } public function handle(Event $event): void { - $serverContainer = $this->serverContainer; - $this->initialStateService->provideLazyInitialState(Application::APP_ID, 'data', function () use ($serverContainer) { - return $serverContainer->query(JSDataService::class); - }); + $this->initialState->provideLazyInitialState( + 'data', + fn () => $this->container->get(JSDataService::class), + ); $this->themeInjectionService->injectHeaders(); + $user = $this->userSession->getUser(); + + if (!empty($user)) { + $userId = $user->getUID(); + + $this->initialState->provideInitialState( + 'background', + $this->config->getUserValue($userId, Application::APP_ID, 'background', 'default'), + ); + + $this->initialState->provideInitialState( + 'backgroundVersion', + $this->config->getUserValue($userId, Application::APP_ID, 'backgroundVersion', 0), + ); + + $this->initialState->provideInitialState( + 'themingDefaultBackground', + $this->config->getAppValue('theming', 'backgroundMime', ''), + ); + + $this->initialState->provideInitialState( + 'shippedBackgrounds', + BackgroundService::SHIPPED_BACKGROUNDS, + ); + } + // Making sure to inject just after core \OCP\Util::addScript('theming', 'theming', 'core'); } diff --git a/apps/dashboard/lib/Service/BackgroundService.php b/apps/theming/lib/Service/BackgroundService.php index c98b92412cb..2223c1d2d0a 100644 --- a/apps/dashboard/lib/Service/BackgroundService.php +++ b/apps/theming/lib/Service/BackgroundService.php @@ -7,6 +7,7 @@ declare(strict_types=1); * * @author Jan C. Borchardt <hey@jancborchardt.net> * @author Julius Härtl <jus@bitgrid.net> + * @author Christopher Ng <chrng8@gmail.com> * * @license GNU AGPL version 3 or any later version * @@ -24,10 +25,11 @@ declare(strict_types=1); * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ -namespace OCA\Dashboard\Service; +namespace OCA\Theming\Service; use InvalidArgumentException; use OC\User\NoUserException; +use OCA\Theming\AppInfo\Application; use OCP\Files\File; use OCP\Files\IAppData; use OCP\Files\IRootFolder; @@ -109,21 +111,18 @@ class BackgroundService { 'theming' => self::THEMING_MODE_DARK, ] ]; - /** - * @var IRootFolder - */ - private $rootFolder; - /** - * @var IAppData - */ - private $appData; - /** - * @var IConfig - */ - private $config; - private $userId; - public function __construct(IRootFolder $rootFolder, IAppData $appData, IConfig $config, $userId) { + private IRootFolder $rootFolder; + private IAppData $appData; + private IConfig $config; + private string $userId; + + public function __construct( + IRootFolder $rootFolder, + IAppData $appData, + IConfig $config, + ?string $userId + ) { if ($userId === null) { return; } @@ -134,7 +133,7 @@ class BackgroundService { } public function setDefaultBackground(): void { - $this->config->deleteUserValue($this->userId, 'dashboard', 'background'); + $this->config->deleteUserValue($this->userId, Application::APP_ID, 'background'); } /** @@ -146,7 +145,7 @@ class BackgroundService { * @throws NoUserException */ public function setFileBackground($path): void { - $this->config->setUserValue($this->userId, 'dashboard', 'background', 'custom'); + $this->config->setUserValue($this->userId, Application::APP_ID, 'background', 'custom'); $userFolder = $this->rootFolder->getUserFolder($this->userId); /** @var File $file */ $file = $userFolder->get($path); @@ -161,18 +160,18 @@ class BackgroundService { if (!array_key_exists($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, Application::APP_ID, 'background', $fileName); } public function setColorBackground(string $color): void { if (!preg_match('/^#([0-9a-f]{3}|[0-9a-f]{6})$/i', $color)) { throw new InvalidArgumentException('The given color is invalid'); } - $this->config->setUserValue($this->userId, 'dashboard', 'background', $color); + $this->config->setUserValue($this->userId, Application::APP_ID, 'background', $color); } public function getBackground(): ?ISimpleFile { - $background = $this->config->getUserValue($this->userId, 'dashboard', 'background', 'default'); + $background = $this->config->getUserValue($this->userId, Application::APP_ID, 'background', 'default'); if ($background === 'custom') { try { return $this->getAppDataFolder()->getFile('background.jpg'); diff --git a/apps/theming/lib/Settings/Personal.php b/apps/theming/lib/Settings/Personal.php index 790c0fd7f39..5da72bf0158 100644 --- a/apps/theming/lib/Settings/Personal.php +++ b/apps/theming/lib/Settings/Personal.php @@ -30,7 +30,6 @@ use OCA\Theming\Service\ThemesService; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Services\IInitialState; use OCP\IConfig; -use OCP\IUserSession; use OCP\Settings\ISettings; use OCP\Util; @@ -38,18 +37,15 @@ class Personal implements ISettings { protected string $appName; private IConfig $config; - private IUserSession $userSession; private ThemesService $themesService; private IInitialState $initialStateService; public function __construct(string $appName, IConfig $config, - IUserSession $userSession, ThemesService $themesService, IInitialState $initialStateService) { $this->appName = $appName; $this->config = $config; - $this->userSession = $userSession; $this->themesService = $themesService; $this->initialStateService = $initialStateService; } diff --git a/apps/theming/lib/Themes/DefaultTheme.php b/apps/theming/lib/Themes/DefaultTheme.php index 986892a6b6c..0fe1e8ff691 100644 --- a/apps/theming/lib/Themes/DefaultTheme.php +++ b/apps/theming/lib/Themes/DefaultTheme.php @@ -24,10 +24,11 @@ declare(strict_types=1); */ namespace OCA\Theming\Themes; +use OCA\Theming\AppInfo\Application; use OCA\Theming\ImageManager; +use OCA\Theming\ITheme; use OCA\Theming\ThemingDefaults; use OCA\Theming\Util; -use OCA\Theming\ITheme; use OCP\App\IAppManager; use OCP\IConfig; use OCP\IL10N; @@ -98,7 +99,7 @@ class DefaultTheme implements ITheme { $colorPrimaryElementLight = $this->util->mix($colorPrimaryElement, $colorMainBackground, -80); $hasCustomLogoHeader = $this->imageManager->hasImage('logo') || $this->imageManager->hasImage('logoheader'); - $hasCustomPrimaryColour = !empty($this->config->getAppValue('theming', 'color')); + $hasCustomPrimaryColour = !empty($this->config->getAppValue(Application::APP_ID, 'color')); $variables = [ '--color-main-background' => $colorMainBackground, @@ -210,7 +211,7 @@ class DefaultTheme implements ITheme { '--image-main-background' => "url('" . $this->urlGenerator->imagePath('core', 'app-background.jpg') . "')", ]; - $backgroundDeleted = $this->config->getAppValue('theming', 'backgroundMime', '') === 'backgroundColor'; + $backgroundDeleted = $this->config->getAppValue(Application::APP_ID, 'backgroundMime', '') === 'backgroundColor'; // If primary as background has been request or if we have a custom primary colour // let's not define the background image if ($backgroundDeleted || $hasCustomPrimaryColour) { @@ -240,13 +241,13 @@ class DefaultTheme implements ITheme { $appManager = Server::get(IAppManager::class); $userSession = Server::get(IUserSession::class); $user = $userSession->getUser(); - if ($appManager->isEnabledForUser('dashboard') && $user !== null) { - $dashboardBackground = $this->config->getUserValue($user->getUID(), 'dashboard', 'background', 'default'); + if ($appManager->isEnabledForUser(Application::APP_ID) && $user !== null) { + $themingBackground = $this->config->getUserValue($user->getUID(), Application::APP_ID, 'background', 'default'); - if ($dashboardBackground === 'custom') { - $variables['--image-main-background'] = "url('" . $this->urlGenerator->linkToRouteAbsolute('dashboard.dashboard.getBackground') . "')"; - } elseif ($dashboardBackground !== 'default' && substr($dashboardBackground, 0, 1) !== '#') { - $variables['--image-main-background'] = "url('/apps/dashboard/img/" . $dashboardBackground . "')"; + if ($themingBackground === 'custom') { + $variables['--image-main-background'] = "url('" . $this->urlGenerator->linkToRouteAbsolute('theming.theming.getBackground') . "')"; + } elseif ($themingBackground !== 'default' && substr($themingBackground, 0, 1) !== '#') { + $variables['--image-main-background'] = "url('" . $this->urlGenerator->linkTo(Application::APP_ID, "/img/background/$themingBackground") . "')"; } } diff --git a/apps/theming/src/UserThemes.vue b/apps/theming/src/UserThemes.vue index 8e7f1d54e37..c886394136a 100644 --- a/apps/theming/src/UserThemes.vue +++ b/apps/theming/src/UserThemes.vue @@ -1,42 +1,83 @@ +<!-- + - @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net> + - @copyright Copyright (c) 2022 Greta Doci <gretadoci@gmail.com> + - + - @author Christopher Ng <chrng8@gmail.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/>. + - +--> + <template> - <NcSettingsSection class="theming" :title="t('themes', 'Appearance and accessibility')"> - <p v-html="description" /> - <p v-html="descriptionDetail" /> - - <div class="theming__preview-list"> - <ItemPreview v-for="theme in themes" - :key="theme.id" - :enforced="theme.id === enforceTheme" - :selected="selectedTheme.id === theme.id" - :theme="theme" - :unique="themes.length === 1" - type="theme" - @change="changeTheme" /> - </div> - - <div class="theming__preview-list"> - <ItemPreview v-for="theme in fonts" - :key="theme.id" - :selected="theme.enabled" - :theme="theme" - :unique="fonts.length === 1" - type="font" - @change="changeFont" /> - </div> - </NcSettingsSection> + <section> + <NcSettingsSection class="theming" :title="t('theming', 'Appearance and accessibility')"> + <p v-html="description" /> + <p v-html="descriptionDetail" /> + + <div class="theming__preview-list"> + <ItemPreview v-for="theme in themes" + :key="theme.id" + :enforced="theme.id === enforceTheme" + :selected="selectedTheme.id === theme.id" + :theme="theme" + :unique="themes.length === 1" + type="theme" + @change="changeTheme" /> + </div> + + <div class="theming__preview-list"> + <ItemPreview v-for="theme in fonts" + :key="theme.id" + :selected="theme.enabled" + :theme="theme" + :unique="fonts.length === 1" + type="font" + @change="changeFont" /> + </div> + </NcSettingsSection> + <NcSettingsSection :title="t('theming', 'Background')" + class="background"> + <p>{{ t('theming', 'Set a custom background') }}</p> + <BackgroundSettings class="background__grid" + :background="background" + :theming-default-background="themingDefaultBackground" + @update:background="updateBackground" /> + </NcSettingsSection> + </section> </template> <script> -import { generateOcsUrl } from '@nextcloud/router' +import { generateOcsUrl, imagePath } from '@nextcloud/router' import { loadState } from '@nextcloud/initial-state' import axios from '@nextcloud/axios' import NcSettingsSection from '@nextcloud/vue/dist/Components/NcSettingsSection' -import ItemPreview from './components/ItemPreview' +import BackgroundSettings from './components/BackgroundSettings.vue' +import ItemPreview from './components/ItemPreview.vue' + +import { getBackgroundUrl } from '../src/helpers/getBackgroundUrl.js' const availableThemes = loadState('theming', 'themes', []) const enforceTheme = loadState('theming', 'enforceTheme', '') +const background = loadState('theming', 'background') +const backgroundVersion = loadState('theming', 'backgroundVersion') +const themingDefaultBackground = loadState('theming', 'themingDefaultBackground') +const shippedBackgroundList = loadState('theming', 'shippedBackgrounds') + console.debug('Available themes', availableThemes) export default { @@ -44,16 +85,32 @@ export default { components: { ItemPreview, NcSettingsSection, + BackgroundSettings, }, data() { return { availableThemes, enforceTheme, + background, + themingDefaultBackground, } }, computed: { + backgroundImage() { + return getBackgroundUrl(this.background, backgroundVersion, this.themingDefaultBackground) + }, + backgroundStyle() { + if ((this.background === 'default' && this.themingDefaultBackground === 'backgroundColor') + || this.background.match(/#[0-9A-Fa-f]{6}/g)) { + return null + } + + return { + backgroundImage: this.background === 'default' ? 'var(--image-main-background)' : `url('${this.backgroundImage}')`, + } + }, themes() { return this.availableThemes.filter(theme => theme.type === 1) }, @@ -94,7 +151,40 @@ export default { return '<a target="_blank" href="https://nextcloud.com/design" rel="noreferrer nofollow">' }, }, + mounted() { + this.updateGlobalStyles() + }, methods: { + updateBackground(data) { + this.background = (data.type === 'custom' || data.type === 'default') ? data.type : data.value + this.updateGlobalStyles() + }, + updateGlobalStyles() { + // Override primary-invert-if-bright and color-primary-text if background is set + const isBackgroundBright = shippedBackgroundList[this.background]?.theming === 'dark' + if (isBackgroundBright) { + document.querySelector('#header').style.setProperty('--primary-invert-if-bright', 'invert(100%)') + document.querySelector('#header').style.setProperty('--color-primary-text', '#000000') + // document.body.removeAttribute('data-theme-dark') + // document.body.setAttribute('data-theme-light', 'true') + } else { + document.querySelector('#header').style.setProperty('--primary-invert-if-bright', 'no') + document.querySelector('#header').style.setProperty('--color-primary-text', '#ffffff') + // document.body.removeAttribute('data-theme-light') + // document.body.setAttribute('data-theme-dark', 'true') + } + + const themeElements = [document.documentElement, document.querySelector('#header'), document.querySelector('body')] + for (const element of themeElements) { + if (this.background === 'default') { + element.style.setProperty('--image-main-background', `url('${imagePath('core', 'app-background.jpg')}')`) + } else if (this.background.match(/#[0-9A-Fa-f]{6}/g)) { + element.style.setProperty('--image-main-background', undefined) + } else { + element.style.setProperty('--image-main-background', this.backgroundStyle.backgroundImage) + } + } + }, changeTheme({ enabled, id }) { // Reset selected and select new one this.themes.forEach(theme => { @@ -194,11 +284,16 @@ export default { } } +.background { + &__grid { + margin-top: 30px; + } +} + @media (max-width: 1440px) { .theming__preview-list { display: flex; flex-direction: column; } } - </style> diff --git a/apps/dashboard/src/components/BackgroundSettings.vue b/apps/theming/src/components/BackgroundSettings.vue index 101ecaaa742..3de68d5abed 100644 --- a/apps/dashboard/src/components/BackgroundSettings.vue +++ b/apps/theming/src/components/BackgroundSettings.vue @@ -1,7 +1,10 @@ <!-- - @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net> + - @copyright Copyright (c) 2022 Greta Doci <gretadoci@gmail.com> - - @author Julius Härtl <jus@bitgrid.net> + - @author Greta Doci <gretadoci@gmail.com> + - @author Christopher Ng <chrng8@gmail.com> - - @license GNU AGPL version 3 or any later version - @@ -26,19 +29,19 @@ :class="{ active: background === 'custom' }" tabindex="0" @click="pickFile"> - {{ t('dashboard', 'Pick from Files') }} + {{ t('theming', 'Pick from Files') }} </button> <button class="background default" tabindex="0" :class="{ 'icon-loading': loading === 'default', active: background === 'default' }" @click="setDefault"> - {{ t('dashboard', 'Default image') }} + {{ t('theming', 'Default image') }} </button> <button class="background color" :class="{ active: background === 'custom' }" tabindex="0" @click="pickColor"> - {{ t('dashboard', 'Plain background') }} + {{ t('theming', 'Plain background') }} </button> <button v-for="shippedBackground in shippedBackgrounds" :key="shippedBackground.name" @@ -53,14 +56,19 @@ <script> import axios from '@nextcloud/axios' +import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip' import { generateUrl } from '@nextcloud/router' import { loadState } from '@nextcloud/initial-state' -import getBackgroundUrl from './../helpers/getBackgroundUrl' -import prefixWithBaseUrl from './../helpers/prefixWithBaseUrl' -const shippedBackgroundList = loadState('dashboard', 'shippedBackgrounds') +import { getBackgroundUrl } from '../helpers/getBackgroundUrl.js' +import { prefixWithBaseUrl } from '../helpers/prefixWithBaseUrl.js' + +const shippedBackgroundList = loadState('theming', 'shippedBackgrounds') export default { name: 'BackgroundSettings', + directives: { + Tooltip, + }, props: { background: { type: String, @@ -73,18 +81,18 @@ export default { }, data() { return { - backgroundImage: generateUrl('/apps/dashboard/background') + '?v=' + Date.now(), + backgroundImage: generateUrl('/apps/theming/background') + '?v=' + Date.now(), loading: false, } }, computed: { shippedBackgrounds() { - return Object.keys(shippedBackgroundList).map((item) => { + return Object.keys(shippedBackgroundList).map(fileName => { return { - name: item, - url: prefixWithBaseUrl(item), - preview: prefixWithBaseUrl('previews/' + item), - details: shippedBackgroundList[item], + name: fileName, + url: prefixWithBaseUrl(fileName), + preview: prefixWithBaseUrl('preview/' + fileName), + details: shippedBackgroundList[fileName], } }) }, @@ -107,27 +115,27 @@ export default { }, async setDefault() { this.loading = 'default' - const result = await axios.post(generateUrl('/apps/dashboard/background/default')) + const result = await axios.post(generateUrl('/apps/theming/background/default')) this.update(result.data) }, async setShipped(shipped) { this.loading = shipped - const result = await axios.post(generateUrl('/apps/dashboard/background/shipped'), { value: shipped }) + const result = await axios.post(generateUrl('/apps/theming/background/shipped'), { value: shipped }) this.update(result.data) }, async setFile(path) { this.loading = 'custom' - const result = await axios.post(generateUrl('/apps/dashboard/background/custom'), { value: path }) + const result = await axios.post(generateUrl('/apps/theming/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 }) + const result = await axios.post(generateUrl('/apps/theming/background/color'), { value: color }) this.update(result.data) }, pickFile() { - window.OC.dialogs.filepicker(t('dashboard', 'Insert from {productName}', { productName: OC.theme.name }), (path, type) => { + window.OC.dialogs.filepicker(t('theming', 'Insert from {productName}', { productName: OC.theme.name }), (path, type) => { if (type === OC.dialogs.FILEPICKER_TYPE_CHOOSE) { this.setFile(path) } diff --git a/apps/theming/src/helpers/getBackgroundUrl.js b/apps/theming/src/helpers/getBackgroundUrl.js new file mode 100644 index 00000000000..2e0088f6d30 --- /dev/null +++ b/apps/theming/src/helpers/getBackgroundUrl.js @@ -0,0 +1,51 @@ +/** + * @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net> + * + * @author Avior <florian.bouillon@delta-wings.net> + * @author Julien Veyssier <eneiluj@posteo.net> + * @author Julius Härtl <jus@bitgrid.net> + * + * @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/>. + * + */ + +// FIXME hoist this into a package? The same logic is used in `apps/dashboard/src/helpers/getBackgroundUrl.js` + +import { generateUrl } from '@nextcloud/router' +import { prefixWithBaseUrl } from './prefixWithBaseUrl.js' + +export const getBackgroundUrl = (background, time = 0, themingDefaultBackground = '') => { + const enabledThemes = window.OCA?.Theming?.enabledThemes || [] + const isDarkTheme = (enabledThemes.length === 0 || enabledThemes[0] === 'default') + ? window.matchMedia('(prefers-color-scheme: dark)').matches + : enabledThemes.join('').indexOf('dark') !== -1 + + if (background === 'default') { + if (themingDefaultBackground && themingDefaultBackground !== 'backgroundColor') { + return generateUrl('/apps/theming/image/background') + '?v=' + window.OCA.Theming.cacheBuster + } + + if (isDarkTheme) { + return prefixWithBaseUrl('eduardo-neves-pedra-azul.jpg') + } + + return prefixWithBaseUrl('kamil-porembinski-clouds.jpg') + } else if (background === 'custom') { + return generateUrl('/apps/theming/background') + '?v=' + time + } + + return prefixWithBaseUrl(background) +} diff --git a/apps/theming/src/helpers/prefixWithBaseUrl.js b/apps/theming/src/helpers/prefixWithBaseUrl.js new file mode 100644 index 00000000000..07e4986593c --- /dev/null +++ b/apps/theming/src/helpers/prefixWithBaseUrl.js @@ -0,0 +1,27 @@ +/** + * @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net> + * + * @author Julius Härtl <jus@bitgrid.net> + * + * @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/>. + * + */ + +// FIXME hoist this into a package? The same logic is used in `apps/dashboard/src/helpers/prefixWithBaseUrl.js` + +import { generateFilePath } from '@nextcloud/router' + +export const prefixWithBaseUrl = (url) => generateFilePath('theming', '', 'img/background/') + url diff --git a/apps/theming/tests/Controller/UserThemeControllerTest.php b/apps/theming/tests/Controller/UserThemeControllerTest.php index 952cd012210..ffacf5108a5 100644 --- a/apps/theming/tests/Controller/UserThemeControllerTest.php +++ b/apps/theming/tests/Controller/UserThemeControllerTest.php @@ -22,8 +22,10 @@ */ namespace OCA\Theming\Tests\Controller; +use OCA\Theming\AppInfo\Application; use OCA\Theming\Controller\UserThemeController; use OCA\Theming\ITheme; +use OCA\Theming\Service\BackgroundService; use OCA\Theming\Themes\DarkHighContrastTheme; use OCA\Theming\Themes\DarkTheme; use OCA\Theming\Themes\DefaultTheme; @@ -52,6 +54,9 @@ class UserThemeControllerTest extends TestCase { private $userSession; /** @var ThemeService|MockObject */ private $themesService; + /** @var BackgroundService|MockObject */ + private $backgroundService; + /** @var ITheme[] */ private $themes; @@ -61,6 +66,7 @@ class UserThemeControllerTest extends TestCase { $this->config = $this->createMock(IConfig::class); $this->userSession = $this->createMock(IUserSession::class); $this->themesService = $this->createMock(ThemesService::class); + $this->backgroundService = $this->createMock(BackgroundService::class); $this->themes = [ 'default' => $this->createMock(DefaultTheme::class), @@ -80,11 +86,12 @@ class UserThemeControllerTest extends TestCase { ->willReturn('user'); $this->userThemeController = new UserThemeController( - 'theming', + Application::APP_ID, $this->request, $this->config, $this->userSession, $this->themesService, + $this->backgroundService, ); parent::setUp(); diff --git a/apps/theming/tests/Settings/PersonalTest.php b/apps/theming/tests/Settings/PersonalTest.php index a5409e5f57a..3051a210353 100644 --- a/apps/theming/tests/Settings/PersonalTest.php +++ b/apps/theming/tests/Settings/PersonalTest.php @@ -45,12 +45,10 @@ use OCP\AppFramework\Services\IInitialState; use OCP\IConfig; use OCP\IL10N; use OCP\IURLGenerator; -use OCP\IUserSession; use Test\TestCase; class PersonalTest extends TestCase { private IConfig $config; - private IUserSession $userSession; private ThemesService $themesService; private IInitialState $initialStateService; @@ -60,7 +58,6 @@ class PersonalTest extends TestCase { protected function setUp(): void { parent::setUp(); $this->config = $this->createMock(IConfig::class); - $this->userSession = $this->createMock(IUserSession::class); $this->themesService = $this->createMock(ThemesService::class); $this->initialStateService = $this->createMock(IInitialState::class); @@ -74,7 +71,6 @@ class PersonalTest extends TestCase { $this->admin = new Personal( Application::APP_ID, $this->config, - $this->userSession, $this->themesService, $this->initialStateService ); |