Skip to content

Commit 3aef38d

Browse files
authored
Merge pull request #10494 from nextcloud/fix/5907/virtual-scroll-participants
feat(ParticipantsTab) - virtual scrolling for participants list
2 parents 0724e0c + 1ff6968 commit 3aef38d

5 files changed

Lines changed: 123 additions & 17 deletions

File tree

src/components/AvatarWrapper/AvatarWrapper.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
{{ firstLetterOfGuestName }}
3838
</div>
3939
<NcAvatar v-else
40+
:key="id"
4041
:user="id"
4142
:display-name="name"
4243
:menu-container="menuContainerWithFallback"

src/components/RightSidebar/Participants/ParticipantsList/Participant/Participant.vue

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
-->
2121

2222
<template>
23-
<li :data-nav-id="`${participant.source}_${participant.id}`"
23+
<component :is="tag"
24+
:data-nav-id="participantNavigationId"
2425
class="participant-row"
2526
:class="{
2627
'offline': isOffline,
@@ -201,7 +202,7 @@
201202
@close="hidePermissionsEditor" />
202203
<!-- Checkmark in case the current participant is selected -->
203204
<div v-if="isSelected" class="icon-checkmark participant-row__utils utils__checkmark" />
204-
</li>
205+
</component>
205206
</template>
206207

207208
<script>
@@ -275,6 +276,11 @@ export default {
275276
],
276277
277278
props: {
279+
tag: {
280+
type: String,
281+
default: 'li',
282+
},
283+
278284
participant: {
279285
type: Object,
280286
required: true,
@@ -320,6 +326,14 @@ export default {
320326
return this.$store.getters.getMainContainerSelector()
321327
},
322328
329+
participantNavigationId() {
330+
if (this.participant.actorType && this.participant.actorId) {
331+
return this.participant.actorType + '_' + this.participant.actorId
332+
} else {
333+
return this.participant.source + '_' + this.participant.id
334+
}
335+
},
336+
323337
participantSettingsAriaLabel() {
324338
return t('spreed', 'Settings for participant "{user}"', { user: this.computedName })
325339
},

src/components/RightSidebar/Participants/ParticipantsList/ParticipantsList.vue

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,15 @@
2020
-->
2121

2222
<template>
23-
<div>
24-
<ul>
25-
<Participant v-for="item in items"
26-
:key="generateKey(item)"
27-
:participant="item"
28-
:is-selectable="participantsSelectable"
29-
:show-user-status="showUserStatus"
30-
@click-participant="handleClickParticipant" />
31-
</ul>
23+
<ul>
24+
<Participant v-for="item in items"
25+
:key="generateKey(item)"
26+
:participant="item"
27+
:is-selectable="participantsSelectable"
28+
:show-user-status="showUserStatus"
29+
@click-participant="handleClickParticipant" />
3230
<LoadingPlaceholder v-if="loading" type="participants" :count="dummyParticipants" />
33-
</div>
31+
</ul>
3432
</template>
3533

3634
<script>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<!--
2+
- @copyright Copyright (c) 2023 Maksim Sukharev <antreesy.web@gmail.com>
3+
-
4+
- @author Grigorii Shartsev <me@shgk.me>
5+
-
6+
- @license AGPL-3.0-or-later
7+
-
8+
- This program is free software: you can redistribute it and/or modify
9+
- it under the terms of the GNU Affero General Public License as
10+
- published by the Free Software Foundation, either version 3 of the
11+
- License, or (at your option) any later version.
12+
-
13+
- This program is distributed in the hope that it will be useful,
14+
- but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
- GNU Affero General Public License for more details.
17+
-
18+
- You should have received a copy of the GNU Affero General Public License
19+
- along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
-->
21+
22+
<template>
23+
<RecycleScroller ref="scroller"
24+
list-tag="ul"
25+
item-tag="li"
26+
:items="participants"
27+
:item-size="PARTICIPANT_ITEM_SIZE"
28+
key-field="attendeeId">
29+
<template #default="{ item }">
30+
<Participant :participant="item" tag="div" />
31+
</template>
32+
<template v-if="loading" #after>
33+
<LoadingPlaceholder type="participants" :count="dummyParticipants" />
34+
</template>
35+
</RecycleScroller>
36+
</template>
37+
38+
<script>
39+
import { RecycleScroller } from 'vue-virtual-scroller'
40+
41+
import LoadingPlaceholder from '../../../LoadingPlaceholder.vue'
42+
import Participant from './Participant/Participant.vue'
43+
44+
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
45+
46+
const PARTICIPANT_ITEM_SIZE = 64
47+
48+
export default {
49+
name: 'ParticipantsListVirtual',
50+
51+
components: {
52+
LoadingPlaceholder,
53+
Participant,
54+
RecycleScroller,
55+
},
56+
57+
props: {
58+
participants: {
59+
type: Array,
60+
required: true,
61+
},
62+
63+
loading: {
64+
type: Boolean,
65+
default: false,
66+
},
67+
},
68+
69+
setup() {
70+
return {
71+
PARTICIPANT_ITEM_SIZE,
72+
}
73+
},
74+
75+
computed: {
76+
dummyParticipants() {
77+
const dummies = 6 - this.participants.length
78+
return dummies > 0 ? dummies : 0
79+
},
80+
},
81+
}
82+
</script>

src/components/RightSidebar/Participants/ParticipantsTab.vue

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,19 @@
2020
-->
2121

2222
<template>
23-
<div>
23+
<div class="wrapper">
2424
<SearchBox v-if="canSearch"
2525
:value.sync="searchText"
2626
:is-focused.sync="isFocused"
2727
:placeholder-text="searchBoxPlaceholder"
2828
@input="handleInput"
2929
@abort-search="abortSearch" />
3030

31-
<ParticipantsList v-if="!isSearching"
32-
:items="participants"
31+
<ParticipantsListVirtual v-if="!isSearching"
32+
:participants="participants"
3333
:loading="!participantsInitialised" />
3434

35-
<template v-else>
35+
<div v-else class="scroller">
3636
<NcAppNavigationCaption v-if="canAdd" :title="t('spreed', 'Participants')" />
3737

3838
<ParticipantsList v-if="filteredParticipants.length"
@@ -46,7 +46,7 @@
4646
:no-results="noResults"
4747
:search-text="searchText"
4848
@click="addParticipants" />
49-
</template>
49+
</div>
5050
</div>
5151
</template>
5252

@@ -62,6 +62,7 @@ import NcAppNavigationCaption from '@nextcloud/vue/dist/Components/NcAppNavigati
6262
import Hint from '../../Hint.vue'
6363
import SearchBox from '../../LeftSidebar/SearchBox/SearchBox.vue'
6464
import ParticipantsList from './ParticipantsList/ParticipantsList.vue'
65+
import ParticipantsListVirtual from './ParticipantsList/ParticipantsListVirtual.vue'
6566
import ParticipantsSearchResults from './ParticipantsSearchResults/ParticipantsSearchResults.vue'
6667
6768
import { useSortParticipants } from '../../../composables/useSortParticipants.js'
@@ -75,6 +76,7 @@ import CancelableRequest from '../../../utils/cancelableRequest.js'
7576
export default {
7677
name: 'ParticipantsTab',
7778
components: {
79+
ParticipantsListVirtual,
7880
ParticipantsList,
7981
Hint,
8082
NcAppNavigationCaption,
@@ -264,6 +266,15 @@ export default {
264266
</script>
265267
266268
<style scoped>
269+
.wrapper {
270+
display: flex;
271+
flex-direction: column;
272+
height: 100%;
273+
}
274+
275+
.scroller {
276+
overflow-y: auto;
277+
}
267278
268279
/** TODO: fix these in the nextcloud-vue library **/
269280

0 commit comments

Comments
 (0)