Skip to content

Commit

Permalink
feat: add filtering of archived conversations
Browse files Browse the repository at this point in the history
- show ongoing calls in archived conversations, if 'notify about calls' is truthy

Signed-off-by: Maksim Sukharev <[email protected]>
(cherry picked from commit 19286fd)
  • Loading branch information
Antreesy committed Oct 11, 2024
1 parent 559c979 commit 7db9382
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 21 deletions.
71 changes: 54 additions & 17 deletions src/components/LeftSidebar/LeftSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@
<template #icon>
<AtIcon v-if="isFiltered === 'mentions'" :size="64" />
<MessageBadge v-else-if="isFiltered === 'unread'" :size="64" />
<IconArchive v-else-if="showArchived" :size="64" />
<MessageOutline v-else :size="64" />
</template>
<template #action>
Expand Down Expand Up @@ -277,6 +278,27 @@

<template #footer>
<div class="left-sidebar__settings-button-container">
<template v-if="supportsArchive">
<NcButton v-if="showArchived"
type="tertiary"
wide
@click="showArchived = false">
<template #icon>
<IconArrowLeft :size="20" />
</template>
{{ t('spreed', 'Back to conversations') }}
</NcButton>
<NcButton v-else-if="archivedConversationsList.length"
type="tertiary"
wide
@click="showArchived = true">
<template #icon>
<IconArchive :size="20" />
</template>
{{ t('spreed', 'Archived conversations') }}
</NcButton>
</template>

<NcButton type="tertiary" wide @click="showSettings">
<template #icon>
<Cog :size="20" />
Expand All @@ -293,6 +315,8 @@ import debounce from 'debounce'
import { ref } from 'vue'
import AccountMultiplePlus from 'vue-material-design-icons/AccountMultiplePlus.vue'
import IconArchive from 'vue-material-design-icons/Archive.vue'
import IconArrowLeft from 'vue-material-design-icons/ArrowLeft.vue'
import AtIcon from 'vue-material-design-icons/At.vue'
import ChatPlus from 'vue-material-design-icons/ChatPlus.vue'
import Cog from 'vue-material-design-icons/Cog.vue'
Expand Down Expand Up @@ -348,7 +372,7 @@ import { talkBroadcastChannel } from '../../services/talkBroadcastChannel.js'
import { useFederationStore } from '../../stores/federation.ts'
import { useTalkHashStore } from '../../stores/talkHash.js'
import CancelableRequest from '../../utils/cancelableRequest.js'
import { hasUnreadMentions, filterFunction } from '../../utils/conversation.js'
import { hasUnreadMentions, hasCall, filterFunction } from '../../utils/conversation.js'
import { requestTabLeadership } from '../../utils/requestTabLeadership.js'
const isFederationEnabled = getTalkConfig('local', 'federation', 'enabled')
Expand All @@ -357,6 +381,7 @@ const canModerateSipDialOut = hasTalkFeature('local', 'sip-support-dialout')
&& getTalkConfig('local', 'call', 'sip-dialout-enabled')
&& getTalkConfig('local', 'call', 'can-enable-sip')
const canNoteToSelf = hasTalkFeature('local', 'note-to-self')
const supportsArchive = hasTalkFeature('local', 'archived-conversations')
export default {
name: 'LeftSidebar',
Expand Down Expand Up @@ -388,6 +413,8 @@ export default {
MessageOutline,
FilterIcon,
FilterRemoveIcon,
IconArchive,
IconArrowLeft,
Phone,
Plus,
ChatPlus,
Expand All @@ -402,6 +429,8 @@ export default {
const searchBox = ref(null)
const scroller = ref(null)
const showArchived = ref(false)
const federationStore = useFederationStore()
const talkHashStore = useTalkHashStore()
const { initializeNavigation, resetNavigation } = useArrowNavigation(leftSidebar, searchBox)
Expand All @@ -419,6 +448,8 @@ export default {
isMobile,
canModerateSipDialOut,
canNoteToSelf,
supportsArchive,
showArchived,
}
},
Expand Down Expand Up @@ -491,6 +522,9 @@ export default {
},
emptyContentDescription() {
if (this.showArchived) {
return t('spreed', 'You have no archived conversations.')
}
switch (this.isFiltered) {
case 'mentions':
return t('spreed', 'You have no unread mentions.')
Expand All @@ -501,27 +535,27 @@ export default {
}
},
archivedConversationsList() {
return this.$store.getters.archivedConversationsList
},
filteredConversationsList() {
if (this.isFocused) {
return this.conversationsList
}
// applying filters
if (this.isFiltered) {
let validConversationsCount = 0
const filteredConversations = this.conversationsList.filter((conversation) => {
const conversationIsValid = filterFunction(this.isFiltered, conversation)
if (conversationIsValid) {
validConversationsCount++
}
return conversationIsValid
|| conversation.hasCall
|| conversation.token === this.token
})
// return empty if it only includes the current conversation without any flags
return validConversationsCount === 0 && !this.isNavigating ? [] : filteredConversations
}
return this.conversationsList
let validConversationsCount = 0
const filteredConversations = this.conversationsList.filter((conversation) => {
const conversationIsValid = filterFunction(this.isFiltered, this.showArchived, conversation)
if (conversationIsValid) {
validConversationsCount++
}
return conversationIsValid
|| hasCall(conversation)
|| conversation.token === this.token
})
// return empty if it only includes the current conversation without any flags
return validConversationsCount === 0 && !this.isNavigating ? [] : filteredConversations
},
isSearching() {
Expand Down Expand Up @@ -1076,6 +1110,9 @@ export default {
}
.left-sidebar__settings-button-container {
display: flex;
flex-direction: column;
gap: var(--default-grid-baseline);
padding: calc(2 * var(--default-grid-baseline));
}
Expand Down
10 changes: 10 additions & 0 deletions src/store/conversationsStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ const getters = {
return conversation2.lastActivity - conversation1.lastActivity
})
},
/**
* List of all archived conversations sorted
*
* @param {object} state state
* @param {object} getters getters
* @return {object[]} sorted conversations list
*/
archivedConversationsList: (state, getters) => {
return getters.conversationsList.filter(conversation => conversation.isArchived)
},
/**
* Get a conversation providing its token
*
Expand Down
52 changes: 48 additions & 4 deletions src/utils/conversation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { CONVERSATION } from '../constants.js'
import { CONVERSATION, PARTICIPANT } from '../constants.js'
import { hasTalkFeature } from '../services/CapabilitiesManager.ts'

const supportsArchive = hasTalkFeature('local', 'archived-conversations')

/**
* check if the conversation has unread messages
Expand All @@ -27,16 +30,57 @@ export function hasUnreadMentions(conversation) {
&& (conversation.type === CONVERSATION.TYPE.ONE_TO_ONE || conversation.type === CONVERSATION.TYPE.ONE_TO_ONE_FORMER))
}

/**
* check if the conversation has ongoing call
*
* @param {object} conversation conversation object
* @return {boolean}
*/
export function hasCall(conversation) {
return conversation.hasCall && (!isArchived(conversation) || conversation.notificationCalls === PARTICIPANT.NOTIFY_CALLS.ON)
}

/**
* check if the conversation is archived
*
* @param {object} conversation conversation object
* @return {boolean}
*/
export function isArchived(conversation) {
return conversation.isArchived
}

/**
* check if the conversation passes default validation:
* - non-archived
* - archived, but have an unread message with notification triggered
*
* @param {object} conversation conversation object
* @return {boolean}
*/
export function isDefault(conversation) {
return !isArchived(conversation)
|| (conversation.notificationLevel === PARTICIPANT.NOTIFY.ALWAYS && hasUnreadMessages(conversation))
|| (conversation.notificationLevel === PARTICIPANT.NOTIFY.MENTION && hasUnreadMentions(conversation))
}

/**
* apply the active filter
*
* @param {string} filter the filter option
* @param {string} archived the archived filter option
* @param {object} conversation conversation object
*/
export function filterFunction(filter, conversation) {
export function filterFunction(filter, archived, conversation) {
const shouldIncludeArchived = supportsArchive
? (archived ? isArchived(conversation) : isDefault(conversation))
: true

if (filter === 'unread') {
return hasUnreadMessages(conversation)
return shouldIncludeArchived && hasUnreadMessages(conversation)
} else if (filter === 'mentions') {
return hasUnreadMentions(conversation)
return shouldIncludeArchived && hasUnreadMentions(conversation)
} else {
return shouldIncludeArchived
}
}

0 comments on commit 7db9382

Please sign in to comment.