]> git.mxchange.org Git - friendica.git/blob - src/Module/Settings/Display.php
Add icon placeholder for images in image grid
[friendica.git] / src / Module / Settings / Display.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2023, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Module\Settings;
23
24 use Friendica\App;
25 use Friendica\Content\Text\BBCode;
26 use Friendica\Content\Conversation\Factory\Timeline as TimelineFactory;
27 use Friendica\Core\Config\Capability\IManageConfigValues;
28 use Friendica\Core\Hook;
29 use Friendica\Core\L10n;
30 use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
31 use Friendica\Core\Renderer;
32 use Friendica\Core\Session\Capability\IHandleUserSessions;
33 use Friendica\Core\Theme;
34 use Friendica\Model\User;
35 use Friendica\Module\BaseSettings;
36 use Friendica\Module\Response;
37 use Friendica\Navigation\SystemMessages;
38 use Friendica\Network\HTTPException;
39 use Friendica\Util\Profiler;
40 use Psr\Log\LoggerInterface;
41
42 /**
43  * Module to update user settings
44  */
45 class Display extends BaseSettings
46 {
47         /** @var IManageConfigValues */
48         private $config;
49         /** @var IManagePersonalConfigValues */
50         private $pConfig;
51         /** @var App */
52         private $app;
53         /** @var SystemMessages */
54         private $systemMessages;
55         /** @var TimelineFactory */
56         protected $timeline;
57
58         public function __construct(TimelineFactory $timeline, SystemMessages $systemMessages, App $app, IManagePersonalConfigValues $pConfig, IManageConfigValues $config, IHandleUserSessions $session, App\Page $page, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
59         {
60                 parent::__construct($session, $page, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
61
62                 $this->config         = $config;
63                 $this->pConfig        = $pConfig;
64                 $this->app            = $app;
65                 $this->systemMessages = $systemMessages;
66                 $this->timeline       = $timeline;
67         }
68
69         protected function post(array $request = [])
70         {
71                 $uid = $this->session->getLocalUserId();
72                 if (!$uid) {
73                         throw new HTTPException\ForbiddenException($this->t('Permission denied.'));
74                 }
75
76                 self::checkFormSecurityTokenRedirectOnError('/settings/display', 'settings_display');
77
78                 $user = User::getById($uid);
79
80                 $theme                  = !empty($request['theme'])                  ? trim($request['theme'])                    : $user['theme'];
81                 $mobile_theme           = !empty($request['mobile_theme'])           ? trim($request['mobile_theme'])             : '';
82                 $enable_smile           = !empty($request['enable_smile'])           ? intval($request['enable_smile'])           : 0;
83                 $network_timelines      = !empty($request['network_timelines'])      ? $request['network_timelines']              : [];
84                 $channel_languages      = !empty($request['channel_languages'])      ? $request['channel_languages']              : [];
85                 $first_day_of_week      = !empty($request['first_day_of_week'])      ? intval($request['first_day_of_week'])      : 0;
86                 $calendar_default_view  = !empty($request['calendar_default_view'])  ? trim($request['calendar_default_view'])    : 'month';
87                 $infinite_scroll        = !empty($request['infinite_scroll'])        ? intval($request['infinite_scroll'])        : 0;
88                 $enable_smart_threading = !empty($request['enable_smart_threading']) ? intval($request['enable_smart_threading']) : 0;
89                 $enable_dislike         = !empty($request['enable_dislike'])         ? intval($request['enable_dislike'])         : 0;
90                 $display_resharer       = !empty($request['display_resharer'])       ? intval($request['display_resharer'])       : 0;
91                 $stay_local             = !empty($request['stay_local'])             ? intval($request['stay_local'])             : 0;
92                 $preview_mode           = !empty($request['preview_mode'])           ? intval($request['preview_mode'])           : 0;
93                 $browser_update         = !empty($request['browser_update'])         ? intval($request['browser_update'])         : 0;
94                 if ($browser_update != -1) {
95                         $browser_update = $browser_update * 1000;
96                         if ($browser_update < 10000) {
97                                 $browser_update = 10000;
98                         }
99                 }
100
101                 $itemspage_network = !empty($request['itemspage_network']) ?
102                         intval($request['itemspage_network']) :
103                         $this->config->get('system', 'itemspage_network');
104                 if ($itemspage_network > 100) {
105                         $itemspage_network = 100;
106                 }
107                 $itemspage_mobile_network = !empty($request['itemspage_mobile_network']) ?
108                         intval($request['itemspage_mobile_network']) :
109                         $this->config->get('system', 'itemspage_network_mobile');
110                 if ($itemspage_mobile_network > 100) {
111                         $itemspage_mobile_network = 100;
112                 }
113
114                 if ($mobile_theme !== '') {
115                         $this->pConfig->set($uid, 'system', 'mobile_theme', $mobile_theme);
116                 }
117
118                 $this->pConfig->set($uid, 'system', 'itemspage_network'       , $itemspage_network);
119                 $this->pConfig->set($uid, 'system', 'itemspage_mobile_network', $itemspage_mobile_network);
120                 $this->pConfig->set($uid, 'system', 'update_interval'         , $browser_update);
121                 $this->pConfig->set($uid, 'system', 'no_smilies'              , !$enable_smile);
122                 $this->pConfig->set($uid, 'system', 'infinite_scroll'         , $infinite_scroll);
123                 $this->pConfig->set($uid, 'system', 'no_smart_threading'      , !$enable_smart_threading);
124                 $this->pConfig->set($uid, 'system', 'hide_dislike'            , !$enable_dislike);
125                 $this->pConfig->set($uid, 'system', 'display_resharer'        , $display_resharer);
126                 $this->pConfig->set($uid, 'system', 'stay_local'              , $stay_local);
127                 $this->pConfig->set($uid, 'system', 'preview_mode'            , $preview_mode);
128
129                 $this->pConfig->set($uid, 'system', 'network_timelines'       , $network_timelines);
130                 $this->pConfig->set($uid, 'channel', 'languages'              , $channel_languages);
131
132                 $this->pConfig->set($uid, 'calendar', 'first_day_of_week'     , $first_day_of_week);
133                 $this->pConfig->set($uid, 'calendar', 'default_view'          , $calendar_default_view);
134
135                 if (in_array($theme, Theme::getAllowedList())) {
136                         if ($theme == $user['theme']) {
137                                 // call theme_post only if theme has not been changed
138                                 if ($themeconfigfile = Theme::getConfigFile($theme)) {
139                                         require_once $themeconfigfile;
140                                         theme_post($this->app);
141                                 }
142                         } else {
143                                 User::update(['theme' => $theme], $uid);
144                         }
145                 } else {
146                         $this->systemMessages->addNotice($this->t('The theme you chose isn\'t available.'));
147                 }
148
149                 Hook::callAll('display_settings_post', $request);
150
151                 $this->baseUrl->redirect('settings/display');
152         }
153
154         protected function content(array $request = []): string
155         {
156                 parent::content();
157
158                 $uid = $this->session->getLocalUserId();
159                 if (!$uid) {
160                         throw new HTTPException\ForbiddenException($this->t('Permission denied.'));
161                 }
162
163                 $default_theme = $this->config->get('system', 'theme');
164                 if (!$default_theme) {
165                         $default_theme = 'default';
166                 }
167
168                 $default_mobile_theme = $this->config->get('system', 'mobile-theme');
169                 if (!$default_mobile_theme) {
170                         $default_mobile_theme = 'none';
171                 }
172
173                 $user = User::getById($uid);
174
175                 $allowed_themes = Theme::getAllowedList();
176
177                 $themes = [];
178                 $mobile_themes = ['---' => $this->t('No special theme for mobile devices')];
179                 foreach ($allowed_themes as $theme) {
180                         $is_experimental = file_exists('view/theme/' . $theme . '/experimental');
181                         $is_unsupported  = file_exists('view/theme/' . $theme . '/unsupported');
182                         $is_mobile       = file_exists('view/theme/' . $theme . '/mobile');
183                         if (!$is_experimental || $this->config->get('experimental', 'exp_themes')) {
184                                 $theme_name = ucfirst($theme);
185                                 if ($is_unsupported) {
186                                         $theme_name = $this->t('%s - (Unsupported)', $theme_name);
187                                 } elseif ($is_experimental) {
188                                         $theme_name = $this->t('%s - (Experimental)', $theme_name);
189                                 }
190
191                                 if ($is_mobile) {
192                                         $mobile_themes[$theme] = $theme_name;
193                                 } else {
194                                         $themes[$theme] = $theme_name;
195                                 }
196                         }
197                 }
198
199                 $theme_selected        = $user['theme'] ?: $default_theme;
200                 $mobile_theme_selected = $this->session->get('mobile-theme', $default_mobile_theme);
201
202                 $itemspage_network = intval($this->pConfig->get($uid, 'system', 'itemspage_network'));
203                 $itemspage_network = (($itemspage_network > 0 && $itemspage_network < 101) ? $itemspage_network : $this->config->get('system', 'itemspage_network'));
204                 $itemspage_mobile_network = intval($this->pConfig->get($uid, 'system', 'itemspage_mobile_network'));
205                 $itemspage_mobile_network = (($itemspage_mobile_network > 0 && $itemspage_mobile_network < 101) ? $itemspage_mobile_network : $this->config->get('system', 'itemspage_network_mobile'));
206
207                 $browser_update = intval($this->pConfig->get($uid, 'system', 'update_interval'));
208                 if ($browser_update != -1) {
209                         $browser_update = (($browser_update == 0) ? 40 : $browser_update / 1000); // default if not set: 40 seconds
210                 }
211
212                 $enable_smile           = !$this->pConfig->get($uid, 'system', 'no_smilies', 0);
213                 $infinite_scroll        =  $this->pConfig->get($uid, 'system', 'infinite_scroll', 0);
214                 $enable_smart_threading = !$this->pConfig->get($uid, 'system', 'no_smart_threading', 0);
215                 $enable_dislike         = !$this->pConfig->get($uid, 'system', 'hide_dislike', 0);
216                 $display_resharer       =  $this->pConfig->get($uid, 'system', 'display_resharer', 0);
217                 $stay_local             =  $this->pConfig->get($uid, 'system', 'stay_local', 0);
218
219                 $preview_mode  =  $this->pConfig->get($uid, 'system', 'preview_mode', BBCode::PREVIEW_LARGE);
220                 $preview_modes = [
221                         BBCode::PREVIEW_NONE     => $this->t('No preview'),
222                         BBCode::PREVIEW_NO_IMAGE => $this->t('No image'),
223                         BBCode::PREVIEW_SMALL    => $this->t('Small Image'),
224                         BBCode::PREVIEW_LARGE    => $this->t('Large Image'),
225                 ];
226
227                 $network_timelines = $this->pConfig->get($uid, 'system', 'network_timelines', array_keys($this->getAvailableTimelines($uid, true)));
228                 $channel_languages = $this->pConfig->get($uid, 'channel', 'languages', [User::getLanguageCode($uid)]);
229                 $languages         = $this->l10n->getAvailableLanguages(true);
230                 $timelines         = $this->getAvailableTimelines($uid);
231
232                 $first_day_of_week = $this->pConfig->get($uid, 'calendar', 'first_day_of_week', 0);
233                 $weekdays          = [
234                         0 => $this->t('Sunday'),
235                         1 => $this->t('Monday'),
236                         2 => $this->t('Tuesday'),
237                         3 => $this->t('Wednesday'),
238                         4 => $this->t('Thursday'),
239                         5 => $this->t('Friday'),
240                         6 => $this->t('Saturday')
241                 ];
242
243                 $calendar_default_view = $this->pConfig->get($uid, 'calendar', 'default_view', 'month');
244                 $calendarViews         = [
245                         'month'      => $this->t('month'),
246                         'agendaWeek' => $this->t('week'),
247                         'agendaDay'  => $this->t('day'),
248                         'listMonth'  => $this->t('list')
249                 ];
250
251                 $theme_config = '';
252                 if ($themeconfigfile = Theme::getConfigFile($theme_selected)) {
253                         require_once $themeconfigfile;
254                         $theme_config = theme_content($this->app);
255                 }
256
257                 $tpl = Renderer::getMarkupTemplate('settings/display.tpl');
258                 return Renderer::replaceMacros($tpl, [
259                         '$ptitle'         => $this->t('Display Settings'),
260                         '$submit'         => $this->t('Save Settings'),
261                         '$d_tset'         => $this->t('General Theme Settings'),
262                         '$d_ctset'        => $this->t('Custom Theme Settings'),
263                         '$d_cset'         => $this->t('Content Settings'),
264                         '$stitle'         => $this->t('Theme settings'),
265                         '$timeline_title' => $this->t('Timelines'),
266                         '$channel_title'  => $this->t('Channels'),
267                         '$calendar_title' => $this->t('Calendar'),
268
269                         '$form_security_token' => self::getFormSecurityToken('settings_display'),
270                         '$uid'                 => $uid,
271
272                         '$theme'            => ['theme', $this->t('Display Theme:'), $theme_selected, '', $themes, true],
273                         '$mobile_theme' => ['mobile_theme', $this->t('Mobile Theme:'), $mobile_theme_selected, '', $mobile_themes, false],
274                         '$theme_config' => $theme_config,
275
276                         '$itemspage_network'        => ['itemspage_network'       , $this->t('Number of items to display per page:'), $itemspage_network, $this->t('Maximum of 100 items')],
277                         '$itemspage_mobile_network' => ['itemspage_mobile_network', $this->t('Number of items to display per page when viewed from mobile device:'), $itemspage_mobile_network, $this->t('Maximum of 100 items')],
278                         '$ajaxint'                  => ['browser_update'          , $this->t('Update browser every xx seconds'), $browser_update, $this->t('Minimum of 10 seconds. Enter -1 to disable it.')],
279                         '$enable_smile'             => ['enable_smile'            , $this->t('Display emoticons'), $enable_smile, $this->t('When enabled, emoticons are replaced with matching symbols.')],
280                         '$infinite_scroll'          => ['infinite_scroll'         , $this->t('Infinite scroll'), $infinite_scroll, $this->t('Automatic fetch new items when reaching the page end.')],
281                         '$enable_smart_threading'   => ['enable_smart_threading'  , $this->t('Enable Smart Threading'), $enable_smart_threading, $this->t('Enable the automatic suppression of extraneous thread indentation.')],
282                         '$enable_dislike'           => ['enable_dislike'          , $this->t('Display the Dislike feature'), $enable_dislike, $this->t('Display the Dislike button and dislike reactions on posts and comments.')],
283                         '$display_resharer'         => ['display_resharer'        , $this->t('Display the resharer'), $display_resharer, $this->t('Display the first resharer as icon and text on a reshared item.')],
284                         '$stay_local'               => ['stay_local'              , $this->t('Stay local'), $stay_local, $this->t("Don't go to a remote system when following a contact link.")],
285                         '$preview_mode'             => ['preview_mode'            , $this->t('Link preview mode'), $preview_mode, $this->t('Appearance of the link preview that is added to each post with a link.'), $preview_modes, false],
286
287                         '$network_timelines' => ['network_timelines[]', $this->t('Timelines for the network page:'), $network_timelines, $this->t('Select all the timelines that you want to see on your network page.'), $timelines, 'multiple'],
288                         '$channel_languages' => ['channel_languages[]', $this->t('Channel languages:'), $channel_languages, $this->t('Select all languages that you want to see in your channels.'), $languages, 'multiple'],
289
290                         '$first_day_of_week'     => ['first_day_of_week'    , $this->t('Beginning of week:')    , $first_day_of_week    , '', $weekdays     , false],
291                         '$calendar_default_view' => ['calendar_default_view', $this->t('Default calendar view:'), $calendar_default_view, '', $calendarViews, false],
292                 ]);
293         }
294
295         private function getAvailableTimelines(int $uid, bool $only_network = false): array
296         {
297                 $timelines = [];
298
299                 foreach ($this->timeline->getNetworkFeeds('') as $channel) {
300                         $timelines[$channel->code] = $this->t('%s: %s', $channel->label, $channel->description);
301                 }
302
303                 if ($only_network) {
304                         return $timelines;
305                 }
306
307                 foreach ($this->timeline->getChannelsForUser($uid) as $channel) {
308                         $timelines[$channel->code] = $this->t('%s: %s', $channel->label, $channel->description);
309                 }
310
311                 foreach ($this->timeline->getCommunities(true) as $community) {
312                         $timelines[$community->code] = $this->t('%s: %s', $community->label, $community->description);
313                 }
314
315                 return $timelines;
316         }
317 }