diff --git a/appinfo/routes.php b/appinfo/routes.php index 3093b5c73a4fc188851a0847f501c119f0f1d321..01af30c94d3759c28bf0a922dca7c329e81ecbb1 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -34,11 +34,6 @@ return [ 'url' => '/setup', 'verb' => 'GET' ], - [ - 'name' => 'page#accountSettings', - 'url' => '/accounts/{id}/settings', - 'verb' => 'GET' - ], [ 'name' => 'page#mailbox', 'url' => '/box/{id}', diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index 4577bc9833f3bf0a4ba6c12f5fd1ce54c6a9af10..4091519b3e13ae9ac7ac1dec3825839d920c9b57 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -168,16 +168,6 @@ class PageController extends Controller { return $this->index(); } - /** - * @NoAdminRequired - * @NoCSRFRequired - * - * @return TemplateResponse - */ - public function accountSettings(int $id): TemplateResponse { - return $this->index(); - } - /** * @NoAdminRequired * @NoCSRFRequired diff --git a/src/components/AccountForm.vue b/src/components/AccountForm.vue index ad5f866682d15b72f89bf50acebe5d124f6488d8..a37cc7dea9cc08654451b0669aaa410d1d9a5722 100644 --- a/src/components/AccountForm.vue +++ b/src/components/AccountForm.vue @@ -358,6 +358,7 @@ export default { flex-grow: 1; text-align: center; color: var(--color-text-lighter); + margin-bottom: 10px; } ::v-deep .tabs-component-tab.is-active { diff --git a/src/components/AccountSettings.vue b/src/components/AccountSettings.vue new file mode 100644 index 0000000000000000000000000000000000000000..066039b17f1e1d01df48cccb0441bc5b64b77c6f --- /dev/null +++ b/src/components/AccountSettings.vue @@ -0,0 +1,183 @@ +<!-- + - @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + - @copyright 2020 Greta Doci <gretadoci@gmail.com> + - + - @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at> + - @author 2020 Greta Doci <gretadoci@gmail.com> + - + - + - @license GNU AGPL version 3 or any later version + - + - 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> + <AppSettingsDialog + :open.sync="showSettings"> + <AppSettingsSection + :title="t('mail', 'Account settings')"> + <strong>{{ displayName }}</strong> <{{ email }}> + <a + v-if="!account.provisioned" + class="button icon-rename" + :title="t('mail', 'Change name')" + @click="handleClick" /> + <AliasSettings v-if="!account.provisioned" :account="account" /> + </AppSettingsSection> + <AppSettingsSection :title="t('mail', 'Signature')"> + <p class="settings-hint"> + {{ t('mail', 'A signature is added to the text of new messages and replies.') }} + </p> + <SignatureSettings :account="account" /> + </AppSettingsSection> + <AppSettingsSection :title="t('mail', 'Writing mode')"> + <p class="settings-hint"> + {{ t('mail', 'Preferred writing mode for new messages and replies.') }} + </p> + <EditorSettings :account="account" /> + </AppSettingsSection> + + <AppSettingsSection :title="t('mail', 'Mail server')"> + <div v-if="!account.provisioned"> + <div id="mail-settings"> + <AccountForm + :key="account.accountId" + ref="accountForm" + :display-name="displayName" + :email="email" + :save="onSave" + :account="account" /> + </div> + </div> + </AppSettingsSection> + </AppSettingsDialog> +</template> + +<script> +import AccountForm from '../components/AccountForm' +import EditorSettings from '../components/EditorSettings' +import Logger from '../logger' +import SignatureSettings from '../components/SignatureSettings' +import AliasSettings from '../components/AliasSettings' +import AppSettingsDialog from '@nextcloud/vue/dist/Components/AppSettingsDialog' +import AppSettingsSection from '@nextcloud/vue/dist/Components/AppSettingsSection' +export default { + name: 'AccountSettings', + components: { + AccountForm, + AliasSettings, + EditorSettings, + SignatureSettings, + AppSettingsDialog, + AppSettingsSection, + }, + props: { + account: { + required: true, + type: Object, + }, + open: { + required: true, + type: Boolean, + }, + }, + data() { + return { + showSettings: false, + } + }, + computed: { + menu() { + return this.buildMenu() + }, + displayName() { + return this.account.name + }, + email() { + return this.account.emailAddress + }, + }, + watch: { + showSettings(value) { + if (!value) { + this.$emit('update:open', value) + } + }, + open(value) { + if (value) { + this.showSettings = true + } + }, + }, + methods: { + onSave(data) { + Logger.log('saving data', { data }) + return this.$store + .dispatch('updateAccount', { + ...data, + accountId: this.$route.params.accountId, + }) + .then((account) => account) + .catch((error) => { + Logger.error('account update failed:', { error }) + throw error + }) + }, + handleClick() { + this.$refs.accountForm.$el.scrollIntoView({ + behavior: 'smooth', + }) + + }, + }, +} +</script> + +<style lang="scss" scoped> +::v-deep .modal-container { + display: block; + overflow: scroll; + transition: transform 300ms ease; + border-radius: var(--border-radius-large); + box-shadow: 0 0 40px rgba(0,0,0,0.2); + padding: 30px 70px 20px; +} +.button.icon-rename { + background-image: var(--icon-rename-000); + background-color: var(--color-main-background); + border: none; + opacity: 0.7; + &:hover, + &:focus { + opacity: 1; + } +} +.settings-hint { + margin-top: -12px; + margin-bottom: 6px; + color: var(--color-text-maxcontrast); +} +h2 { + font-weight: bold; + font-size: 20px; + margin-bottom: 12px; + margin-left: -30px; + line-height: 30px; + color: var(--color-text-light); +} +.app-settings-section { +margin-bottom: 45px; +} + +</style> diff --git a/src/components/AliasSettings.vue b/src/components/AliasSettings.vue index 6707396c5b33bd7fdef73a317cda8e9aa474836e..c7fd79025e20aa8af246eebaf849e2262a9bc02d 100644 --- a/src/components/AliasSettings.vue +++ b/src/components/AliasSettings.vue @@ -130,6 +130,14 @@ input { } .icon-delete { vertical-align: bottom; + background-image: var(--icon-delete-000); + background-color: var(--color-main-background); + border: none; + opacity: 0.7; + &:hover, + &:focus { + opacity: 1; + } } .icon-add { background-image: var(--icon-add-fff); diff --git a/src/components/EditorSettings.vue b/src/components/EditorSettings.vue index fc260ba24cf67006e7ee3456661603c160ec847d..bc752305953f56ae05e60202bbe4b0fe4a991b1f 100644 --- a/src/components/EditorSettings.vue +++ b/src/components/EditorSettings.vue @@ -20,11 +20,7 @@ --> <template> - <div class="section"> - <h2>{{ t('mail', 'Writing mode') }}</h2> - <p class="settings-hint"> - {{ t('mail', 'Preferred writing mode for new messages and replies.') }} - </p> + <div> <p> <input id="plaintext" v-model="mode" @@ -85,11 +81,6 @@ export default { </script> <style lang="scss" scoped> -.settings-hint { - margin-top: -12px; - margin-bottom: 6px; - color: var(--color-text-maxcontrast); -} label { padding-right: 12px; diff --git a/src/components/NavigationAccount.vue b/src/components/NavigationAccount.vue index 20d1e56a96c4c871436d544b186bb839bcc38ad3..e543f5656ff92c3913033b0e4ee977d06379201e 100644 --- a/src/components/NavigationAccount.vue +++ b/src/components/NavigationAccount.vue @@ -38,9 +38,12 @@ <ActionText v-if="!account.isUnified" icon="icon-info" :title="t('mail', 'Quota')"> {{ quotaText }} </ActionText> - <ActionRouter :to="settingsRoute" icon="icon-settings"> + <ActionButton icon="icon-settings" + :close-after-click="true" + @click="showAccountSettings" + @shortkey="toggleAccountSettings"> {{ t('mail', 'Account settings') }} - </ActionRouter> + </ActionButton> <ActionCheckbox :checked="account.showSubscribedOnly" :disabled="savingShowOnlySubscribed" @@ -64,13 +67,15 @@ {{ t('mail', 'Remove account') }} </ActionButton> </template> + <template #extra> + <AccountSettings :open.sync="showSettings" :account="account" /> + </template> </AppNavigationItem> </template> <script> import AppNavigationItem from '@nextcloud/vue/dist/Components/AppNavigationItem' import AppNavigationIconBullet from '@nextcloud/vue/dist/Components/AppNavigationIconBullet' -import ActionRouter from '@nextcloud/vue/dist/Components/ActionRouter' import ActionButton from '@nextcloud/vue/dist/Components/ActionButton' import ActionCheckbox from '@nextcloud/vue/dist/Components/ActionCheckbox' import ActionInput from '@nextcloud/vue/dist/Components/ActionInput' @@ -81,17 +86,18 @@ import { generateUrl } from '@nextcloud/router' import { calculateAccountColor } from '../util/AccountColor' import logger from '../logger' import { fetchQuota } from '../service/AccountService' +import AccountSettings from './AccountSettings' export default { name: 'NavigationAccount', components: { AppNavigationItem, AppNavigationIconBullet, - ActionRouter, ActionButton, ActionCheckbox, ActionInput, ActionText, + AccountSettings, }, props: { account: { @@ -121,20 +127,13 @@ export default { quota: undefined, editing: false, showSaving: false, + showSettings: false, } }, computed: { visible() { return this.account.isUnified !== true && this.account.visible !== false }, - settingsRoute() { - return { - name: 'accountSettings', - params: { - accountId: this.account.id, - }, - } - }, firstMailboxRoute() { return { name: 'mailbox', @@ -267,6 +266,18 @@ export default { this.quota = quota } }, + /** + * Toggles the account settings overview + */ + toggleAccountSettings() { + this.displayAccountSettings = !this.displayAccountSettings + }, + /** + * Shows the account settings + */ + showAccountSettings() { + this.showSettings = true + }, }, } </script> diff --git a/src/components/SignatureSettings.vue b/src/components/SignatureSettings.vue index 1d399859d987cd7055e63f23a9a25ce1931dbfdb..b8cbbeeca923f19ad80686da2fe5802e77e1e431 100644 --- a/src/components/SignatureSettings.vue +++ b/src/components/SignatureSettings.vue @@ -21,10 +21,6 @@ <template> <div class="section"> - <h2>{{ t('mail', 'Signature') }}</h2> - <p class="settings-hint"> - {{ t('mail', 'A signature is added to the text of new messages and replies.') }} - </p> <TextEditor v-model="signature" :html="true" :placeholder="t('mail', 'Signature …')" @@ -103,14 +99,9 @@ export default { </script> <style lang="scss" scoped> -.settings-hint { - margin-top: -12px; - margin-bottom: 6px; - color: var(--color-text-maxcontrast); -} .ck.ck-editor__editable_inline { - width: 400px; + width: 330px; max-width: 78vw; height: 100px; border-radius: var(--border-radius) !important; @@ -139,4 +130,9 @@ export default { color: var(--color-main-text); } } +.section { + display: block; + padding: 0; + margin-bottom: 23px; +} </style> diff --git a/src/router.js b/src/router.js index 5b00f696a591ad0644b649687e14398d5f41019d..313b831160fa70b87df614928f2b875974a6ca4a 100644 --- a/src/router.js +++ b/src/router.js @@ -2,7 +2,6 @@ import Vue from 'vue' import Router from 'vue-router' import { generateUrl } from '@nextcloud/router' -const AccountSettings = () => import('./views/AccountSettings') const Home = () => import('./views/Home') const Setup = () => import('./views/Setup') @@ -33,11 +32,6 @@ export default new Router({ name: 'message', component: Home, }, - { - path: '/accounts/:accountId/settings', - name: 'accountSettings', - component: AccountSettings, - }, { path: '/setup', name: 'setup', diff --git a/src/views/AccountSettings.vue b/src/views/AccountSettings.vue deleted file mode 100644 index 2df04e4bd08790f74eb034fb82e3e81ce465a313..0000000000000000000000000000000000000000 --- a/src/views/AccountSettings.vue +++ /dev/null @@ -1,103 +0,0 @@ -<template> - <Content app-name="mail"> - <Navigation /> - <AppContent> - <div class="section"> - <h2>{{ t('mail', 'Account settings') }}</h2> - <p> - <strong>{{ displayName }}</strong> <{{ email }}> - <a - v-if="!account.provisioned" - class="button icon-rename" - href="#account-form" - :title="t('mail', 'Change name')" /> - </p> - <AliasSettings v-if="!account.provisioned" :key="'alias-settings-' + account.id" :account="account" /> - </div> - <SignatureSettings :key="'signature-settings-' + account.id" :account="account" /> - <EditorSettings :key="'editor-settings-' + account.id" :account="account" /> - <AccountDefaultsSettings :key="'defaults-settings-' + account.id" :account="account" /> - <div v-if="!account.provisioned" class="section"> - <h2>{{ t('mail', 'Mail server') }}</h2> - <div id="mail-settings"> - <AccountForm - :key="account.accountId" - :display-name="displayName" - :email="email" - :save="onSave" - :account="account" /> - </div> - </div> - </AppContent> - </Content> -</template> - -<script> -import AppContent from '@nextcloud/vue/dist/Components/AppContent' -import Content from '@nextcloud/vue/dist/Components/Content' - -import AccountDefaultsSettings from '../components/AccountDefaultsSettings' -import AccountForm from '../components/AccountForm' -import AliasSettings from '../components/AliasSettings' -import EditorSettings from '../components/EditorSettings' -import Logger from '../logger' -import Navigation from '../components/Navigation' -import SignatureSettings from '../components/SignatureSettings' - -export default { - name: 'AccountSettings', - components: { - AccountDefaultsSettings, - AccountForm, - AliasSettings, - AppContent, - Content, - EditorSettings, - Navigation, - SignatureSettings, - }, - computed: { - menu() { - return this.buildMenu() - }, - account() { - return this.$store.getters.getAccount(this.$route.params.accountId) - }, - displayName() { - return this.$store.getters.getAccount(this.$route.params.accountId).name - }, - email() { - return this.$store.getters.getAccount(this.$route.params.accountId).emailAddress - }, - }, - methods: { - onSave(data) { - Logger.log('saving data', { data }) - return this.$store - .dispatch('updateAccount', { - ...data, - accountId: this.$route.params.accountId, - }) - .then((account) => account) - .catch((error) => { - Logger.error('account update failed:', { error }) - - throw error - }) - }, - }, -} -</script> - -<style lang="scss" scoped> -.button.icon-rename { - background-color: transparent; - border: none; - opacity: 0.3; - - &:hover, - &:focus { - opacity: 1; - } -} -</style>