diff --git a/dev/App/User.js b/dev/App/User.js index becf923ff..36f7f2836 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -187,16 +187,18 @@ class AppUser extends AbstractApp { } MessageUserStore.listLoading(false); }, - FolderUserStore.currentFolderFullNameRaw(), - iOffset, - SettingsUserStore.messagesPerPage(), - MessageUserStore.listSearch(), - MessageUserStore.listThreadUid() + { + Folder: FolderUserStore.currentFolderFullNameRaw(), + Offset: iOffset, + Limit: SettingsUserStore.messagesPerPage(), + Search: MessageUserStore.listSearch(), + UidNext: MessageUserStore.listThreadUid() + } ); } recacheInboxMessageList() { - Remote.messageList(()=>{}, getFolderInboxName(), 0, SettingsUserStore.messagesPerPage(), '', '', true); + Remote.messageList(null, {Folder: getFolderInboxName()}, true); } /** diff --git a/dev/Common/EnumsUser.js b/dev/Common/EnumsUser.js index 19d382c70..9ede882ee 100644 --- a/dev/Common/EnumsUser.js +++ b/dev/Common/EnumsUser.js @@ -14,6 +14,22 @@ export const FolderType = { User: 99 }; +/** + * @enum {string} + */ +export const FolderSortMode = { + DateDesc: '', // default 'REVERSE DATE' + DateAsc: 'DATE', + FromDesc: 'REVERSE FROM', + FromAsc: 'FROM', + SizeDesc: 'REVERSE SIZE', + SizeAsc: 'SIZE', + SubjectDesc: 'REVERSE SUBJECT', + SubjectAsc: 'SUBJECT' +// ToDesc: 'REVERSE TO', +// ToAsc: 'TO', +}; + /** * @enum {string} */ diff --git a/dev/Model/FolderCollection.js b/dev/Model/FolderCollection.js index 017fa37a9..cc172d464 100644 --- a/dev/Model/FolderCollection.js +++ b/dev/Model/FolderCollection.js @@ -113,6 +113,7 @@ export class FolderCollectionModel extends AbstractCollectionModel AppUserStore.threadsAllowed(!!(Settings.app('useImapThread') && this.IsThreadsSupported)); FolderUserStore.folderListOptimized(!!this.Optimized); + FolderUserStore.sortSupported(!!this.IsSortSupported); let update = false; diff --git a/dev/Remote/User/Fetch.js b/dev/Remote/User/Fetch.js index 182f15a23..64bf5704e 100644 --- a/dev/Remote/User/Fetch.js +++ b/dev/Remote/User/Fetch.js @@ -297,54 +297,44 @@ class RemoteUserFetch extends AbstractFetchRemote { /** * @param {Function} fCallback - * @param {string} sFolderFullNameRaw - * @param {number=} iOffset = 0 - * @param {number=} iLimit = 20 - * @param {string=} sSearch = '' - * @param {string=} sThreadUid = '' + * @param {object} params * @param {boolean=} bSilent = false */ - messageList(fCallback, sFolderFullNameRaw, iOffset = 0, iLimit = 20, sSearch = '', sThreadUid = '', bSilent = false) { - sFolderFullNameRaw = pString(sFolderFullNameRaw); - - const folderHash = getFolderHash(sFolderFullNameRaw), - useThreads = AppUserStore.threadsAllowed() && SettingsUserStore.useThreads(), + messageList(fCallback, params, bSilent = false) { + const + sFolderFullNameRaw = pString(params.Folder), + folderHash = getFolderHash(sFolderFullNameRaw), + useThreads = AppUserStore.threadsAllowed() && SettingsUserStore.useThreads() ? 1 : 0, inboxUidNext = getFolderInboxName() === sFolderFullNameRaw ? getFolderUidNext(sFolderFullNameRaw) : ''; - let params = {}, sGetAdd = ''; + params.Folder = sFolderFullNameRaw; + params.ThreadUid = useThreads ? params.ThreadUid : ''; + params = Object.assign({ + Folder: '', + Offset: 0, + Limit: SettingsUserStore.messagesPerPage(), + Search: '', + UidNext: inboxUidNext, + UseThreads: useThreads, + ThreadUid: '', + Sort: FolderUserStore.sortMode() + }, params); - if (folderHash && (!sSearch || !sSearch.includes('is:'))) { + let sGetAdd = ''; + + if (folderHash && (!params.Search || !params.Search.includes('is:'))) { sGetAdd = 'MessageList/' + SUB_QUERY_PREFIX + '/' + - urlsafeArray([ - sFolderFullNameRaw, - iOffset, - iLimit, - sSearch, - SettingsGet('ProjectHash'), - folderHash, - inboxUidNext, - useThreads ? 1 : 0, - useThreads ? sThreadUid : '' - ]); - } else { - params = { - Folder: sFolderFullNameRaw, - Offset: iOffset, - Limit: iLimit, - Search: sSearch, - UidNext: inboxUidNext, - UseThreads: useThreads ? 1 : 0, - ThreadUid: useThreads ? sThreadUid : '' - }; + urlsafeArray([SettingsGet('ProjectHash'),folderHash].concat(Object.values(params))); + params = {}; } this.defaultRequest( fCallback, 'MessageList', params, - sSearch ? 300000 : 30000, + 30000, sGetAdd, bSilent ? [] : ['MessageList'] ); @@ -562,7 +552,7 @@ class RemoteUserFetch extends AbstractFetchRemote { * @param {Object} oData */ sendMessage(fCallback, oData) { - this.defaultRequest(fCallback, 'SendMessage', oData, 300000); + this.defaultRequest(fCallback, 'SendMessage', oData, 30000); } /** diff --git a/dev/Stores/User/Folder.js b/dev/Stores/User/Folder.js index 0cc19c389..34ed105bf 100644 --- a/dev/Stores/User/Folder.js +++ b/dev/Stores/User/Folder.js @@ -1,6 +1,6 @@ import ko from 'ko'; -import { FolderType } from 'Common/EnumsUser'; +import { FolderType, FolderSortMode } from 'Common/EnumsUser'; import { UNUSED_OPTION_VALUE } from 'Common/Consts'; import { addObservablesTo, addSubscribablesTo } from 'Common/Utils'; import { folderListOptionsBuilder } from 'Common/UtilsUser'; @@ -19,6 +19,12 @@ export const FolderUserStore = new class { */ displaySpecSetting: false, + /** + * If the IMAP server supports SORT + */ + sortSupported: false, +// sortMode: '', + sentFolder: '', draftFolder: '', spamFolder: '', @@ -36,6 +42,8 @@ export const FolderUserStore = new class { foldersInboxUnreadCount: 0 }); + this.sortMode = ko.observable('').extend({ limitedList: Object.values(FolderSortMode) }); + this.namespace = ''; this.folderList = ko.observableArray(); diff --git a/dev/Styles/MessageList.less b/dev/Styles/MessageList.less index 2af0a7e51..8a73446de 100644 --- a/dev/Styles/MessageList.less +++ b/dev/Styles/MessageList.less @@ -6,6 +6,11 @@ html.rl-no-preview-pane { } } +#sort-list-dropdown-id { + padding-left: 6px; + padding-right: 6px; +} + .messageList { .toolbar { diff --git a/dev/View/User/MailBox/MessageList.js b/dev/View/User/MailBox/MessageList.js index b1b48ba62..3701cbe93 100644 --- a/dev/View/User/MailBox/MessageList.js +++ b/dev/View/User/MailBox/MessageList.js @@ -74,6 +74,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight { this.messageListDisableAutoSelect = MessageUserStore.listDisableAutoSelect; this.folderList = FolderUserStore.folderList; + this.sortSupported = FolderUserStore.sortSupported; this.composeInEdit = AppUserStore.composeInEdit; this.leftPanelDisabled = leftPanelDisabled; @@ -106,6 +107,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight { this.addObservables({ moveDropdownTrigger: false, moreDropdownTrigger: false, + sortDropdownTrigger: false, dragOverArea: null, dragOverBodyArea: null, @@ -174,7 +176,20 @@ export class MessageListMailBoxUserView extends AbstractViewRight { mobileCheckedStateHide: () => ThemeStore.isMobile() ? !MessageUserStore.listChecked().length : true, - messageListFocused: () => Scope.MessageList === AppUserStore.focusedState() + messageListFocused: () => Scope.MessageList === AppUserStore.focusedState(), + + sortText: () => { + let mode = FolderUserStore.sortMode(); + if ('' === mode) { + return '📅⬇'; + } + mode = mode.split(/\s+/); + return (mode.includes('SIZE') ? '✉' + : (mode.includes('FROM') ? '@' + : (mode.includes('SUBJECT') ? '𝐒' + : '📅'))) + + (mode.includes('REVERSE') ? '⬇' : '⬆'); + } }); this.hasCheckedOrSelectedLines = MessageUserStore.hasCheckedOrSelected, @@ -246,6 +261,11 @@ export class MessageListMailBoxUserView extends AbstractViewRight { }); } + changeSort(self, event) { + FolderUserStore.sortMode(event.target.closest('li').dataset.sort); + this.reloadCommand(); + } + clearCommand() { if (Settings.capa(Capa.DangerousActions)) { showScreenPopup(FolderClearPopupView, [FolderUserStore.currentFolder()]); diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php index 9ea88e869..e6d243c6e 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php @@ -293,6 +293,13 @@ class ImapClient extends \MailSo\Net\NetClient } /** + * Test support for things like: + * IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY + * THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND + * URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED + * I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH + * LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY STATUS=SIZE LITERAL+ NOTIFY SPECIAL-USE + * * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ @@ -596,6 +603,7 @@ class ImapClient extends \MailSo\Net\NetClient } /** + * See https://tools.ietf.org/html/rfc5256 * @throws \MailSo\Base\Exceptions\InvalidArgumentException * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception 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 8db19093f..a6e0a1044 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 @@ -32,6 +32,11 @@ class FolderCollection extends \MailSo\Base\Collection */ public $IsThreadsSupported; + /** + * @var bool + */ + public $IsSortSupported; + /** * @var bool */ @@ -50,6 +55,7 @@ class FolderCollection extends \MailSo\Base\Collection $this->FoldersHash = ''; $this->SystemFolders = array(); $this->IsThreadsSupported = false; + $this->IsSortSupported = false; $this->Optimized = false; } @@ -239,6 +245,7 @@ class FolderCollection extends \MailSo\Base\Collection 'Namespace' => $this->GetNamespace(), 'FoldersHash' => $this->FoldersHash ?: '', 'IsThreadsSupported' => $this->IsThreadsSupported, + 'IsSortSupported' => $this->IsSortSupported, 'Optimized' => $this->Optimized, 'CountRec' => $this->CountRec(), 'SystemFolders' => isset($this->SystemFolders) && \is_array($this->SystemFolders) ? diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php index e7bad6d30..12f25fa8e 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php @@ -1473,8 +1473,47 @@ class MailClient * @throws \MailSo\Net\Exceptions\Exception * @throws \MailSo\Imap\Exceptions\Exception */ - public function GetUids(?\MailSo\Cache\CacheClient $oCacher, string $sSearch, string $sFilter, string $sFolderName, string $sFolderHash, bool $bUseSortIfSupported = false) : array + public function GetUids(?\MailSo\Cache\CacheClient $oCacher, string $sSearch, + string $sFilter, string $sFolderName, string $sFolderHash, + bool $bUseSortIfSupported = false, string $sSort = '') : array { + /* TODO: Validate $sSort + ARRIVAL + Internal date and time of the message. This differs from the + ON criteria in SEARCH, which uses just the internal date. + + CC + [IMAP] addr-mailbox of the first "cc" address. + + DATE + Sent date and time, as described in section 2.2. + + FROM + [IMAP] addr-mailbox of the first "From" address. + + REVERSE + Followed by another sort criterion, has the effect of that + criterion but in reverse (descending) order. + Note: REVERSE only reverses a single criterion, and does not + affect the implicit "sequence number" sort criterion if all + other criteria are identical. Consequently, a sort of + REVERSE SUBJECT is not the same as a reverse ordering of a + SUBJECT sort. This can be avoided by use of additional + criteria, e.g., SUBJECT DATE vs. REVERSE SUBJECT REVERSE + DATE. In general, however, it's better (and faster, if the + client has a "reverse current ordering" command) to reverse + the results in the client instead of issuing a new SORT. + + SIZE + Size of the message in octets. + + SUBJECT + Base subject text. + + TO + [IMAP] addr-mailbox of the first "To" address. + */ + $aResultUids = false; $bUidsFromCacher = false; $bUseCacheAfterSearch = true; @@ -1482,18 +1521,13 @@ class MailClient $sSerializedHash = ''; $sSerializedLog = ''; - $bUseSortIfSupported = $bUseSortIfSupported ? !!$this->oImapClient->IsSupported('SORT') : false; - - if (0 < \strlen($sSearch)) - { - $bUseSortIfSupported = false; - } + $bUseSortIfSupported = $bUseSortIfSupported && !\strlen($sSearch) && $this->oImapClient->IsSupported('SORT'); $sSearchCriterias = $this->getImapSearchCriterias($sSearch, $sFilter, 0, $bUseCacheAfterSearch); if ($bUseCacheAfterSearch && $oCacher && $oCacher->IsInited()) { $sSerializedHash = 'GetUids/'. - ($bUseSortIfSupported ? 'S': 'N').'/'. + ($bUseSortIfSupported ? 'S' . $sSort : 'N').'/'. $this->GenerateImapClientHash().'/'. $sFolderName.'/'.$sSearchCriterias; @@ -1522,7 +1556,7 @@ class MailClient if (!\is_array($aResultUids)) { $aResultUids = $bUseSortIfSupported ? - $this->oImapClient->MessageSimpleSort(array('REVERSE DATE'), $sSearchCriterias, true) : + $this->oImapClient->MessageSimpleSort(array($sSort ?: 'REVERSE DATE'), $sSearchCriterias, true) : $this->oImapClient->MessageSimpleSearch($sSearchCriterias, true, \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? '' : 'UTF-8') ; @@ -1551,7 +1585,7 @@ class MailClient public function MessageList(string $sFolderName, int $iOffset = 0, int $iLimit = 10, string $sSearch = '', string $sPrevUidNext = '', ?\MailSo\Cache\CacheClient $oCacher = null, bool $bUseSortIfSupported = false, bool $bUseThreadSortIfSupported = false, - string $sThreadUid = '', string $sFilter = '') : MessageCollection + string $sThreadUid = '', string $sFilter = '', string $sSort = '') : MessageCollection { $sFilter = \trim($sFilter); $sSearch = \trim($sSearch); @@ -1584,7 +1618,7 @@ class MailClient $sUidNext = '0'; $sHighestModSeq = ''; - $bUseSortIfSupported = $bUseSortIfSupported ? $this->oImapClient->IsSupported('SORT') : false; + $bUseSortIfSupported = $bUseSortIfSupported && $this->oImapClient->IsSupported('SORT'); $bUseThreadSortIfSupported = $bUseThreadSortIfSupported ? ($this->oImapClient->IsSupported('THREAD=REFS') || $this->oImapClient->IsSupported('THREAD=REFERENCES') || $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT')) : false; @@ -1630,7 +1664,7 @@ class MailClient if (0 < $iMessageRealCount && !$bMessageListOptimization) { $mAllSortedUids = $this->GetUids($oCacher, '', $sFilter, - $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported); + $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported, $sSort); $mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap( $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $mAllSortedUids, $oCacher) : null; @@ -2010,6 +2044,8 @@ class MailClient } $oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported(); + + $oFolderCollection->IsSortSupported = $this->oImapClient->IsSupported('SORT'); } return $oFolderCollection; diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php index ec894f8e2..8b8f0352e 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php @@ -24,16 +24,17 @@ trait Messages $sUidNext = ''; $bUseThreads = false; $sThreadUid = ''; + $sSort = ''; $sRawKey = $this->GetActionParam('RawKey', ''); - $aValues = $this->getDecodedClientRawKeyValue($sRawKey, 9); + $aValues = $this->getDecodedClientRawKeyValue($sRawKey, 10); if ($aValues && 7 < \count($aValues)) { - $sFolder =(string) $aValues[0]; - $iOffset = (int) $aValues[1]; - $iLimit = (int) $aValues[2]; - $sSearch = (string) $aValues[3]; + $sFolder = (string) $aValues[2]; + $iOffset = (int) $aValues[3]; + $iLimit = (int) $aValues[4]; + $sSearch = (string) $aValues[5]; $sUidNext = (string) $aValues[6]; $bUseThreads = (bool) $aValues[7]; @@ -42,6 +43,8 @@ trait Messages $sThreadUid = isset($aValues[8]) ? (string) $aValues[8] : ''; } + $sSort = isset($aValues[9]) ? (string) $aValues[9] : ''; + $this->verifyCacheByKey($sRawKey); } else @@ -50,8 +53,9 @@ trait Messages $iOffset = (int) $this->GetActionParam('Offset', 0); $iLimit = (int) $this->GetActionParam('Limit', 10); $sSearch = $this->GetActionParam('Search', ''); + $sSort = $this->GetActionParam('Sort', ''); $sUidNext = $this->GetActionParam('UidNext', ''); - $bUseThreads = '1' === (string) $this->GetActionParam('UseThreads', '0'); + $bUseThreads = !empty($this->GetActionParam('UseThreads', '0')); if ($bUseThreads) { @@ -76,10 +80,11 @@ trait Messages $oMessageList = $this->MailClient()->MessageList( $sFolder, $iOffset, $iLimit, $sSearch, $sUidNext, $this->cacherForUids(), - !!$this->Config()->Get('labs', 'use_imap_sort', false), + !!$this->Config()->Get('labs', 'use_imap_sort', true), $bUseThreads, $sThreadUid, - '' + '', + $sSort ); } catch (\Throwable $oException) diff --git a/snappymail/v/0.0.0/app/localization/webmail/_source.en.yml b/snappymail/v/0.0.0/app/localization/webmail/_source.en.yml index 11a00960a..e5e8a3bde 100644 --- a/snappymail/v/0.0.0/app/localization/webmail/_source.en.yml +++ b/snappymail/v/0.0.0/app/localization/webmail/_source.en.yml @@ -101,6 +101,15 @@ en: YESTERDAY_AT: "yesterday at %TIME%" NEW_MESSAGE_NOTIFICATION: "You have %COUNT% new messages!" QUOTA_SIZE: "Using %SIZE% (%PROC%%) of your %LIMIT%" + SORT: "Sort" + SORT_DATE_ASC: "Date ascending" + SORT_DATE_DESC: "Date descending" + SORT_SIZE_ASC: "Size ascending" + SORT_SIZE_DESC: "Size descending" + SORT_SUBJECT_ASC: "Subject A-Z" + SORT_SUBJECT_DESC: "Subject Z-A" + SORT_FROM_ASC: "From A-Z" + SORT_FROM_DESC: "From Z-A" MESSAGE: BUTTON_EDIT: "Edit" BUTTON_UNSUBSCRIBE: "Unsubscribe from this list" diff --git a/snappymail/v/0.0.0/app/localization/webmail/de_DE.yml b/snappymail/v/0.0.0/app/localization/webmail/de_DE.yml index 93e0ff611..a042e84b7 100644 --- a/snappymail/v/0.0.0/app/localization/webmail/de_DE.yml +++ b/snappymail/v/0.0.0/app/localization/webmail/de_DE.yml @@ -101,6 +101,15 @@ de_DE: YESTERDAY_AT: "Gestern um %TIME%" NEW_MESSAGE_NOTIFICATION: "Sie haben %COUNT% neue Nachrichten!" QUOTA_SIZE: "Sie nutzen %SIZE% (%PROC%%) von %LIMIT%." + SORT: "Sortieren" + SORT_DATE_ASC: "Datum aufsteigend" + SORT_DATE_DESC: "Datum absteigend" + SORT_SIZE_ASC: "Größe aufsteigend" + SORT_SIZE_DESC: "Größe absteigend" + SORT_SUBJECT_ASC: "Betreff A-Z" + SORT_SUBJECT_DESC: "Betreff Z-A" + SORT_FROM_ASC: "Von A-Z" + SORT_FROM_DESC: "Von Z-A" MESSAGE: BUTTON_EDIT: "Bearbeiten" BUTTON_UNSUBSCRIBE: "Diese Liste abbestellen" diff --git a/snappymail/v/0.0.0/app/localization/webmail/en_GB.yml b/snappymail/v/0.0.0/app/localization/webmail/en_GB.yml index 1e7f1fc30..840950b7c 100644 --- a/snappymail/v/0.0.0/app/localization/webmail/en_GB.yml +++ b/snappymail/v/0.0.0/app/localization/webmail/en_GB.yml @@ -101,6 +101,15 @@ en_GB: YESTERDAY_AT: "yesterday at %TIME%" NEW_MESSAGE_NOTIFICATION: "You have %COUNT% new messages!" QUOTA_SIZE: "Using %SIZE% (%PROC%%) of your %LIMIT%" + SORT: "Sort" + SORT_DATE_ASC: "Date ascending" + SORT_DATE_DESC: "Date descending" + SORT_SIZE_ASC: "Size ascending" + SORT_SIZE_DESC: "Size descending" + SORT_SUBJECT_ASC: "Subject A-Z" + SORT_SUBJECT_DESC: "Subject Z-A" + SORT_FROM_ASC: "From A-Z" + SORT_FROM_DESC: "From Z-A" MESSAGE: BUTTON_EDIT: "Edit" BUTTON_UNSUBSCRIBE: "Unsubscribe from this list" diff --git a/snappymail/v/0.0.0/app/localization/webmail/en_US.yml b/snappymail/v/0.0.0/app/localization/webmail/en_US.yml index 6b58bec90..b1bedc535 100644 --- a/snappymail/v/0.0.0/app/localization/webmail/en_US.yml +++ b/snappymail/v/0.0.0/app/localization/webmail/en_US.yml @@ -101,6 +101,15 @@ en_US: YESTERDAY_AT: "yesterday at %TIME%" NEW_MESSAGE_NOTIFICATION: "You have %COUNT% new messages!" QUOTA_SIZE: "Using %SIZE% (%PROC%%) of your %LIMIT%" + SORT: "Sort" + SORT_DATE_ASC: "Date ascending" + SORT_DATE_DESC: "Date descending" + SORT_SIZE_ASC: "Size ascending" + SORT_SIZE_DESC: "Size descending" + SORT_SUBJECT_ASC: "Subject A-Z" + SORT_SUBJECT_DESC: "Subject Z-A" + SORT_FROM_ASC: "From A-Z" + SORT_FROM_DESC: "From Z-A" MESSAGE: BUTTON_EDIT: "Edit" BUTTON_UNSUBSCRIBE: "Unsubscribe from this list" diff --git a/snappymail/v/0.0.0/app/localization/webmail/es_ES.yml b/snappymail/v/0.0.0/app/localization/webmail/es_ES.yml index 17b2bb532..8b0d43ede 100644 --- a/snappymail/v/0.0.0/app/localization/webmail/es_ES.yml +++ b/snappymail/v/0.0.0/app/localization/webmail/es_ES.yml @@ -101,6 +101,15 @@ es_ES: YESTERDAY_AT: "ayer a las %TIME%" NEW_MESSAGE_NOTIFICATION: "Tiene %COUNT% nuevos mensajes." QUOTA_SIZE: "Usando %SIZE% (%PROC%%) de sus %LIMIT%" + SORT: "Ordenar" + SORT_DATE_ASC: "Fecha ascendente" + SORT_DATE_DESC: "Fecha descendente" + SORT_SIZE_ASC: "Tamaño ascendente" + SORT_SIZE_DESC: "Tamaño descendente" + SORT_SUBJECT_ASC: "Asunto A-Z" + SORT_SUBJECT_DESC: "Asunto Z-A" + SORT_FROM_ASC: "Desde A-Z" + SORT_FROM_DESC: "Desde Z-A" MESSAGE: BUTTON_EDIT: "Editar" BUTTON_UNSUBSCRIBE: "Eliminar suscripción de esta lista" diff --git a/snappymail/v/0.0.0/app/localization/webmail/fr_FR.yml b/snappymail/v/0.0.0/app/localization/webmail/fr_FR.yml index a67a06f02..f67640847 100644 --- a/snappymail/v/0.0.0/app/localization/webmail/fr_FR.yml +++ b/snappymail/v/0.0.0/app/localization/webmail/fr_FR.yml @@ -101,6 +101,15 @@ fr_FR: YESTERDAY_AT: "hier à %TIME%" NEW_MESSAGE_NOTIFICATION: "Vous avez %COUNT% nouveaux messages !" QUOTA_SIZE: "Vous utilisez %SIZE% (%PROC%%) sur %LIMIT%" + SORT: "Trier" + SORT_DATE_ASC: "Date ascendante" + SORT_DATE_DESC: "Date décroissante" + SORT_SIZE_ASC: "Taille ascendante" + SORT_SIZE_DESC: "Taille décroissante" + SORT_SUBJECT_ASC: "Sujet A-Z" + SORT_SUBJECT_DESC: "Sujet Z-A" + SORT_FROM_ASC: "De A-Z" + SORT_FROM_DESC: "De Z-A" MESSAGE: BUTTON_EDIT: "Modifier" BUTTON_UNSUBSCRIBE: "Se désinscrire de cette liste" diff --git a/snappymail/v/0.0.0/app/localization/webmail/nl_NL.yml b/snappymail/v/0.0.0/app/localization/webmail/nl_NL.yml index 7bc303307..8a37c4761 100644 --- a/snappymail/v/0.0.0/app/localization/webmail/nl_NL.yml +++ b/snappymail/v/0.0.0/app/localization/webmail/nl_NL.yml @@ -101,6 +101,15 @@ nl_NL: YESTERDAY_AT: "gisteren om %TIME%" NEW_MESSAGE_NOTIFICATION: "U heeft %COUNT% nieuwe berichten!" QUOTA_SIZE: "U gebruikt %SIZE% (%PROC%%) van %LIMIT%" + SORT: "Sorteren" + SORT_DATE_ASC: "Datum oplopend" + SORT_DATE_DESC: "Datum aflopend" + SORT_SIZE_ASC: "Grootte oplopend" + SORT_SIZE_DESC: "Grootte aflopend" + SORT_SUBJECT_ASC: "Onderwerp A-Z" + SORT_SUBJECT_DESC: "Onderwerp Z-A" + SORT_FROM_ASC: "Van A-Z" + SORT_FROM_DESC: "Van Z-A" MESSAGE: BUTTON_EDIT: "Aanpassen" BUTTON_UNSUBSCRIBE: "Abonnement op deze e-mail lijst opzeggen" diff --git a/snappymail/v/0.0.0/app/localization/webmail/zh_CN.yml b/snappymail/v/0.0.0/app/localization/webmail/zh_CN.yml index 37337a3a4..2ff83d1d1 100644 --- a/snappymail/v/0.0.0/app/localization/webmail/zh_CN.yml +++ b/snappymail/v/0.0.0/app/localization/webmail/zh_CN.yml @@ -101,6 +101,15 @@ zh_CN: YESTERDAY_AT: "昨天 %TIME%" NEW_MESSAGE_NOTIFICATION: "您有 %COUNT% 封新邮件!" QUOTA_SIZE: "使用了 %LIMIT% 存储空间中的%SIZE% (%PROC%%)" + SORT: "排序" + SORT_DATE_ASC: "日期升序" + SORT_DATE_DESC: "日期降序" + SORT_SIZE_ASC: "大小递增" + SORT_SIZE_DESC: "大小递减" + SORT_SUBJECT_ASC: "主题 A-Z" + SORT_SUBJECT_DESC: "主题 Z-A" + SORT_FROM_ASC: "发送自 A-Z" + SORT_FROM_DESC: "发送自 Z-A" MESSAGE: BUTTON_EDIT: "编辑" BUTTON_UNSUBSCRIBE: "从此列表中取消订阅" diff --git a/snappymail/v/0.0.0/app/templates/Views/User/MailMessageList.html b/snappymail/v/0.0.0/app/templates/Views/User/MailMessageList.html index 62616d7fc..3a039252f 100644 --- a/snappymail/v/0.0.0/app/templates/Views/User/MailMessageList.html +++ b/snappymail/v/0.0.0/app/templates/Views/User/MailMessageList.html @@ -101,6 +101,59 @@ +