diff --git a/lib/Contracts/IMailSearch.php b/lib/Contracts/IMailSearch.php index 161aadaa40..078bcf4bdd 100644 --- a/lib/Contracts/IMailSearch.php +++ b/lib/Contracts/IMailSearch.php @@ -46,6 +46,7 @@ public function findMessage(Account $account, /** * @param Account $account * @param Mailbox $mailbox + * @param string $sortOrder * @param string|null $filter * @param int|null $cursor * @param int|null $limit @@ -56,10 +57,11 @@ public function findMessage(Account $account, * @throws ServiceException */ public function findMessages(Account $account, - Mailbox $mailbox, - ?string $filter, - ?int $cursor, - ?int $limit): array; + Mailbox $mailbox, + string $sortOrder, + ?string $filter, + ?int $cursor, + ?int $limit): array; /** * @param IUser $user diff --git a/lib/Controller/MessagesController.php b/lib/Controller/MessagesController.php index 70643270a4..2d993fa6d8 100755 --- a/lib/Controller/MessagesController.php +++ b/lib/Controller/MessagesController.php @@ -39,6 +39,7 @@ use OCA\Mail\Contracts\IMailSearch; use OCA\Mail\Contracts\IMailTransmission; use OCA\Mail\Contracts\ITrustedSenderService; +use OCA\Mail\Contracts\IUserPreferences; use OCA\Mail\Db\Message; use OCA\Mail\Exception\ClientException; use OCA\Mail\Exception\ServiceException; @@ -86,6 +87,7 @@ class MessagesController extends Controller { private SmimeService $smimeService; private IMAPClientFactory $clientFactory; private IDkimService $dkimService; + private IUserPreferences $preferences; public function __construct(string $appName, IRequest $request, @@ -104,7 +106,8 @@ public function __construct(string $appName, IMailTransmission $mailTransmission, SmimeService $smimeService, IMAPClientFactory $clientFactory, - IDkimService $dkimService) { + IDkimService $dkimService, + IUserPreferences $preferences) { parent::__construct($appName, $request); $this->accountService = $accountService; $this->mailManager = $mailManager; @@ -122,6 +125,7 @@ public function __construct(string $appName, $this->smimeService = $smimeService; $this->clientFactory = $clientFactory; $this->dkimService = $dkimService; + $this->preferences = $preferences; } /** @@ -149,12 +153,14 @@ public function index(int $mailboxId, return new JSONResponse([], Http::STATUS_FORBIDDEN); } - $this->logger->debug("loading messages of folder <$mailboxId>"); + $this->logger->debug("loading messages of mailbox <$mailboxId>"); + $order = $this->preferences->getPreference($this->currentUserId, 'sort-order', 'newest') === 'newest' ? 'DESC': 'ASC'; return new JSONResponse( $this->mailSearch->findMessages( $account, $mailbox, + $order, $filter === '' ? null : $filter, $cursor, $limit diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index 2f9e27e492..c76dd4945f 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -162,6 +162,11 @@ public function index(): TemplateResponse { $this->tagMapper->getAllTagsForUser($this->currentUserId) ); + $this->initialStateService->provideInitialState( + 'sort-order', + $this->preferences->getPreference($this->currentUserId, 'sort-order', 'newest') + ); + try { $password = $this->credentialStore->getLoginCredentials()->getPassword(); $passwordIsUnavailable = $password === null || $password === ''; diff --git a/lib/Db/MessageMapper.php b/lib/Db/MessageMapper.php index 82e21f2aec..17d63acc48 100644 --- a/lib/Db/MessageMapper.php +++ b/lib/Db/MessageMapper.php @@ -695,11 +695,11 @@ public function findByMessageId(Account $account, string $messageId): array { * @param Mailbox $mailbox * @param SearchQuery $query * @param int|null $limit - * @param int[]|null $uids + * @param int[]|null $uidsa * * @return int[] */ - public function findIdsByQuery(Mailbox $mailbox, SearchQuery $query, ?int $limit, array $uids = null): array { + public function findIdsByQuery(Mailbox $mailbox, SearchQuery $query, string $sortOrder, ?int $limit, array $uids = null): array { $qb = $this->db->getQueryBuilder(); if ($this->needDistinct($query)) { @@ -820,7 +820,11 @@ public function findIdsByQuery(Mailbox $mailbox, SearchQuery $query, ?int $limit $select->andWhere($qb->expr()->isNull('m2.id')); - $select->orderBy('m.sent_at', 'desc'); + if ($sortOrder === 'ASC') { + $select->orderBy('sent_at', $sortOrder); + } else { + $select->orderBy('sent_at', 'DESC'); + } if ($limit !== null) { $select->setMaxResults($limit); @@ -1074,10 +1078,11 @@ public function findByMailboxAndIds(Mailbox $mailbox, string $userId, array $ids /** * @param string $userId * @param int[] $ids + * @param string $sortOrder * * @return Message[] */ - public function findByIds(string $userId, array $ids): array { + public function findByIds(string $userId, array $ids, string $sortOrder): array { if ($ids === []) { return []; } @@ -1088,7 +1093,7 @@ public function findByIds(string $userId, array $ids): array { ->where( $qb->expr()->in('id', $qb->createParameter('ids')) ) - ->orderBy('sent_at', 'desc'); + ->orderBy('sent_at', $sortOrder); $results = []; foreach (array_chunk($ids, 1000) as $chunk) { diff --git a/lib/Service/Search/MailSearch.php b/lib/Service/Search/MailSearch.php index c6e25f653f..f325f34fe4 100644 --- a/lib/Service/Search/MailSearch.php +++ b/lib/Service/Search/MailSearch.php @@ -92,6 +92,7 @@ public function findMessage(Account $account, /** * @param Account $account * @param Mailbox $mailbox + * @param string $sortOrder * @param string|null $filter * @param int|null $cursor * @param int|null $limit @@ -103,6 +104,7 @@ public function findMessage(Account $account, */ public function findMessages(Account $account, Mailbox $mailbox, + string $sortOrder, ?string $filter, ?int $cursor, ?int $limit): array { @@ -130,7 +132,8 @@ public function findMessages(Account $account, $account, $mailbox, $this->messageMapper->findByIds($account->getUserId(), - $this->getIdsLocally($account, $mailbox, $query, $limit) + $this->getIdsLocally($account, $mailbox, $query, $sortOrder, $limit), + $sortOrder, ) ); } @@ -164,9 +167,9 @@ public function findMessagesGlobally(IUser $user, * * @throws ServiceException */ - private function getIdsLocally(Account $account, Mailbox $mailbox, SearchQuery $query, ?int $limit): array { + private function getIdsLocally(Account $account, Mailbox $mailbox, SearchQuery $query, string $sortOrder, ?int $limit): array { if (empty($query->getTextTokens())) { - return $this->messageMapper->findIdsByQuery($mailbox, $query, $limit); + return $this->messageMapper->findIdsByQuery($mailbox, $query, $sortOrder, $limit); } $fromImap = $this->imapSearchProvider->findMatches( @@ -174,7 +177,7 @@ private function getIdsLocally(Account $account, Mailbox $mailbox, SearchQuery $ $mailbox, $query ); - return $this->messageMapper->findIdsByQuery($mailbox, $query, $limit, $fromImap); + return $this->messageMapper->findIdsByQuery($mailbox, $query, $sortOrder, $limit, $fromImap); } /** diff --git a/src/components/AppSettingsMenu.vue b/src/components/AppSettingsMenu.vue index 4029afa5cb..4eb0873721 100644 --- a/src/components/AppSettingsMenu.vue +++ b/src/components/AppSettingsMenu.vue @@ -99,6 +99,33 @@ +

+ Sorting +

+
+ + {{ t('mail', 'Newest') }} + + + {{ t('mail', 'Oldest') }} + +

{{ t('mail', 'Looking for a way to encrypt your emails?') }} @@ -116,7 +143,7 @@ import { generateUrl } from '@nextcloud/router' import { showError } from '@nextcloud/dialogs' -import { NcButton as ButtonVue, NcLoadingIcon as IconLoading } from '@nextcloud/vue' +import { NcButton as ButtonVue, NcLoadingIcon as IconLoading, NcCheckboxRadioSwitch as CheckboxRadioSwitch } from '@nextcloud/vue' import IconInfo from 'vue-material-design-icons/Information' import IconAdd from 'vue-material-design-icons/Plus' @@ -137,6 +164,7 @@ export default { IconLoading, IconLock, SmimeCertificateModal, + CheckboxRadioSwitch, }, data() { return { @@ -152,6 +180,7 @@ export default { autoTaggingText: t('mail', 'Automatically classify importance of new email'), toggleAutoTagging: false, displaySmimeCertificateModal: false, + sortOrder: 'newest', } }, computed: { @@ -171,6 +200,9 @@ export default { return this.$store.getters.getPreference('allow-new-accounts', true) }, }, + mounted() { + this.sortOrder = this.$store.getters.getPreference('sort-order', 'newest') + }, methods: { onToggleButtonReplies(e) { this.loadingReplySettings = true @@ -211,6 +243,21 @@ export default { this.loadingOptOutSettings = false }) }, + async onSortByDate(e) { + const previousValue = this.sortOrder + try { + this.sortOrder = e + await this.$store + .dispatch('savePreference', { + key: 'sort-order', + value: e, + }) + } catch (error) { + Logger.error('could not save preferences', { error }) + this.sortOrder = previousValue + showError(t('mail', 'Could not update preference')) + } + }, async onToggleAutoTagging(e) { this.toggleAutoTagging = true @@ -307,4 +354,15 @@ p.app-settings { } } +.section-title { + margin-top: 20px; + margin-bottom: 10px; +} +.sorting { + display: flex; + width: 100%; + &__switch{ + width: 50%; + } +} diff --git a/src/components/EnvelopeList.vue b/src/components/EnvelopeList.vue index 2f09b2fb6b..0d409005a3 100644 --- a/src/components/EnvelopeList.vue +++ b/src/components/EnvelopeList.vue @@ -179,7 +179,7 @@ { + return a.dateInt < b.dateInt ? -1 : 1 + }) + } + return [...this.envelopes] + }, selectMode() { // returns true when in selection mode (where the user selects several emails at once) return this.selection.length > 0 @@ -307,15 +319,15 @@ export default { return this.selectedEnvelopes.every((env) => env.flags.flagged === true) }, selectedEnvelopes() { - return this.envelopes.filter((env) => this.selection.includes(env.databaseId)) + return this.sortedEnvelops.filter((env) => this.selection.includes(env.databaseId)) }, hasMultipleAccounts() { - const mailboxIds = this.envelopes.map(envelope => envelope.mailboxId) + const mailboxIds = this.sortedEnvelops.map(envelope => envelope.mailboxId) return Array.from(new Set(mailboxIds)).length > 1 }, }, watch: { - envelopes(newVal, oldVal) { + sortedEnvelops(newVal, oldVal) { // Unselect vanished envelopes const newIds = newVal.map((env) => env.databaseId) this.selection = this.selection.filter((id) => newIds.includes(id)) @@ -381,7 +393,7 @@ export default { let nextEnvelopeToNavigate let isAllSelected - if (this.selectedEnvelopes.length === this.envelopes.length) { + if (this.selectedEnvelopes.length === this.sortedEnvelops.length) { isAllSelected = true } else { const indexSelectedEnvelope = this.selectedEnvelopes.findIndex((selectedEnvelope) => @@ -390,7 +402,7 @@ export default { // one of threads is selected if (indexSelectedEnvelope !== -1) { const lastSelectedEnvelope = this.selectedEnvelopes[this.selectedEnvelopes.length - 1] - const diff = this.envelopes.filter(envelope => envelope === lastSelectedEnvelope || !this.selectedEnvelopes.includes(envelope)) + const diff = this.sortedEnvelops.filter(envelope => envelope === lastSelectedEnvelope || !this.selectedEnvelopes.includes(envelope)) const lastIndex = diff.indexOf(lastSelectedEnvelope) nextEnvelopeToNavigate = diff[lastIndex === 0 ? 1 : lastIndex - 1] } @@ -460,12 +472,12 @@ export default { const end = Math.max(this.lastToggledIndex, index) const selected = this.selection.includes(envelope.databaseId) for (let i = start; i <= end; i++) { - this.setEnvelopeSelected(this.envelopes[i], !selected) + this.setEnvelopeSelected(this.sortedEnvelops[i], !selected) } this.lastToggledIndex = index }, unselectAll() { - this.envelopes.forEach((env) => { + this.sortedEnvelops.forEach((env) => { env.flags.selected = false }) this.selection = [] diff --git a/src/components/Mailbox.vue b/src/components/Mailbox.vue index ea095509ee..cee4999913 100644 --- a/src/components/Mailbox.vue +++ b/src/components/Mailbox.vue @@ -125,6 +125,9 @@ export default { } }, computed: { + sortOrder() { + return this.$store.getters.getPreference('sort-order', 'DESC') + }, envelopes() { return this.$store.getters.getEnvelopes(this.mailbox.databaseId, this.searchQuery) }, @@ -176,6 +179,9 @@ export default { searchQuery() { this.loadEnvelopes() }, + sortOrder() { + this.loadEnvelopes() + }, }, created() { this.bus.$on('load-more', this.onScroll) diff --git a/src/main.js b/src/main.js index 8cfde4903f..6e2ab597ec 100644 --- a/src/main.js +++ b/src/main.js @@ -66,6 +66,12 @@ store.commit('savePreference', { key: 'ncVersion', value: loadState('mail', 'ncVersion'), }) + +store.commit('savePreference', { + key: 'sort-order', + value: loadState('mail', 'sort-order', 'newest'), +}) + store.commit('savePreference', { key: 'attachment-size-limit', value: Number.parseInt(getPreferenceFromPage('attachment-size-limit'), 10),