diff --git a/dev/Model/FolderCollection.js b/dev/Model/FolderCollection.js index 769768dfb..4b702dc0c 100644 --- a/dev/Model/FolderCollection.js +++ b/dev/Model/FolderCollection.js @@ -25,7 +25,7 @@ const INBOX: 1, SENT: 2, DRAFTS: 3, - JUNK: 4, + SPAM: 4, // JUNK TRASH: 5, // IMPORTANT: 10, // FLAGGED: 11, @@ -39,6 +39,8 @@ normalizeFolder = sFolderFullNameRaw => ('' === sFolderFullNameRaw ? sFolderFullNameRaw : ''; +let SystemFolders = {}; + export class FolderCollectionModel extends AbstractCollectionModel { /* @@ -59,7 +61,11 @@ export class FolderCollectionModel extends AbstractCollectionModel */ static reviveFromJson(object) { const expandedFolders = Local.get(ClientSideKeyName.ExpandedFolders); - return super.reviveFromJson(object, (oFolder, self) => { + if (object && object.SystemFolders) { + SystemFolders = object.SystemFolders; + } + + return super.reviveFromJson(object, oFolder => { let oCacheFolder = Cache.getFolderFromCacheList(oFolder.FullNameRaw); /* if (oCacheFolder) { @@ -68,7 +74,7 @@ export class FolderCollectionModel extends AbstractCollectionModel } */ if (!oCacheFolder && (oCacheFolder = FolderModel.reviveFromJson(oFolder))) { - if (oFolder.FullNameRaw == self.SystemFolders[ServerFolderType.INBOX]) { + if (oFolder.FullNameRaw == SystemFolders[ServerFolderType.INBOX]) { oCacheFolder.type(FolderType.Inbox); Cache.setFolderInboxName(oFolder.FullNameRaw); } @@ -76,6 +82,25 @@ export class FolderCollectionModel extends AbstractCollectionModel } if (oCacheFolder) { + switch (oFolder.FullNameRaw) + { + case (SettingsGet('SentFolder') || SystemFolders[ServerFolderType.SENT]): + oCacheFolder.type(FolderType.Sent); + break; + case (SettingsGet('DraftFolder') || SystemFolders[ServerFolderType.DRAFTS]): + oCacheFolder.type(FolderType.Drafts); + break; + case (SettingsGet('SpamFolder') || SystemFolders[ServerFolderType.SPAM]): + oCacheFolder.type(FolderType.Spam); + break; + case (SettingsGet('TrashFolder') || SystemFolders[ServerFolderType.TRASH]): + oCacheFolder.type(FolderType.Trash); + break; + case (SettingsGet('ArchiveFolder') || SystemFolders[ServerFolderType.ARCHIVE]): + oCacheFolder.type(FolderType.Archive); + break; + } + oCacheFolder.collapsed(!expandedFolders || !isArray(expandedFolders) || !expandedFolders.includes(oCacheFolder.fullNameHash)); @@ -104,6 +129,23 @@ export class FolderCollectionModel extends AbstractCollectionModel FolderUserStore.displaySpecSetting(0 >= cnt || Math.max(10, Math.min(100, pInt(Settings.app('folderSpecLimit')))) < cnt); + if (SystemFolders && + !('' + + SettingsGet('SentFolder') + + SettingsGet('DraftFolder') + + SettingsGet('SpamFolder') + + SettingsGet('TrashFolder') + + SettingsGet('ArchiveFolder')) + ) { + FolderUserStore.saveSystemFolders({ + SentFolder: SystemFolders[ServerFolderType.SENT] || null, + DraftFolder: SystemFolders[ServerFolderType.DRAFTS] || null, + SpamFolder: SystemFolders[ServerFolderType.SPAM] || null, + TrashFolder: SystemFolders[ServerFolderType.TRASH] || null, + ArchiveFolder: SystemFolders[ServerFolderType.ARCHIVE] || null + }); + } + FolderUserStore.folderList(this); if (undefined !== this.Namespace) { @@ -115,41 +157,13 @@ export class FolderCollectionModel extends AbstractCollectionModel FolderUserStore.folderListOptimized(!!this.Optimized); FolderUserStore.sortSupported(!!this.IsSortSupported); - let update = false; - - if ( - this.SystemFolders && - !('' + - SettingsGet('SentFolder') + - SettingsGet('DraftFolder') + - SettingsGet('SpamFolder') + - SettingsGet('TrashFolder') + - SettingsGet('ArchiveFolder')) - ) { - Settings.set('SentFolder', this.SystemFolders[ServerFolderType.SENT] || null); - Settings.set('DraftFolder', this.SystemFolders[ServerFolderType.DRAFTS] || null); - Settings.set('SpamFolder', this.SystemFolders[ServerFolderType.JUNK] || null); - Settings.set('TrashFolder', this.SystemFolders[ServerFolderType.TRASH] || null); - Settings.set('ArchiveFolder', this.SystemFolders[ServerFolderType.ARCHIVE] || null); - - update = true; - } - FolderUserStore.sentFolder(normalizeFolder(SettingsGet('SentFolder'))); FolderUserStore.draftFolder(normalizeFolder(SettingsGet('DraftFolder'))); FolderUserStore.spamFolder(normalizeFolder(SettingsGet('SpamFolder'))); FolderUserStore.trashFolder(normalizeFolder(SettingsGet('TrashFolder'))); FolderUserStore.archiveFolder(normalizeFolder(SettingsGet('ArchiveFolder'))); - if (update) { - rl.app.Remote.saveSystemFolders(()=>0, { - SentFolder: FolderUserStore.sentFolder(), - DraftFolder: FolderUserStore.draftFolder(), - SpamFolder: FolderUserStore.spamFolder(), - TrashFolder: FolderUserStore.trashFolder(), - ArchiveFolder: FolderUserStore.archiveFolder() - }); - } +// FolderUserStore.folderList.valueHasMutated(); Local.set(ClientSideKeyName.FoldersLashHash, this.FoldersHash); } @@ -254,26 +268,22 @@ export class FolderModel extends AbstractModel { hasSubscribedSubfolders: () => - !!folder.subFolders.find( + !!folder.subFolders().find( oFolder => (oFolder.subscribed() || oFolder.hasSubscribedSubfolders()) && !oFolder.isSystemFolder() ), canBeEdited: () => FolderType.User === folder.type() && folder.exists/* && folder.selectable*/, visible: () => { - const isSubscribed = folder.subscribed(), - isSubFolders = folder.hasSubscribedSubfolders(); - - return isSubscribed || (isSubFolders && (!folder.exists/* || !folder.selectable*/)); + const hasSubFolders = folder.hasSubscribedSubfolders(); + return folder.subscribed() || hasSubFolders; }, isSystemFolder: () => FolderType.User !== folder.type(), hidden: () => { - const isSystem = folder.isSystemFolder(), - isSubFolders = folder.hasSubscribedSubfolders(); - - return (isSystem && !isSubFolders) || (!folder.selectable && !isSubFolders); + let hasSubFolders = folder.hasSubscribedSubfolders(); + return (folder.isSystemFolder() || !folder.selectable) && !hasSubFolders; }, printableUnreadCount: () => { @@ -298,7 +308,7 @@ export class FolderModel extends AbstractModel { return null; }, - canBeDeleted: () => !folder.isSystemFolder() && !folder.subFolders.length, + canBeDeleted: () => !folder.isSystemFolder() && !folder.subFolders().length, canBeSubscribed: () => !folder.isSystemFolder() && SettingsUserStore.hideUnsubscribed() @@ -329,16 +339,16 @@ export class FolderModel extends AbstractModel { }, collapsed: { - read: () => !folder.hidden() && folder.collapsedPrivate(), - write: (value) => { - folder.collapsedPrivate(value); - } + read: () => folder.isInbox() && FolderUserStore.singleRootFolder() + ? false + : !folder.hidden() && folder.collapsedPrivate(), + write: value => folder.collapsedPrivate(value) }, hasUnreadMessages: () => 0 < folder.messageCountUnread() && folder.printableUnreadCount(), hasSubscribedUnreadMessagesSubfolders: () => - !!folder.subFolders.find( + !!folder.subFolders().find( folder => folder.hasUnreadMessages() || folder.hasSubscribedUnreadMessagesSubfolders() ) }); diff --git a/dev/Stores/User/Folder.js b/dev/Stores/User/Folder.js index dc709e897..3ac87bdba 100644 --- a/dev/Stores/User/Folder.js +++ b/dev/Stores/User/Folder.js @@ -4,7 +4,7 @@ import { FolderType, FolderSortMode } from 'Common/EnumsUser'; import { UNUSED_OPTION_VALUE } from 'Common/Consts'; import { addObservablesTo, addSubscribablesTo } from 'Common/Utils'; import { getFolderInboxName, getFolderFromCacheList } from 'Common/Cache'; -import { SettingsGet } from 'Common/Globals'; +import { Settings, SettingsGet } from 'Common/Globals'; export const FolderUserStore = new class { constructor() { @@ -55,9 +55,17 @@ export const FolderUserStore = new class { () => !this.draftFolder() || UNUSED_OPTION_VALUE === this.draftFolder() ); - this.foldersListWithSingleInboxRootFolder = ko.computed( - () => !this.folderList.find(folder => folder && !folder.isSystemFolder() && folder.visible()) - ); + // foldersListWithSingleInboxRootFolder + /** returns true when there are no non-system folders in the root of the folders tree */ + this.singleRootFolder = ko.computed(() => { + let multiple = false; + this.folderList.forEach(folder => { + let subscribed = folder.subscribed(), + hasSub = folder.hasSubscribedSubfolders(); + multiple |= (!folder.isSystemFolder() || (hasSub && !folder.isInbox())) && (subscribed || hasSub) + }); + return !multiple; + }); this.currentFolderFullNameRaw = ko.computed(() => (this.currentFolder() ? this.currentFolder().fullNameRaw : '')); @@ -156,4 +164,16 @@ export const FolderUserStore = new class { return result.filter((value, index, self) => self.indexOf(value) == index); } + + saveSystemFolders(folders) { + folders = folders || { + SentFolder: FolderUserStore.sentFolder(), + DraftFolder: FolderUserStore.draftFolder(), + SpamFolder: FolderUserStore.spamFolder(), + TrashFolder: FolderUserStore.trashFolder(), + ArchiveFolder: FolderUserStore.archiveFolder() + }; + Object.entries(folders).forEach(([k,v])=>Settings.set(k,v)); + rl.app.Remote.saveSystemFolders(()=>0, folders); + } }; diff --git a/dev/Styles/User/FolderList.less b/dev/Styles/User/FolderList.less index 28b68b4de..19f5f1a99 100644 --- a/dev/Styles/User/FolderList.less +++ b/dev/Styles/User/FolderList.less @@ -4,6 +4,10 @@ .b-folders { + ul { + margin: 0; + } + .move-action-content-wrapper { z-index: -1; position: fixed; @@ -60,8 +64,8 @@ border-bottom: 1px solid #999; } - .e-item { - + li { + display: block; overflow: hidden; white-space: nowrap; @@ -143,7 +147,7 @@ font-weight: bold; } - .b-sub-folders.collapsed { + ul.collapsed { max-height: 0; height: 0; display: none; @@ -182,45 +186,39 @@ } } - .b-folder-system-item { + .b-folders-system { font-weight: bold; } - .b-sub-folders .e-item a { + li li a { padding-left: @subPadding * 1 + @folderItemPadding; } - .b-sub-folders .b-sub-folders .e-item a { + li li li a { padding-left: @subPadding * 2 + @folderItemPadding; } - .b-sub-folders .b-sub-folders .b-sub-folders .e-item a { + li li li li a { padding-left: @subPadding * 3 + @folderItemPadding; } - .b-sub-folders .b-sub-folders .b-sub-folders .b-sub-folders .e-item a { + li li li li li a { padding-left: @subPadding * 4 + @folderItemPadding; } /**/ - &.single-root-inbox a.i-am-inbox { + &.single-root-inbox .b-folders-user > li > a { display: none !important; } - &.single-root-inbox .i-am-inbox-wrapper > .b-sub-folders { - max-height: none !important; - height: inherit !important; - display: block !important; - } - - &.single-root-inbox .i-am-inbox-wrapper { - .b-sub-folders .e-item a { + &.single-root-inbox { + li li a { padding-left: @folderItemPadding; } - .b-sub-folders .b-sub-folders .e-item a { + li li li a { padding-left: @subPadding * 1 + @folderItemPadding; } - .b-sub-folders .b-sub-folders .b-sub-folders .e-item a { + li li li li a { padding-left: @subPadding * 2 + @folderItemPadding; } - .b-sub-folders .b-sub-folders .b-sub-folders .b-sub-folders .e-item a { + li li li li li a { padding-left: @subPadding * 3 + @folderItemPadding; } } diff --git a/dev/View/Popup/FolderSystem.js b/dev/View/Popup/FolderSystem.js index 31e3e0577..77f5e1ed7 100644 --- a/dev/View/Popup/FolderSystem.js +++ b/dev/View/Popup/FolderSystem.js @@ -2,15 +2,12 @@ import ko from 'ko'; import { SetSystemFoldersNotification } from 'Common/EnumsUser'; import { UNUSED_OPTION_VALUE } from 'Common/Consts'; -import { Settings } from 'Common/Globals'; import { defaultOptionsAfterRender, addSubscribablesTo } from 'Common/Utils'; import { folderListOptionsBuilder } from 'Common/UtilsUser'; import { initOnStartOrLangChange, i18n } from 'Common/Translator'; import { FolderUserStore } from 'Stores/User/Folder'; -import Remote from 'Remote/User/Fetch'; - import { AbstractViewPopup } from 'Knoin/AbstractViews'; class FolderSystemPopupView extends AbstractViewPopup { @@ -43,35 +40,14 @@ class FolderSystemPopupView extends AbstractViewPopup { this.trashFolder = FolderUserStore.trashFolder; this.archiveFolder = FolderUserStore.archiveFolder; - const settingsSet = Settings.set, - fSetSystemFolders = () => { - settingsSet('SentFolder', FolderUserStore.sentFolder()); - settingsSet('DraftFolder', FolderUserStore.draftFolder()); - settingsSet('SpamFolder', FolderUserStore.spamFolder()); - settingsSet('TrashFolder', FolderUserStore.trashFolder()); - settingsSet('ArchiveFolder', FolderUserStore.archiveFolder()); - }, - fSaveSystemFolders = (()=>{ - fSetSystemFolders(); - Remote.saveSystemFolders(()=>0, { - SentFolder: FolderUserStore.sentFolder(), - DraftFolder: FolderUserStore.draftFolder(), - SpamFolder: FolderUserStore.spamFolder(), - TrashFolder: FolderUserStore.trashFolder(), - ArchiveFolder: FolderUserStore.archiveFolder() - }); - }).debounce(1000), - fCallback = () => { - fSetSystemFolders(); - fSaveSystemFolders(); - }; + const fSaveSystemFolders = (()=>FolderUserStore.saveSystemFolders()).debounce(1000); addSubscribablesTo(FolderUserStore, { - sentFolder: fCallback, - draftFolder: fCallback, - spamFolder: fCallback, - trashFolder: fCallback, - archiveFolder: fCallback + sentFolder: fSaveSystemFolders, + draftFolder: fSaveSystemFolders, + spamFolder: fSaveSystemFolders, + trashFolder: fSaveSystemFolders, + archiveFolder: fSaveSystemFolders }); this.defaultOptionsAfterRender = defaultOptionsAfterRender; diff --git a/dev/View/User/MailBox/FolderList.js b/dev/View/User/MailBox/FolderList.js index 9f9b9813f..ed559037a 100644 --- a/dev/View/User/MailBox/FolderList.js +++ b/dev/View/User/MailBox/FolderList.js @@ -32,7 +32,7 @@ export class FolderListMailBoxUserView extends AbstractViewLeft { this.moveAction = moveAction; - this.foldersListWithSingleInboxRootFolder = FolderUserStore.foldersListWithSingleInboxRootFolder; + this.foldersListWithSingleInboxRootFolder = FolderUserStore.singleRootFolder; this.leftPanelDisabled = leftPanelDisabled; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php index d821afc78..e202505d0 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/FolderCollection.php @@ -157,8 +157,7 @@ class FolderCollection extends \MailSo\Base\Collection 'IsSortSupported' => $this->IsSortSupported, 'Optimized' => $this->Optimized, 'CountRec' => $this->CountRec(), - 'SystemFolders' => isset($this->SystemFolders) && \is_array($this->SystemFolders) ? - $this->SystemFolders : array() + 'SystemFolders' => empty($this->SystemFolders) ? null : $this->SystemFolders )); } } diff --git a/snappymail/v/0.0.0/app/templates/Views/User/MailFolderList.html b/snappymail/v/0.0.0/app/templates/Views/User/MailFolderList.html index 01516a173..0fa1be24d 100644 --- a/snappymail/v/0.0.0/app/templates/Views/User/MailFolderList.html +++ b/snappymail/v/0.0.0/app/templates/Views/User/MailFolderList.html @@ -7,9 +7,9 @@ 📇