2727 class="filters"
2828 :class =" { ' hidden-visually' : isSearching } " >
2929 <template #icon >
30- <IconFilterOutline :size =" 20 " />
30+ <IconFilterCogOutline :size =" 20 " />
3131 </template >
3232 <NcActionCaption :name =" t (' spreed' , ' Filter conversations by' )" />
3333
7474 </template >
7575 {{ t('spreed', 'Clear filters') }}
7676 </NcActionButton >
77+
78+ <template v-if =" supportSortOrder " >
79+ <NcActionSeparator />
80+
81+ <NcActionCaption :name =" SORT_LABELS .SORTBY_HEADER " />
82+
83+ <NcActionButton
84+ closeAfterClick
85+ type="radio"
86+ :value =" CONVERSATION .SORT_ORDER .ACTIVITY "
87+ :modelValue =" sortOrder "
88+ @update :modelValue =" handleSortOrder " >
89+ <template #icon >
90+ <IconClockOutline :size =" 20 " />
91+ </template >
92+ {{ SORT_LABELS.SORTBY_ACTIVITY }}
93+ </NcActionButton >
94+
95+ <NcActionButton
96+ closeAfterClick
97+ type="radio"
98+ :value =" CONVERSATION .SORT_ORDER .ALPHABETICAL "
99+ :modelValue =" sortOrder "
100+ @update :modelValue =" handleSortOrder " >
101+ <template #icon >
102+ <IconSortAlphabeticalAscending :size =" 20 " />
103+ </template >
104+ {{ SORT_LABELS.SORTBY_ALPHABET }}
105+ </NcActionButton >
106+
107+ <NcActionSeparator />
108+
109+ <NcActionButton
110+ closeAfterClick
111+ type="radio"
112+ :value =" CONVERSATION .GROUP_MODE .NONE "
113+ :modelValue =" groupMode "
114+ @update :modelValue =" handleGroupMode " >
115+ <template #icon >
116+ <IconFormatListBulleted :size =" 20 " />
117+ </template >
118+ {{ SORT_LABELS.GROUPBY_NONE }}
119+ </NcActionButton >
120+
121+ <NcActionButton
122+ closeAfterClick
123+ type="radio"
124+ :value =" CONVERSATION .GROUP_MODE .PRIVATE_FIRST "
125+ :modelValue =" groupMode "
126+ @update :modelValue =" handleGroupMode " >
127+ <template #icon >
128+ <IconAccountOutline :size =" 20 " />
129+ </template >
130+ {{ SORT_LABELS.GROUPBY_PRIVATE_FIRST }}
131+ </NcActionButton >
132+
133+ <NcActionButton
134+ closeAfterClick
135+ type="radio"
136+ :value =" CONVERSATION .GROUP_MODE .GROUP_FIRST "
137+ :modelValue =" groupMode "
138+ @update :modelValue =" handleGroupMode " >
139+ <template #icon >
140+ <IconAccountMultipleOutline :size =" 20 " />
141+ </template >
142+ {{ SORT_LABELS.GROUPBY_GROUP_FIRST }}
143+ </NcActionButton >
144+ </template >
77145 </NcActions >
78146 </TransitionWrapper >
79147
@@ -310,21 +378,25 @@ import { START_LOCATION } from 'vue-router'
310378import NcActionButton from ' @nextcloud/vue/components/NcActionButton'
311379import NcActionCaption from ' @nextcloud/vue/components/NcActionCaption'
312380import NcActions from ' @nextcloud/vue/components/NcActions'
381+ import NcActionSeparator from ' @nextcloud/vue/components/NcActionSeparator'
313382import NcAppNavigation from ' @nextcloud/vue/components/NcAppNavigation'
314383import NcAppNavigationCaption from ' @nextcloud/vue/components/NcAppNavigationCaption'
315384import NcAppNavigationItem from ' @nextcloud/vue/components/NcAppNavigationItem'
316385import NcButton from ' @nextcloud/vue/components/NcButton'
317386import NcChip from ' @nextcloud/vue/components/NcChip'
318387import NcCounterBubble from ' @nextcloud/vue/components/NcCounterBubble'
319388import NcEmptyContent from ' @nextcloud/vue/components/NcEmptyContent'
389+ import IconAccountMultipleOutline from ' vue-material-design-icons/AccountMultipleOutline.vue'
320390import IconAccountMultiplePlusOutline from ' vue-material-design-icons/AccountMultiplePlusOutline.vue'
391+ import IconAccountOutline from ' vue-material-design-icons/AccountOutline.vue'
321392import IconArchiveOutline from ' vue-material-design-icons/ArchiveOutline.vue'
322393import IconArrowLeft from ' vue-material-design-icons/ArrowLeft.vue'
323394import IconAt from ' vue-material-design-icons/At.vue'
324395import IconCalendarBlankOutline from ' vue-material-design-icons/CalendarBlankOutline.vue'
325396import IconChatPlusOutline from ' vue-material-design-icons/ChatPlusOutline.vue'
397+ import IconClockOutline from ' vue-material-design-icons/ClockOutline.vue'
326398import IconCogOutline from ' vue-material-design-icons/CogOutline.vue'
327- import IconFilterOutline from ' vue-material-design-icons/FilterOutline .vue'
399+ import IconFilterCogOutline from ' vue-material-design-icons/FilterCogOutline .vue'
328400import IconFilterRemoveOutline from ' vue-material-design-icons/FilterRemoveOutline.vue'
329401import IconFormatListBulleted from ' vue-material-design-icons/FormatListBulleted.vue'
330402import IconForumOutline from ' vue-material-design-icons/ForumOutline.vue'
@@ -334,6 +406,7 @@ import IconMessageOutline from 'vue-material-design-icons/MessageOutline.vue'
334406import IconNoteEditOutline from ' vue-material-design-icons/NoteEditOutline.vue'
335407import IconPhoneOutline from ' vue-material-design-icons/PhoneOutline.vue'
336408import IconPlus from ' vue-material-design-icons/Plus.vue'
409+ import IconSortAlphabeticalAscending from ' vue-material-design-icons/SortAlphabeticalAscending.vue'
337410import NewConversationDialog from ' ../NewConversationDialog/NewConversationDialog.vue'
338411import ThreadItem from ' ../RightSidebar/Threads/ThreadItem.vue'
339412import LoadingPlaceholder from ' ../UIShared/LoadingPlaceholder.vue'
@@ -375,6 +448,7 @@ const canModerateSipDialOut = hasTalkFeature('local', 'sip-support-dialout')
375448const canNoteToSelf = hasTalkFeature (' local' , ' note-to-self' )
376449const supportsArchive = hasTalkFeature (' local' , ' archived-conversations-v2' )
377450const supportThreads = hasTalkFeature (' local' , ' threads' )
451+ const supportSortOrder = getTalkConfig (' local' , ' conversations' , ' sort-order' ) !== undefined
378452
379453// TRANSLATORS The main home view
380454const HOME_BUTTON_LABEL = t (' spreed' , ' Home' )
@@ -384,6 +458,21 @@ const FILTER_LABELS = {
384458 events: t (' spreed' , ' Meetings' ),
385459 default: ' ' ,
386460}
461+ const SORT_LABELS = {
462+ // TRANSLATORS Navigation actions: sort conversations by recent activity / sort alphabetically
463+ SORTBY_HEADER : t (' spreed' , ' Sort conversations' ),
464+ // TRANSLATORS Navigation actions: sort conversations by recent activity / sort alphabetically
465+ SORTBY_ACTIVITY : t (' spreed' , ' By recent activity' ),
466+ // TRANSLATORS Navigation actions: sort conversations by recent activity / sort alphabetically
467+ SORTBY_ALPHABET : t (' spreed' , ' Alphabetically' ),
468+
469+ // TRANSLATORS Navigation actions: arrange list by putting private or group conversations on top
470+ GROUPBY_NONE : t (' spreed' , ' Do not group by type' ),
471+ // TRANSLATORS Navigation actions: arrange list by putting private or group conversations on top
472+ GROUPBY_PRIVATE_FIRST : t (' spreed' , ' Show private ones first' ),
473+ // TRANSLATORS Navigation actions: arrange list by putting private or group conversations on top
474+ GROUPBY_GROUP_FIRST : t (' spreed' , ' Show group ones first' ),
475+ }
387476
388477let actualizeDataTimeout = null
389478
@@ -407,6 +496,8 @@ export default {
407496 NcActions,
408497 NcActionButton,
409498 NcActionCaption,
499+ NcActionSeparator,
500+ NcEmptyContent,
410501 TransitionWrapper,
411502 ConversationsListVirtual,
412503 SearchConversationsResults,
@@ -415,7 +506,7 @@ export default {
415506 IconAt,
416507 IconMessageBadgeOutline,
417508 IconMessageOutline,
418- IconFilterOutline ,
509+ IconFilterCogOutline ,
419510 IconFilterRemoveOutline,
420511 IconArchiveOutline,
421512 IconArrowLeft,
@@ -428,7 +519,10 @@ export default {
428519 IconCogOutline,
429520 IconFormatListBulleted,
430521 IconNoteEditOutline,
431- NcEmptyContent,
522+ IconSortAlphabeticalAscending,
523+ IconClockOutline,
524+ IconAccountMultipleOutline,
525+ IconAccountOutline,
432526 },
433527
434528 setup () {
@@ -461,11 +555,14 @@ export default {
461555 canNoteToSelf,
462556 supportsArchive,
463557 supportThreads,
558+ supportSortOrder,
464559 showArchived,
465560 showThreadsList,
466561 settingsStore,
562+ CONVERSATION ,
467563 HOME_BUTTON_LABEL ,
468564 FILTER_LABELS ,
565+ SORT_LABELS ,
469566 actorStore: useActorStore (),
470567 chatExtrasStore: useChatExtrasStore (),
471568 tokenStore: useTokenStore (),
@@ -502,16 +599,47 @@ export default {
502599 },
503600
504601 computed: {
602+ sortOrder () {
603+ return this .settingsStore .sortOrder
604+ },
605+
606+ groupMode () {
607+ return this .settingsStore .groupMode
608+ },
609+
505610 conversationsList () {
506611 return this .$store .getters .conversationsList
507612 },
508613
509614 sortedConversationsList () {
510615 return this .filteredConversationsList .slice ()
511616 .sort ((conversation1 , conversation2 ) => {
617+ // Favorites always first
512618 if (conversation1 .isFavorite !== conversation2 .isFavorite ) {
513619 return conversation1 .isFavorite ? - 1 : 1
514620 }
621+
622+ if (this .groupMode !== CONVERSATION .GROUP_MODE .NONE ) {
623+ const isOneToOne1 = [CONVERSATION .TYPE .ONE_TO_ONE , CONVERSATION .TYPE .ONE_TO_ONE_FORMER ].includes (conversation1 .type )
624+ const isOneToOne2 = [CONVERSATION .TYPE .ONE_TO_ONE , CONVERSATION .TYPE .ONE_TO_ONE_FORMER ].includes (conversation2 .type )
625+
626+ if (isOneToOne1 !== isOneToOne2) {
627+ if (this .groupMode === CONVERSATION .GROUP_MODE .GROUP_FIRST ) {
628+ // Group mode: groups first
629+ return isOneToOne1 ? 1 : - 1
630+ } else if (this .groupMode === CONVERSATION .GROUP_MODE .PRIVATE_FIRST ) {
631+ // Group mode: private first
632+ return isOneToOne1 ? - 1 : 1
633+ }
634+ }
635+ }
636+
637+ // Sort order: by alphabet A->Z
638+ if (this .sortOrder === CONVERSATION .SORT_ORDER .ALPHABETICAL ) {
639+ return (conversation1 .displayName ).localeCompare (conversation2 .displayName )
640+ }
641+
642+ // Default (legacy) sort order: by recent activity
515643 return conversation2 .lastActivity - conversation1 .lastActivity
516644 })
517645 },
@@ -728,6 +856,14 @@ export default {
728856 this .$refs .invitationHandler .showModal ()
729857 },
730858
859+ handleSortOrder (newValue ) {
860+ this .settingsStore .updateSortOrder (newValue)
861+ },
862+
863+ handleGroupMode (newValue ) {
864+ this .settingsStore .updateGroupMode (newValue)
865+ },
866+
731867 handleFilter (filter ) {
732868 // Store the active filter
733869 if (filter === null ) {
0 commit comments