Move background settings from dashboard app to Appearance and accessibility settings
Signed-off-by: greta <gretadoci@gmail.com> Signed-off-by: Christopher Ng <chrng8@gmail.com>
|
|
@ -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'],
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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' => [
|
||||
[
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1 MiB After Width: | Height: | Size: 1 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 249 KiB After Width: | Height: | Size: 249 KiB |
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 523 KiB After Width: | Height: | Size: 523 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1 MiB After Width: | Height: | Size: 1 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 934 KiB After Width: | Height: | Size: 934 KiB |
|
Before Width: | Height: | Size: 279 KiB After Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 454 KiB After Width: | Height: | Size: 454 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 239 KiB After Width: | Height: | Size: 239 KiB |
|
|
@ -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)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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") . "')";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
<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 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>
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
51
apps/theming/src/helpers/getBackgroundUrl.js
Normal file
|
|
@ -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)
|
||||
}
|
||||
27
apps/theming/src/helpers/prefixWithBaseUrl.js
Normal file
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
|
|
|
|||