Skip to content

Commit faee255

Browse files
authored
Merge pull request #840 from nextcloud/theming-icon-endpoint
Add dynamic icon creation
2 parents e851166 + 2ab4d1e commit faee255

22 files changed

+1350
-6
lines changed

apps/theming/appinfo/routes.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,23 @@
6060
'url' => '/js/theming',
6161
'verb' => 'GET',
6262
],
63+
[
64+
'name' => 'Icon#getFavicon',
65+
'url' => '/favicon/{app}',
66+
'verb' => 'GET',
67+
'defaults' => array('app' => 'core'),
68+
],
69+
[
70+
'name' => 'Icon#getTouchIcon',
71+
'url' => '/icon/{app}',
72+
'verb' => 'GET',
73+
'defaults' => array('app' => 'core'),
74+
],
75+
[
76+
'name' => 'Icon#getThemedIcon',
77+
'url' => '/img/{app}/{image}',
78+
'verb' => 'GET',
79+
'requirements' => array('image' => '.+')
80+
],
6381
]];
6482

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
<?php
2+
/**
3+
* @copyright Copyright (c) 2016 Julius Haertl <jus@bitgrid.net>
4+
*
5+
* @author Julius Haertl <jus@bitgrid.net>
6+
*
7+
* @license GNU AGPL version 3 or any later version
8+
*
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Affero General Public License as
11+
* published by the Free Software Foundation, either version 3 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Affero General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Affero General Public License
20+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
*
22+
*/
23+
namespace OCA\Theming\Controller;
24+
25+
use OCA\Theming\IconBuilder;
26+
use OCA\Theming\ImageManager;
27+
use OCA\Theming\ThemingDefaults;
28+
use OCP\AppFramework\Controller;
29+
use OCP\AppFramework\Http;
30+
use OCP\AppFramework\Http\NotFoundResponse;
31+
use OCP\AppFramework\Http\FileDisplayResponse;
32+
use OCP\AppFramework\Utility\ITimeFactory;
33+
use OCP\Files\NotFoundException;
34+
use OCP\IRequest;
35+
use OCA\Theming\Util;
36+
use OCP\IConfig;
37+
38+
class IconController extends Controller {
39+
/** @var ThemingDefaults */
40+
private $themingDefaults;
41+
/** @var Util */
42+
private $util;
43+
/** @var ITimeFactory */
44+
private $timeFactory;
45+
/** @var IConfig */
46+
private $config;
47+
/** @var IconBuilder */
48+
private $iconBuilder;
49+
/** @var ImageManager */
50+
private $imageManager;
51+
52+
/**
53+
* IconController constructor.
54+
*
55+
* @param string $appName
56+
* @param IRequest $request
57+
* @param ThemingDefaults $themingDefaults
58+
* @param Util $util
59+
* @param ITimeFactory $timeFactory
60+
* @param IConfig $config
61+
* @param IconBuilder $iconBuilder
62+
* @param ImageManager $imageManager
63+
*/
64+
public function __construct(
65+
$appName,
66+
IRequest $request,
67+
ThemingDefaults $themingDefaults,
68+
Util $util,
69+
ITimeFactory $timeFactory,
70+
IConfig $config,
71+
IconBuilder $iconBuilder,
72+
ImageManager $imageManager
73+
) {
74+
parent::__construct($appName, $request);
75+
76+
$this->themingDefaults = $themingDefaults;
77+
$this->util = $util;
78+
$this->timeFactory = $timeFactory;
79+
$this->config = $config;
80+
$this->iconBuilder = $iconBuilder;
81+
$this->imageManager = $imageManager;
82+
}
83+
84+
/**
85+
* @PublicPage
86+
* @NoCSRFRequired
87+
*
88+
* @param $app string app name
89+
* @param $image string image file name (svg required)
90+
* @return FileDisplayResponse|NotFoundResponse
91+
*/
92+
public function getThemedIcon($app, $image) {
93+
try {
94+
$iconFile = $this->imageManager->getCachedImage("icon-" . $app . '-' . str_replace("/","_",$image));
95+
} catch (NotFoundException $exception) {
96+
$icon = $this->iconBuilder->colorSvg($app, $image);
97+
$iconFile = $this->imageManager->setCachedImage("icon-" . $app . '-' . str_replace("/","_",$image), $icon);
98+
}
99+
if ($iconFile !== false) {
100+
$response = new FileDisplayResponse($iconFile, Http::STATUS_OK, ['Content-Type' => 'image/svg+xml']);
101+
$response->cacheFor(86400);
102+
$expires = new \DateTime();
103+
$expires->setTimestamp($this->timeFactory->getTime());
104+
$expires->add(new \DateInterval('PT24H'));
105+
$response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
106+
$response->addHeader('Pragma', 'cache');
107+
return $response;
108+
} else {
109+
return new NotFoundResponse();
110+
}
111+
}
112+
113+
/**
114+
* Return a 32x32 favicon as png
115+
*
116+
* @PublicPage
117+
* @NoCSRFRequired
118+
*
119+
* @param $app string app name
120+
* @return FileDisplayResponse|NotFoundResponse
121+
*/
122+
public function getFavicon($app = "core") {
123+
if ($this->themingDefaults->shouldReplaceIcons()) {
124+
try {
125+
$iconFile = $this->imageManager->getCachedImage('favIcon-' . $app);
126+
} catch (NotFoundException $exception) {
127+
$icon = $this->iconBuilder->getFavicon($app);
128+
$iconFile = $this->imageManager->setCachedImage('favIcon-' . $app, $icon);
129+
}
130+
if ($iconFile !== false) {
131+
$response = new FileDisplayResponse($iconFile, Http::STATUS_OK, ['Content-Type' => 'image/x-icon']);
132+
$response->cacheFor(86400);
133+
$expires = new \DateTime();
134+
$expires->setTimestamp($this->timeFactory->getTime());
135+
$expires->add(new \DateInterval('PT24H'));
136+
$response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
137+
$response->addHeader('Pragma', 'cache');
138+
return $response;
139+
}
140+
}
141+
return new NotFoundResponse();
142+
}
143+
144+
/**
145+
* Return a 512x512 icon for touch devices
146+
*
147+
* @PublicPage
148+
* @NoCSRFRequired
149+
*
150+
* @param $app string app name
151+
* @return FileDisplayResponse|NotFoundResponse
152+
*/
153+
public function getTouchIcon($app = "core") {
154+
if ($this->themingDefaults->shouldReplaceIcons()) {
155+
try {
156+
$iconFile = $this->imageManager->getCachedImage('touchIcon-' . $app);
157+
} catch (NotFoundException $exception) {
158+
$icon = $this->iconBuilder->getTouchIcon($app);
159+
$iconFile = $this->imageManager->setCachedImage('touchIcon-' . $app, $icon);
160+
}
161+
if ($iconFile !== false) {
162+
$response = new FileDisplayResponse($iconFile, Http::STATUS_OK, ['Content-Type' => 'image/png']);
163+
$response->cacheFor(86400);
164+
$expires = new \DateTime();
165+
$expires->setTimestamp($this->timeFactory->getTime());
166+
$expires->add(new \DateInterval('PT24H'));
167+
$response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
168+
$response->addHeader('Pragma', 'cache');
169+
return $response;
170+
}
171+
}
172+
return new NotFoundResponse();
173+
}
174+
}

apps/theming/lib/Controller/ThemingController.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,15 @@ public function getStylesheet() {
410410
$responseCss .= '.nc-theming-contrast {color: #ffffff}' . "\n";
411411
}
412412

413+
if($logo !== '' or $color !== '') {
414+
$responseCss .= '.icon-file,.icon-filetype-text {' .
415+
'background-image: url(\'./img/core/filetypes/text.svg?v='.$cacheBusterValue.'\');' . "}\n" .
416+
'.icon-folder, .icon-filetype-folder {' .
417+
'background-image: url(\'./img/core/filetypes/folder.svg?v='.$cacheBusterValue.'\');' . "}\n" .
418+
'.icon-filetype-folder-drag-accept {' .
419+
'background-image: url(\'./img/core/filetypes/folder-drag-accept.svg?v='.$cacheBusterValue.'\')!important;' . "}\n";
420+
}
421+
413422
$response = new DataDownloadResponse($responseCss, 'style', 'text/css');
414423
$response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime()));
415424
$response->addHeader('Pragma', 'cache');
@@ -423,13 +432,15 @@ public function getStylesheet() {
423432
* @return DataDownloadResponse
424433
*/
425434
public function getJavascript() {
435+
$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
426436
$responseJS = '(function() {
427437
OCA.Theming = {
428438
name: ' . json_encode($this->template->getName()) . ',
429439
url: ' . json_encode($this->template->getBaseUrl()) . ',
430440
slogan: ' . json_encode($this->template->getSlogan()) . ',
431441
color: ' . json_encode($this->template->getMailHeaderColor()) . ',
432442
inverted: ' . json_encode($this->util->invertTextColor($this->template->getMailHeaderColor())) . ',
443+
cacheBuster: ' . json_encode($cacheBusterValue). '
433444
};
434445
})();';
435446
$response = new Http\DataDisplayResponse($responseJS);

0 commit comments

Comments
 (0)