Skip to content

Commit

Permalink
FEATURE: Implements multiple envelopes selection
Browse files Browse the repository at this point in the history
#2273

Signed-off-by: Cyrille Bollu <cyrpub@bollu.be>
  • Loading branch information
StCyr committed Mar 25, 2020
1 parent 53b51b5 commit eec162f
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 1 deletion.
22 changes: 21 additions & 1 deletion src/components/Envelope.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@
@click.prevent="onToggleFlagged"
></div>
<div class="app-content-list-item-icon">
<Avatar :display-name="addresses" :email="avatarEmail" />
<div v-if="selectMode">
<Actions>
<ActionCheckbox :checked="selected" @click.prevent="$emit('select', data)">{{
selected ? t('mail', 'Unselect') : t('mail', 'Select')
}}</ActionCheckbox>
</Actions>
</div>
<Avatar v-else :display-name="addresses" :email="avatarEmail" />
</div>
<div class="app-content-list-item-line-one" :title="addresses">
{{ addresses }}
Expand All @@ -29,6 +36,9 @@
<Moment :timestamp="data.dateInt" />
</div>
<Actions class="app-content-list-item-menu" menu-align="right">
<ActionButton icon="icon-checkmark" @click.prevent="$emit('select', data)">{{
selected ? t('mail', 'Unselect') : t('mail', 'Select')
}}</ActionButton>
<ActionButton icon="icon-starred" @click.prevent="onToggleFlagged">{{
data.flags.flagged ? t('mail', 'Unfavorite') : t('mail', 'Favorite')
}}</ActionButton>
Expand All @@ -43,6 +53,7 @@
<script>
import Actions from '@nextcloud/vue/dist/Components/Actions'
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
import ActionCheckbox from '@nextcloud/vue/dist/Components/ActionCheckbox'
import Moment from './Moment'
import Avatar from './Avatar'
Expand All @@ -53,6 +64,7 @@ export default {
components: {
Actions,
ActionButton,
ActionCheckbox,
Avatar,
Moment,
},
Expand All @@ -65,6 +77,14 @@ export default {
type: Object,
required: true,
},
selectMode: {
type: Boolean,
default: false,
},
selected: {
type: Boolean,
default: false,
},
},
computed: {
accountColor() {
Expand Down
107 changes: 107 additions & 0 deletions src/components/EnvelopeList.vue
Original file line number Diff line number Diff line change
@@ -1,25 +1,49 @@
<template>
<div>
<div v-if="selectMode" class="multiselect-header">
<div>
<b>{{ 'Unselect ' + selection.length }}</b>
</div>
<Actions class="app-content-list-item-menu" menu-align="right">
<ActionButton icon="icon-mail" @click.prevent="markSelectedSeenOrUnseen(false)">
{{ t('mail', 'Mark read') }}
</ActionButton>
<ActionButton icon="icon-mail" @click.prevent="markSelectedSeenOrUnseen(true)">
{{ t('mail', 'Mark unread') }}
</ActionButton>
<ActionButton icon="icon-delete" @click.prevent="deleteAllSelected">
{{ t('mail', 'Delete') }}
</ActionButton>
</Actions>
</div>
<transition-group name="list">
<div id="list-refreshing" key="loading" class="icon-loading-small" :class="{refreshing: refreshing}" />
<Envelope
v-for="env in envelopes"
:key="env.uid"
:data="env"
:folder="folder"
:selected="isEnvelopeSelected(envelopes.indexOf(env))"
:select-mode="selectMode"
@delete="$emit('delete', env.uid)"
@select="onEnvelopeSelect"
/>
<div id="load-more-mail-messages" key="loadingMore" :class="{'icon-loading-small': loadingMore}" />
</transition-group>
</div>
</template>

<script>
import Actions from '@nextcloud/vue/dist/Components/Actions'
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
import Envelope from './Envelope'
export default {
name: 'EnvelopeList',
components: {
Actions,
ActionButton,
Envelope,
},
props: {
Expand All @@ -38,16 +62,99 @@ export default {
refreshing: {
type: Boolean,
required: true,
default: true,
},
loadingMore: {
type: Boolean,
required: true,
},
},
data() {
return {
shortkeys: {
del: ['del'],
flag: ['s'],
next: ['arrowright'],
prev: ['arrowleft'],
refresh: ['r'],
unseen: ['u'],
},
selection: [],
}
},
computed: {
selectMode() {
// returns true when in selection mode (where the user selects several emails at once)
return this.selection.length > 0
},
},
methods: {
markSelectedSeenOrUnseen(seenFlag) {
this.selection.forEach(envelopeId => {
this.$store.dispatch('markEnvelopeSeenOrUnseen', {
envelope: this.envelopes[envelopeId],
seenFlag: seenFlag,
})
})
this.selection = []
},
deleteAllSelected() {
this.selection.forEach(envelopeId => {
// Navigate if the message beeing deleted is the one currently viewed
if (this.envelopes[envelopeId].uid == this.$route.params.messageUid) {
let next
if (envelopeId === 0) {
next = this.envelopes[envelopeId + 1]
} else {
next = this.envelopes[envelopeId - 1]
}
if (next) {
this.$router.push({
name: 'message',
params: {
accountId: this.$route.params.accountId,
folderId: this.$route.params.folderId,
messageUid: next.uid,
},
})
}
}
this.$store.dispatch('deleteMessage', this.envelopes[envelopeId])
})
this.selection = []
},
isEnvelopeSelected(idx) {
if (this.selection.length == 0) {
return false
}
return this.selection.includes(idx)
},
onEnvelopeSelect(envelope) {
const idx = this.envelopes.indexOf(envelope)
if (this.selection.indexOf(idx) == -1) {
this.selection.push(idx)
} else {
this.selection.splice(this.selection.indexOf(idx), 1)
}
return
},
},
}
</script>

<style scoped>
.multiselect-header {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
background-color: var(--color-main-background-translucent);
}
#load-more-mail-messages {
margin: 10px auto;
padding: 10px;
Expand Down
20 changes: 20 additions & 0 deletions src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,26 @@ export default {
})
})
},
markEnvelopeSeenOrUnseen({commit, getters}, {envelope, seenFlag}) {
// Change immediately and switch back on error
const oldState = envelope.flags.unseen
commit('flagEnvelope', {
envelope,
flag: 'unseen',
value: seenFlag,
})

setEnvelopeFlag(envelope.accountId, envelope.folderId, envelope.id, 'unseen', seenFlag).catch(e => {
console.error('could not mark message ' + envelope.uid + ' seen/unseen', e)

// Revert change
commit('flagEnvelope', {
envelope,
flag: 'unseen',
value: oldState,
})
})
},
fetchMessage({commit}, uid) {
const {accountId, folderId, id} = parseUid(uid)
return fetchMessage(accountId, folderId, id).then((message) => {
Expand Down

0 comments on commit eec162f

Please sign in to comment.