diff --git a/apps/theming/lib/Listener/BeforePreferenceListener.php b/apps/theming/lib/Listener/BeforePreferenceListener.php
index d823df1ab33c2..78e2f3c447c58 100644
--- a/apps/theming/lib/Listener/BeforePreferenceListener.php
+++ b/apps/theming/lib/Listener/BeforePreferenceListener.php
@@ -22,7 +22,15 @@ class BeforePreferenceListener implements IEventListener {
/**
* @var string[]
*/
- private const ALLOWED_KEYS = ['force_enable_blur_filter', 'shortcuts_disabled', 'primary_color'];
+ private const ALLOWED_KEYS = ['force_enable_blur_filter', 'shortcuts_disabled', 'primary_color', 'toast_timeout'];
+
+ /**
+ * Allowed toast timeout values in milliseconds.
+ * Default (7000) is represented by deleting the preference.
+ *
+ * @var string[]
+ */
+ public const TOAST_TIMEOUT_VALUES = ['15000', '30000', '-1'];
public function __construct(
private IAppManager $appManager,
@@ -62,6 +70,9 @@ private function handleThemingValues(BeforePreferenceSetEvent|BeforePreferenceDe
case 'primary_color':
$event->setValid(preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $event->getConfigValue()) === 1);
break;
+ case 'toast_timeout':
+ $event->setValid(in_array($event->getConfigValue(), self::TOAST_TIMEOUT_VALUES, true));
+ break;
default:
$event->setValid(false);
}
diff --git a/apps/theming/lib/Listener/BeforeTemplateRenderedListener.php b/apps/theming/lib/Listener/BeforeTemplateRenderedListener.php
index 3a62d8ebdf32b..88a307067d434 100644
--- a/apps/theming/lib/Listener/BeforeTemplateRenderedListener.php
+++ b/apps/theming/lib/Listener/BeforeTemplateRenderedListener.php
@@ -51,6 +51,17 @@ public function handle(Event $event): void {
}
return false;
});
+
+ $this->initialState->provideLazyInitialState('toastTimeout', function () {
+ if ($this->userSession->getUser()) {
+ $uid = $this->userSession->getUser()->getUID();
+ $value = $this->config->getUserValue($uid, Application::APP_ID, 'toast_timeout', '7000');
+ if (in_array($value, BeforePreferenceListener::TOAST_TIMEOUT_VALUES, true) || $value === '7000') {
+ return (int)$value;
+ }
+ }
+ return 7000;
+ });
}
$this->themeInjectionService->injectHeaders();
diff --git a/apps/theming/src/components/UserSectionToastTimeout.vue b/apps/theming/src/components/UserSectionToastTimeout.vue
new file mode 100644
index 0000000000000..5506cdab0f9c2
--- /dev/null
+++ b/apps/theming/src/components/UserSectionToastTimeout.vue
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/theming/src/theming.ts b/apps/theming/src/theming.ts
index 4678efe37a319..4187da73a9e56 100644
--- a/apps/theming/src/theming.ts
+++ b/apps/theming/src/theming.ts
@@ -3,6 +3,12 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
+import { setToastTimeout, TOAST_DEFAULT_TIMEOUT } from '@nextcloud/dialogs'
import { loadState } from '@nextcloud/initial-state'
window.OCA.Theming = loadState('theming', 'data')
+
+const toastTimeout = loadState('theming', 'toastTimeout', TOAST_DEFAULT_TIMEOUT)
+if (typeof toastTimeout === 'number') {
+ setToastTimeout(toastTimeout)
+}
diff --git a/apps/theming/src/views/UserTheming.vue b/apps/theming/src/views/UserTheming.vue
index 6ecee83202e7a..7bb7128547e0d 100644
--- a/apps/theming/src/views/UserTheming.vue
+++ b/apps/theming/src/views/UserTheming.vue
@@ -49,6 +49,7 @@
+
@@ -68,6 +69,7 @@ import UserSectionAppMenu from '../components/UserSectionAppMenu.vue'
import UserSectionBackground from '../components/UserSectionBackground.vue'
import UserSectionHotkeys from '../components/UserSectionHotkeys.vue'
import UserSectionPrimaryColor from '../components/UserSectionPrimaryColor.vue'
+import UserSectionToastTimeout from '../components/UserSectionToastTimeout.vue'
import { refreshStyles } from '../utils/refreshStyles.js'
const isUserThemingDisabled = loadState('theming', 'isUserThemingDisabled')