diff --git a/dev/Common/Globals.js b/dev/Common/Globals.js index c7107eb98..4097c5ee3 100644 --- a/dev/Common/Globals.js +++ b/dev/Common/Globals.js @@ -192,10 +192,23 @@ export const VIEW_MODELS = { 'settings-disabled': [] }; +export const moveAction = ko.observable(false); export const leftPanelDisabled = ko.observable(false); export const leftPanelType = ko.observable(''); export const leftPanelWidth = ko.observable(0); +leftPanelDisabled.subscribe((value) => { + if (value && moveAction()) { + moveAction(false); + } +}); + +moveAction.subscribe((value) => { + if (value && leftPanelDisabled()) { + leftPanelDisabled(false); + } +}); + // popups export const popupVisibilityNames = ko.observableArray([]); diff --git a/dev/Screen/User/MailBox.js b/dev/Screen/User/MailBox.js index 1d10a32e9..39792c83b 100644 --- a/dev/Screen/User/MailBox.js +++ b/dev/Screen/User/MailBox.js @@ -2,7 +2,7 @@ import _ from '_'; import {Focused, Capa, ClientSideKeyName, Magics} from 'Common/Enums'; -import {leftPanelDisabled, leftPanelType, bMobileDevice} from 'Common/Globals'; +import {$html, leftPanelDisabled, leftPanelType, moveAction, bMobileDevice} from 'Common/Globals'; import {pString, pInt, decodeURI, windowResizeCallback} from 'Common/Utils'; import {getFolderFromCacheList, getFolderFullNameRaw, getFolderInboxName} from 'Common/Cache'; import {i18n} from 'Common/Translator'; @@ -141,6 +141,10 @@ class MailBoxUserScreen extends AbstractScreen getApp().initHorizontalLayoutResizer(ClientSideKeyName.MessageListSize); }); } + + $html.on('click', '#rl-right', () => { + moveAction(false); + }); } /** diff --git a/dev/Settings/Admin/General.js b/dev/Settings/Admin/General.js index ebbc3f230..ad298e276 100644 --- a/dev/Settings/Admin/General.js +++ b/dev/Settings/Admin/General.js @@ -42,6 +42,7 @@ class GeneralAdminSettings this.allowLanguagesOnSettings = AppAdminStore.allowLanguagesOnSettings; this.weakPassword = AppAdminStore.weakPassword; + this.newMoveToFolder = AppAdminStore.newMoveToFolder; this.mainAttachmentLimit = ko.observable(pInt(settingsGet('AttachmentLimit')) / (Magics.BitLength1024 * Magics.BitLength1024)).extend({posInterer: 25}); @@ -151,6 +152,12 @@ class GeneralAdminSettings 'AllowLanguagesOnSettings': boolToAjax(value) }); }); + + this.newMoveToFolder.subscribe((value) => { + Remote.saveAdminConfig(null, { + 'NewMoveToFolder': boolToAjax(value) + }); + }); }, Magics.Time50ms); } diff --git a/dev/Stores/AbstractApp.js b/dev/Stores/AbstractApp.js index a396857c1..ddfe81dc4 100644 --- a/dev/Stores/AbstractApp.js +++ b/dev/Stores/AbstractApp.js @@ -8,6 +8,7 @@ class AbstractAppStore constructor() { this.allowLanguagesOnSettings = ko.observable(true); this.allowLanguagesOnLogin = ko.observable(true); + this.newMoveToFolder = ko.observable(true); this.interfaceAnimation = ko.observable(true); @@ -25,6 +26,7 @@ class AbstractAppStore populate() { this.allowLanguagesOnLogin(!!Settings.settingsGet('AllowLanguagesOnLogin')); this.allowLanguagesOnSettings(!!Settings.settingsGet('AllowLanguagesOnSettings')); + this.newMoveToFolder(!!Settings.settingsGet('NewMoveToFolder')); this.interfaceAnimation(!!Settings.settingsGet('InterfaceAnimation')); diff --git a/dev/Stores/User/App.js b/dev/Stores/User/App.js index b9eea2391..524e9dfdf 100644 --- a/dev/Stores/User/App.js +++ b/dev/Stores/User/App.js @@ -1,7 +1,8 @@ import ko from 'ko'; import {Focused, KeyState} from 'Common/Enums'; -import {keyScope} from 'Common/Globals'; + +import {keyScope, leftPanelDisabled} from 'Common/Globals'; import {isNonEmptyArray} from 'Common/Utils'; import * as Settings from 'Storage/Settings'; @@ -17,17 +18,28 @@ class AppUserStore extends AbstractAppStore this.focusedState = ko.observable(Focused.None); + const isMobile = Settings.appSettingsGet('mobile'); + this.focusedState.subscribe((value) => { switch (value) { case Focused.MessageList: keyScope(KeyState.MessageList); + if (isMobile) { + leftPanelDisabled(true); + } break; case Focused.MessageView: keyScope(KeyState.MessageView); + if (isMobile) { + leftPanelDisabled(true); + } break; case Focused.FolderList: keyScope(KeyState.FolderList); + if (isMobile) { + leftPanelDisabled(false); + } break; default: break; diff --git a/dev/Styles/FolderList.less b/dev/Styles/FolderList.less index 3e422746b..3a36a5140 100644 --- a/dev/Styles/FolderList.less +++ b/dev/Styles/FolderList.less @@ -4,6 +4,21 @@ .b-folders { + .move-action-content-wrapper { + z-index: -1; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + opacity: 0.05; + background-color: #fff; + background-size: 60px 60px; + background-image: linear-gradient(135deg, #000 25%, transparent 25%, + transparent 50%, #000 50%, #000 75%, + transparent 75%, transparent); + } + &.focused .b-content { } diff --git a/dev/View/User/MailBox/FolderList.js b/dev/View/User/MailBox/FolderList.js index bb253e4da..c482f0aa4 100644 --- a/dev/View/User/MailBox/FolderList.js +++ b/dev/View/User/MailBox/FolderList.js @@ -6,7 +6,7 @@ import key from 'key'; import {trim, isNormal, isArray, windowResize} from 'Common/Utils'; import {Capa, Focused, Layout, KeyState, EventKeyCode, Magics} from 'Common/Enums'; -import {$html, leftPanelDisabled} from 'Common/Globals'; +import {$html, leftPanelDisabled, moveAction} from 'Common/Globals'; import {mailBox, settings} from 'Common/Links'; import {setFolderHash} from 'Common/Cache'; @@ -42,6 +42,8 @@ class FolderListMailBoxUserView extends AbstractViewNext this.folderListSystem = FolderStore.folderListSystem; this.foldersChanging = FolderStore.foldersChanging; + this.moveAction = moveAction; + this.foldersListWithSingleInboxRootFolder = FolderStore.foldersListWithSingleInboxRootFolder; this.leftPanelDisabled = leftPanelDisabled; @@ -71,6 +73,7 @@ class FolderListMailBoxUserView extends AbstractViewNext isMobile = Settings.appSettingsGet('mobile'), fSelectFolder = (el, event, starred) => { + const isMove = moveAction(); if (isMobile) { leftPanelDisabled(true); @@ -86,24 +89,39 @@ class FolderListMailBoxUserView extends AbstractViewNext const folder = ko.dataFor(el); if (folder) { - if (Layout.NoPreview === SettingsStore.layout()) + if (isMove) { - MessageStore.message(null); - } - - if (folder.fullNameRaw === FolderStore.currentFolderFullNameRaw()) - { - setFolderHash(folder.fullNameRaw, ''); - } - - if (starred) - { - setHash(mailBox(folder.fullNameHash, 1, 'is:flagged')); + moveAction(false); + getApp().moveMessagesToFolder( + FolderStore.currentFolderFullNameRaw(), + MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), + folder.fullNameRaw, + false + ); } else { - setHash(mailBox(folder.fullNameHash)); + if (Layout.NoPreview === SettingsStore.layout()) + { + MessageStore.message(null); + } + + if (folder.fullNameRaw === FolderStore.currentFolderFullNameRaw()) + { + setFolderHash(folder.fullNameRaw, ''); + } + + if (starred) + { + setHash(mailBox(folder.fullNameHash, 1, 'is:flagged')); + } + else + { + setHash(mailBox(folder.fullNameHash)); + } } + + AppStore.focusedState(Focused.MessageList); } }; @@ -186,6 +204,7 @@ class FolderListMailBoxUserView extends AbstractViewNext key('esc, tab, shift+tab, right', KeyState.FolderList, () => { AppStore.focusedState(Focused.MessageList); + moveAction(false); return false; }); diff --git a/dev/View/User/MailBox/MessageList.js b/dev/View/User/MailBox/MessageList.js index 2701d871b..c8d7aec4e 100644 --- a/dev/View/User/MailBox/MessageList.js +++ b/dev/View/User/MailBox/MessageList.js @@ -20,7 +20,8 @@ import { import { bMobileDevice, popupVisibility, - leftPanelDisabled + leftPanelDisabled, + moveAction } from 'Common/Globals'; import { @@ -76,6 +77,7 @@ class MessageListMailBoxUserView extends AbstractViewNext this.iGoToUpUpOrDownDownTimeout = 0; this.mobile = !!Settings.appSettingsGet('mobile'); + this.newMoveToFolder = AppStore.newMoveToFolder; this.allowReload = !!Settings.capa(Capa.Reload); this.allowSearch = !!Settings.capa(Capa.Search); @@ -350,6 +352,30 @@ class MessageListMailBoxUserView extends AbstractViewNext @command(canBeMovedHelper) moveCommand() {} // eslint-disable-line no-empty-function + @command(canBeMovedHelper) + moveNewCommand(vm, event) { + if (this.newMoveToFolder() && this.mobileCheckedStateShow()) + { + if (vm && event && event.preventDefault) { + event.preventDefault(); + if (event.stopPropagation) { + event.stopPropagation(); + } + } + + if (moveAction()) + { + AppStore.focusedState(Focused.MessageList); + moveAction(false); + } + else + { + AppStore.focusedState(Focused.FolderList); + moveAction(true); + } + } + } + hideLeft(item, event) { event.preventDefault(); event.stopPropagation(); @@ -869,7 +895,16 @@ class MessageListMailBoxUserView extends AbstractViewNext { // move key('m', KeyState.MessageList, () => { - this.moveDropdownTrigger(true); + + if (this.newMoveToFolder()) + { + this.moveNewCommand(); + } + else + { + this.moveDropdownTrigger(true); + } + return false; }); } diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php index c12ac53d0..ac01f1dec 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -1817,6 +1817,7 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack $sLanguageAdmin = $oConfig->Get('webmail', 'language_admin', 'en'); $sTheme = $oConfig->Get('webmail', 'theme', 'Default'); + $aResult['NewMoveToFolder'] = (bool) $oConfig->Get('interface', 'new_move_to_folder_button', true); $aResult['AllowLanguagesOnSettings'] = (bool) $oConfig->Get('webmail', 'allow_languages_on_settings', true); $aResult['AllowLanguagesOnLogin'] = (bool) $oConfig->Get('login', 'allow_languages_on_login', true); $aResult['AttachmentLimit'] = ((int) $oConfig->Get('webmail', 'attachment_size_limit', 10)) * 1024 * 1024; @@ -3746,6 +3747,8 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack $this->setConfigFromParams($oConfig, 'UseLocalProxyForExternalImages', 'labs', 'use_local_proxy_for_external_images', 'bool'); + $this->setConfigFromParams($oConfig, 'NewMoveToFolder', 'interface', 'new_move_to_folder_button', 'bool'); + $this->setConfigFromParams($oConfig, 'AllowLanguagesOnSettings', 'webmail', 'allow_languages_on_settings', 'bool'); $this->setConfigFromParams($oConfig, 'AllowLanguagesOnLogin', 'login', 'allow_languages_on_login', 'bool'); $this->setConfigFromParams($oConfig, 'AttachmentLimit', 'webmail', 'attachment_size_limit', 'int'); diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php index e6e624936..8e38cd224 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php @@ -160,7 +160,8 @@ class Application extends \RainLoop\Config\AbstractConfig 'interface' => array( 'show_attachment_thumbnail' => array(true, ''), - 'use_native_scrollbars' => array(false) + 'use_native_scrollbars' => array(false), + 'new_move_to_folder_button' => array(true) ), 'branding' => array( diff --git a/rainloop/v/0.0.0/app/localization/admin/_source.en.yml b/rainloop/v/0.0.0/app/localization/admin/_source.en.yml index d5e29597e..de025ab37 100644 --- a/rainloop/v/0.0.0/app/localization/admin/_source.en.yml +++ b/rainloop/v/0.0.0/app/localization/admin/_source.en.yml @@ -26,6 +26,7 @@ en: LABEL_ALLOW_LANGUAGES_ON_SETTINGS: "Allow language selection on settings screen" LABEL_ALLOW_THEMES_ON_SETTINGS: "Allow theme selection on settings screen" LABEL_ALLOW_BACKGROUND_ON_SETTINGS: "Allow background selection on settings screen" + LABEL_NEW_FOLDER_MOVE: "New \"move to folder\" button" LABEL_SHOW_THUMBNAILS: "Show thumbnails (attachments)" LABEL_ALLOW_GRAVATAR: "Allow Gravatar" LEGEND_MAIN: "Main" diff --git a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsGeneral.html b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsGeneral.html index de03fc6cb..a297c34a2 100644 --- a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsGeneral.html +++ b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsGeneral.html @@ -1,164 +1,171 @@ -