]> git.mxchange.org Git - friendica.git/blob - src/Module/Settings/Display.php
Merge pull request #13724 from Raroun/Fix-for-Issue-#13637---Photo-caption-prevents...
[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\Conversation\Collection\Timelines;
26 use Friendica\Content\Text\BBCode;
27 use Friendica\Content\Conversation\Factory\Channel as ChannelFactory;
28 use Friendica\Content\Conversation\Factory\Community as CommunityFactory;
29 use Friendica\Content\Conversation\Factory\Network as NetworkFactory;
30 use Friendica\Content\Conversation\Factory\Timeline as TimelineFactory;
31 use Friendica\Content\Conversation\Repository;
32 use Friendica\Core\Config\Capability\IManageConfigValues;
33 use Friendica\Core\Hook;
34 use Friendica\Core\L10n;
35 use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
36 use Friendica\Core\Renderer;
37 use Friendica\Core\Session\Capability\IHandleUserSessions;
38 use Friendica\Core\Theme;
39 use Friendica\Model\User;
40 use Friendica\Module\BaseSettings;
41 use Friendica\Module\Response;
42 use Friendica\Navigation\SystemMessages;
43 use Friendica\Network\HTTPException;
44 use Friendica\Util\Profiler;
45 use Psr\Log\LoggerInterface;
46
47 /**
48  * Module to update user settings
49  */
50 class Display extends BaseSettings
51 {
52         /** @var IManageConfigValues */
53         private $config;
54         /** @var IManagePersonalConfigValues */
55         private $pConfig;
56         /** @var App */
57         private $app;
58         /** @var SystemMessages */
59         private $systemMessages;
60         /** @var ChannelFactory */
61         protected $channel;
62         /** @var Repository\UserDefinedChannel */
63         protected $userDefinedChannel;
64         /** @var CommunityFactory */
65         protected $community;
66         /** @var NetworkFactory */
67         protected $network;
68         /** @var TimelineFactory */
69         protected $timeline;
70
71         public function __construct(Repository\UserDefinedChannel $userDefinedChannel, NetworkFactory $network, CommunityFactory $community, ChannelFactory $channel, 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 = [])
72         {
73                 parent::__construct($session, $page, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
74
75                 $this->config             = $config;
76                 $this->pConfig            = $pConfig;
77                 $this->app                = $app;
78                 $this->systemMessages     = $systemMessages;
79                 $this->timeline           = $timeline;
80                 $this->channel            = $channel;
81                 $this->community          = $community;
82                 $this->network            = $network;
83                 $this->userDefinedChannel = $userDefinedChannel;
84         }
85
86         protected function post(array $request = [])
87         {
88                 $uid = $this->session->getLocalUserId();
89                 if (!$uid) {
90                         throw new HTTPException\ForbiddenException($this->t('Permission denied.'));
91                 }
92
93                 self::checkFormSecurityTokenRedirectOnError('/settings/display', 'settings_display');
94
95                 $user = User::getById($uid);
96
97                 $theme                  = trim($request['theme']);
98                 $mobile_theme           = trim($request['mobile_theme'] ?? '');
99                 $enable_smile           = (bool)$request['enable_smile'];
100                 $enable                 = (array)$request['enable'];
101                 $bookmark               = (array)$request['bookmark'];
102                 $channel_languages      = (array)$request['channel_languages'];
103                 $first_day_of_week      = (bool)$request['first_day_of_week'];
104                 $calendar_default_view  = trim($request['calendar_default_view']);
105                 $infinite_scroll        = (bool)$request['infinite_scroll'];
106                 $enable_smart_threading = (bool)$request['enable_smart_threading'];
107                 $enable_dislike         = (bool)$request['enable_dislike'];
108                 $display_resharer       = (bool)$request['display_resharer'];
109                 $stay_local             = (bool)$request['stay_local'];
110                 $show_page_drop         = (bool)$request['show_page_drop'];
111                 $display_eventlist      = (bool)$request['display_eventlist'];
112                 $preview_mode           = (int)$request['preview_mode'];
113                 $browser_update         = (int)$request['browser_update'];
114                 if ($browser_update != -1) {
115                         $browser_update = $browser_update * 1000;
116                         if ($browser_update < 10000) {
117                                 $browser_update = 10000;
118                         }
119                 }
120
121                 $enabled_timelines = [];
122                 foreach ($enable as $code => $enabled) {
123                         if ($enabled) {
124                                 $enabled_timelines[] = $code;
125                         }
126                 }
127
128                 $network_timelines = [];
129                 foreach ($bookmark as $code => $bookmarked) {
130                         if ($bookmarked) {
131                                 $network_timelines[] = $code;
132                         }
133                 }
134
135                 $itemspage_network = !empty($request['itemspage_network']) ?
136                         intval($request['itemspage_network']) :
137                         $this->config->get('system', 'itemspage_network');
138                 if ($itemspage_network > 100) {
139                         $itemspage_network = 100;
140                 }
141                 $itemspage_mobile_network = !empty($request['itemspage_mobile_network']) ?
142                         intval($request['itemspage_mobile_network']) :
143                         $this->config->get('system', 'itemspage_network_mobile');
144                 if ($itemspage_mobile_network > 100) {
145                         $itemspage_mobile_network = 100;
146                 }
147
148                 if ($mobile_theme !== '') {
149                         $this->pConfig->set($uid, 'system', 'mobile_theme', $mobile_theme);
150                 }
151
152                 $this->pConfig->set($uid, 'system', 'itemspage_network'       , $itemspage_network);
153                 $this->pConfig->set($uid, 'system', 'itemspage_mobile_network', $itemspage_mobile_network);
154                 $this->pConfig->set($uid, 'system', 'update_interval'         , $browser_update);
155                 $this->pConfig->set($uid, 'system', 'no_smilies'              , !$enable_smile);
156                 $this->pConfig->set($uid, 'system', 'infinite_scroll'         , $infinite_scroll);
157                 $this->pConfig->set($uid, 'system', 'no_smart_threading'      , !$enable_smart_threading);
158                 $this->pConfig->set($uid, 'system', 'hide_dislike'            , !$enable_dislike);
159                 $this->pConfig->set($uid, 'system', 'display_resharer'        , $display_resharer);
160                 $this->pConfig->set($uid, 'system', 'stay_local'              , $stay_local);
161                 $this->pConfig->set($uid, 'system', 'show_page_drop'          , $show_page_drop);
162                 $this->pConfig->set($uid, 'system', 'display_eventlist'       , $display_eventlist);
163                 $this->pConfig->set($uid, 'system', 'preview_mode'            , $preview_mode);
164
165                 $this->pConfig->set($uid, 'system', 'network_timelines'       , $network_timelines);
166                 $this->pConfig->set($uid, 'system', 'enabled_timelines'       , $enabled_timelines);
167                 $this->pConfig->set($uid, 'channel', 'languages'              , $channel_languages);
168
169                 $this->pConfig->set($uid, 'calendar', 'first_day_of_week'     , $first_day_of_week);
170                 $this->pConfig->set($uid, 'calendar', 'default_view'          , $calendar_default_view);
171
172                 if (in_array($theme, Theme::getAllowedList())) {
173                         if ($theme == $user['theme']) {
174                                 // call theme_post only if theme has not been changed
175                                 if ($themeconfigfile = Theme::getConfigFile($theme)) {
176                                         require_once $themeconfigfile;
177                                         theme_post($this->app);
178                                 }
179                         } else {
180                                 User::update(['theme' => $theme], $uid);
181                         }
182                 } else {
183                         $this->systemMessages->addNotice($this->t('The theme you chose isn\'t available.'));
184                 }
185
186                 Hook::callAll('display_settings_post', $request);
187
188                 $this->baseUrl->redirect('settings/display');
189         }
190
191         protected function content(array $request = []): string
192         {
193                 parent::content();
194
195                 $uid = $this->session->getLocalUserId();
196                 if (!$uid) {
197                         throw new HTTPException\ForbiddenException($this->t('Permission denied.'));
198                 }
199
200                 $default_theme = $this->config->get('system', 'theme');
201                 if (!$default_theme) {
202                         $default_theme = 'default';
203                 }
204
205                 $default_mobile_theme = $this->config->get('system', 'mobile-theme');
206                 if (!$default_mobile_theme) {
207                         $default_mobile_theme = 'none';
208                 }
209
210                 $user = User::getById($uid);
211
212                 $allowed_themes = Theme::getAllowedList();
213
214                 $themes = [];
215                 $mobile_themes = ['---' => $this->t('No special theme for mobile devices')];
216                 foreach ($allowed_themes as $theme) {
217                         $is_experimental = file_exists('view/theme/' . $theme . '/experimental');
218                         $is_unsupported  = file_exists('view/theme/' . $theme . '/unsupported');
219                         $is_mobile       = file_exists('view/theme/' . $theme . '/mobile');
220                         if (!$is_experimental || $this->config->get('experimental', 'exp_themes')) {
221                                 $theme_name = ucfirst($theme);
222                                 if ($is_unsupported) {
223                                         $theme_name = $this->t('%s - (Unsupported)', $theme_name);
224                                 } elseif ($is_experimental) {
225                                         $theme_name = $this->t('%s - (Experimental)', $theme_name);
226                                 }
227
228                                 if ($is_mobile) {
229                                         $mobile_themes[$theme] = $theme_name;
230                                 } else {
231                                         $themes[$theme] = $theme_name;
232                                 }
233                         }
234                 }
235
236                 $theme_selected        = $user['theme'] ?: $default_theme;
237                 $mobile_theme_selected = $this->session->get('mobile-theme', $default_mobile_theme);
238
239                 $itemspage_network = intval($this->pConfig->get($uid, 'system', 'itemspage_network'));
240                 $itemspage_network = (($itemspage_network > 0 && $itemspage_network < 101) ? $itemspage_network : $this->config->get('system', 'itemspage_network'));
241                 $itemspage_mobile_network = intval($this->pConfig->get($uid, 'system', 'itemspage_mobile_network'));
242                 $itemspage_mobile_network = (($itemspage_mobile_network > 0 && $itemspage_mobile_network < 101) ? $itemspage_mobile_network : $this->config->get('system', 'itemspage_network_mobile'));
243
244                 $browser_update = intval($this->pConfig->get($uid, 'system', 'update_interval'));
245                 if ($browser_update != -1) {
246                         $browser_update = (($browser_update == 0) ? 40 : $browser_update / 1000); // default if not set: 40 seconds
247                 }
248
249                 $enable_smile           = !$this->pConfig->get($uid, 'system', 'no_smilies', false);
250                 $infinite_scroll        =  $this->pConfig->get($uid, 'system', 'infinite_scroll', false);
251                 $enable_smart_threading = !$this->pConfig->get($uid, 'system', 'no_smart_threading', false);
252                 $enable_dislike         = !$this->pConfig->get($uid, 'system', 'hide_dislike', false);
253                 $display_resharer       =  $this->pConfig->get($uid, 'system', 'display_resharer', false);
254                 $stay_local             =  $this->pConfig->get($uid, 'system', 'stay_local', false);
255                 $show_page_drop         =  $this->pConfig->get($uid, 'system', 'show_page_drop', true);
256                 $display_eventlist      =  $this->pConfig->get($uid, 'system', 'display_eventlist', true);
257
258                 $preview_mode  =  $this->pConfig->get($uid, 'system', 'preview_mode', BBCode::PREVIEW_LARGE);
259                 $preview_modes = [
260                         BBCode::PREVIEW_NONE     => $this->t('No preview'),
261                         BBCode::PREVIEW_NO_IMAGE => $this->t('No image'),
262                         BBCode::PREVIEW_SMALL    => $this->t('Small Image'),
263                         BBCode::PREVIEW_LARGE    => $this->t('Large Image'),
264                 ];
265
266                 $bookmarked_timelines = $this->pConfig->get($uid, 'system', 'network_timelines', $this->getAvailableTimelines($uid, true)->column('code'));
267                 $enabled_timelines    = $this->pConfig->get($uid, 'system', 'enabled_timelines', $this->getAvailableTimelines($uid, false)->column('code'));
268                 $channel_languages = User::getWantedLanguages($uid);
269                 $languages         = $this->l10n->getLanguageCodes(true);
270
271                 $timelines = [];
272                 foreach ($this->getAvailableTimelines($uid) as $timeline) {
273                         $timelines[] = [
274                                 'label'        => $timeline->label,
275                                 'description'  => $timeline->description,
276                                 'enable'       => ["enable[{$timeline->code}]", '', in_array($timeline->code, $enabled_timelines)],
277                                 'bookmark'     => ["bookmark[{$timeline->code}]", '', in_array($timeline->code, $bookmarked_timelines)],
278                         ];
279                 }
280
281                 $first_day_of_week = $this->pConfig->get($uid, 'calendar', 'first_day_of_week', 0);
282                 $weekdays          = [
283                         0 => $this->t('Sunday'),
284                         1 => $this->t('Monday'),
285                         2 => $this->t('Tuesday'),
286                         3 => $this->t('Wednesday'),
287                         4 => $this->t('Thursday'),
288                         5 => $this->t('Friday'),
289                         6 => $this->t('Saturday')
290                 ];
291
292                 $calendar_default_view = $this->pConfig->get($uid, 'calendar', 'default_view', 'month');
293                 $calendarViews         = [
294                         'month'      => $this->t('month'),
295                         'agendaWeek' => $this->t('week'),
296                         'agendaDay'  => $this->t('day'),
297                         'listMonth'  => $this->t('list')
298                 ];
299
300                 $theme_config = '';
301                 if ($themeconfigfile = Theme::getConfigFile($theme_selected)) {
302                         require_once $themeconfigfile;
303                         $theme_config = theme_content($this->app);
304                 }
305
306                 $tpl = Renderer::getMarkupTemplate('settings/display.tpl');
307                 return Renderer::replaceMacros($tpl, [
308                         '$ptitle'         => $this->t('Display Settings'),
309                         '$submit'         => $this->t('Save Settings'),
310                         '$d_tset'         => $this->t('General Theme Settings'),
311                         '$d_ctset'        => $this->t('Custom Theme Settings'),
312                         '$d_cset'         => $this->t('Content Settings'),
313                         '$stitle'         => $this->t('Theme settings'),
314                         '$timeline_title' => $this->t('Timelines'),
315                         '$channel_title'  => $this->t('Channels'),
316                         '$calendar_title' => $this->t('Calendar'),
317
318                         '$form_security_token' => self::getFormSecurityToken('settings_display'),
319                         '$uid'                 => $uid,
320
321                         '$theme'            => ['theme', $this->t('Display Theme:'), $theme_selected, '', $themes, true],
322                         '$mobile_theme' => ['mobile_theme', $this->t('Mobile Theme:'), $mobile_theme_selected, '', $mobile_themes, false],
323                         '$theme_config' => $theme_config,
324
325                         '$itemspage_network'        => ['itemspage_network'       , $this->t('Number of items to display per page:'), $itemspage_network, $this->t('Maximum of 100 items')],
326                         '$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')],
327                         '$ajaxint'                  => ['browser_update'          , $this->t('Update browser every xx seconds'), $browser_update, $this->t('Minimum of 10 seconds. Enter -1 to disable it.')],
328                         '$enable_smile'             => ['enable_smile'            , $this->t('Display emoticons'), $enable_smile, $this->t('When enabled, emoticons are replaced with matching symbols.')],
329                         '$infinite_scroll'          => ['infinite_scroll'         , $this->t('Infinite scroll'), $infinite_scroll, $this->t('Automatic fetch new items when reaching the page end.')],
330                         '$enable_smart_threading'   => ['enable_smart_threading'  , $this->t('Enable Smart Threading'), $enable_smart_threading, $this->t('Enable the automatic suppression of extraneous thread indentation.')],
331                         '$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.')],
332                         '$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.')],
333                         '$stay_local'               => ['stay_local'              , $this->t('Stay local'), $stay_local, $this->t("Don't go to a remote system when following a contact link.")],
334                         '$show_page_drop'           => ['show_page_drop'          , $this->t('Show the post deletion checkbox'), $show_page_drop, $this->t("Display the checkbox for the post deletion on the network page.")],
335                         '$display_eventlist'        => ['display_eventlist'       , $this->t('DIsplay the event list'), $display_eventlist, $this->t("Display the birthday reminder and event list on the network page.")],
336                         '$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],
337
338                         '$timeline_label'       => $this->t('Label'),
339                         '$timeline_descriptiom' => $this->t('Description'),
340                         '$timeline_enable'      => $this->t('Enable'),
341                         '$timeline_bookmark'    => $this->t('Bookmark'),
342                         '$timelines'            => $timelines,
343                         '$timeline_explanation' => $this->t('Enable timelines that you want to see in the channels widget. Bookmark timelines that you want to see in the top menu.'),
344
345                         '$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'],
346
347                         '$first_day_of_week'     => ['first_day_of_week'    , $this->t('Beginning of week:')    , $first_day_of_week    , '', $weekdays     , false],
348                         '$calendar_default_view' => ['calendar_default_view', $this->t('Default calendar view:'), $calendar_default_view, '', $calendarViews, false],
349                 ]);
350         }
351
352         private function getAvailableTimelines(int $uid, bool $only_network = false): Timelines
353         {
354                 $timelines = [];
355
356                 foreach ($this->network->getTimelines('') as $channel) {
357                         $timelines[] = $channel;
358                 }
359
360                 if ($only_network) {
361                         return new Timelines($timelines);
362                 }
363
364                 foreach ($this->channel->getTimelines($uid) as $channel) {
365                         $timelines[] = $channel;
366                 }
367
368                 foreach ($this->userDefinedChannel->selectByUid($uid) as $channel) {
369                         $timelines[] = $channel;
370                 }
371
372                 foreach ($this->community->getTimelines(true) as $community) {
373                         $timelines[] = $community;
374                 }
375
376                 return new Timelines($timelines);
377         }
378 }