Skip to content

Commit f823beb

Browse files
committed
Merge branch 'perf-improvements' into develop, thus fixing #49
2 parents 07592e9 + 5cb6394 commit f823beb

32 files changed

+1019
-456
lines changed

mobile/src/App.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<ion-app>
2+
<ion-app :style="animationVariables">
33
<ion-router-outlet />
44
</ion-app>
55
<pwa-reload-prompt />
@@ -9,6 +9,12 @@
99
import { IonApp, IonRouterOutlet } from '@ionic/vue';
1010
import PwaReloadPrompt from "@/components/PwaReloadPrompt.vue";
1111
import {useDevUtilities} from "@/state/useDevUtilities";
12+
import {TimeslotAnimations} from "@/services/Animations";
13+
14+
const animationVariables = {
15+
'--app-voxxrin-animations-timeslots-anim-base-delay': `${TimeslotAnimations.ANIMATION_BASE_DELAY.total('milliseconds')}ms`,
16+
'--app-voxxrin-animations-timeslots-anim-duration': `${TimeslotAnimations.ANIMATION_DURATION.total('milliseconds')}ms`,
17+
}
1218
1319
useDevUtilities();
1420
</script>

mobile/src/components/events/EventTabs.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
IonRouterOutlet,
2121
} from '@ionic/vue';
2222
import {ComponentPublicInstance, PropType, watch} from "vue";
23-
import {managedRef as ref} from "@/views/vue-utils";
23+
import {managedRef as ref, toManagedRef as toRef} from "@/views/vue-utils";
2424
import {useRoute} from "vue-router";
2525
import {EventId} from "@/models/VoxxrinEvent";
2626
import {useTabbedPageNav} from "@/state/useTabbedPageNav";
@@ -41,7 +41,7 @@ const props = defineProps({
4141
}
4242
})
4343
44-
const {conferenceDescriptor: confDescriptor} = useSharedConferenceDescriptor(props.eventId);
44+
const {conferenceDescriptor: confDescriptor} = useSharedConferenceDescriptor(toRef(() => props.eventId));
4545
4646
const { registerTabbedPageNavListeners } = useTabbedPageNav();
4747
registerTabbedPageNavListeners();

mobile/src/components/feedbacks/FeedbackTalkSelector.vue

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
<talk-format-groups-breakdown :conf-descriptor="confDescriptor" :talks="displayedTalks">
44
<template #talk="{ talk }">
55
<ion-item class="listTalks-item">
6-
<schedule-talk :talk="talk" @talkClicked="updateSelected($event)" :is-highlighted="(talk, talkNotes) => talk.id.isSameThan(selectedTalkId)" :conf-descriptor="confDescriptor">
6+
<schedule-talk :talk="talk" :talk-stats="talkStatsRefByTalkId.get(talk.id.value)" :talk-notes="userTalkNotesRefByTalkId.get(talk.id.value)"
7+
:is-highlighted="(talk, talkNotes) => talk.id.isSameThan(selectedTalkId)" :conf-descriptor="confDescriptor"
8+
@talkClicked="updateSelected($event)" >
79
<template #upper-right="{ talk, talkNotes }">
8-
<talk-is-favorited :talk-notes="talkNotes.value" />
10+
<talk-is-favorited :talk-notes="talkNotes" />
911
</template>
10-
<template #footer-actions="{ talk, userTalkHook }">
11-
<talk-watch-later-button :user-talk-notes="userTalkHook" :conf-descriptor="confDescriptor"></talk-watch-later-button>
12+
<template #footer-actions="{ talk, talkNotes, talkStats }">
13+
<talk-watch-later-button :user-talk-notes="talkNotes" :conf-descriptor="confDescriptor"></talk-watch-later-button>
1214
<talk-select-for-feedback :is-active="talk.id.isSameThan(selectedTalkId)" @click.stop="() => updateSelected(talk)"></talk-select-for-feedback>
1315
</template>
1416
</schedule-talk>
@@ -24,8 +26,8 @@
2426
</template>
2527

2628
<script setup lang="ts">
27-
import {computed, PropType, Ref, unref} from "vue";
28-
import {managedRef as ref} from "@/views/vue-utils";
29+
import {computed, PropType, Ref, toValue} from "vue";
30+
import {managedRef as ref, toManagedRef as toRef} from "@/views/vue-utils";
2931
import {TalkId, VoxxrinTalk} from "@/models/VoxxrinTalk";
3032
import TalkFormatGroupsBreakdown from "@/components/schedule/TalkFormatGroupsBreakdown.vue";
3133
import {VoxxrinConferenceDescriptor} from "@/models/VoxxrinConferenceDescriptor";
@@ -34,6 +36,8 @@ import TalkWatchLaterButton from "@/components/talk-card/TalkWatchLaterButton.vu
3436
import TalkSelectForFeedback from "@/components/talk-card/TalkSelectForFeedback.vue";
3537
import ScheduleTalk from "@/components/talk-card/ScheduleTalk.vue";
3638
import TalkIsFavorited from "@/components/talk-card/TalkIsFavorited.vue";
39+
import {useEventTalkStats} from "@/state/useEventTalkStats";
40+
import {useUserEventTalkNotes} from "@/state/useUserTalkNotes";
3741
3842
const { LL } = typesafeI18n()
3943
@@ -61,6 +65,12 @@ const emits = defineEmits<{
6165
(e: 'talk-deselected', talk: VoxxrinTalk): void,
6266
}>()
6367
68+
const eventId = toRef(() => props.confDescriptor?.id);
69+
const talkIdsRef = toRef(() => props.talks?.map(talk => talk.id));
70+
71+
const {firestoreEventTalkStatsRef: talkStatsRefByTalkId} = useEventTalkStats(eventId, talkIdsRef)
72+
const {userEventTalkNotesRef: userTalkNotesRefByTalkId} = useUserEventTalkNotes(eventId, talkIdsRef)
73+
6474
function updateSelected(talk: VoxxrinTalk) {
6575
if(talk.id.isSameThan(props.selectedTalkId)) {
6676
emits('talk-deselected', talk);
@@ -72,10 +82,10 @@ function updateSelected(talk: VoxxrinTalk) {
7282
const showUnfavoritedTalksRef = ref<boolean>(false);
7383
7484
const displayedTalks: Ref<VoxxrinTalk[]> = computed(() => {
75-
const showUnfavoritedTalks = unref(showUnfavoritedTalksRef),
76-
allUserFavoritedTalkIds = props.allUserFavoritedTalkIds;
85+
const showUnfavoritedTalks = toValue(showUnfavoritedTalksRef),
86+
allUserFavoritedTalkIds = toValue(props.allUserFavoritedTalkIds);
7787
78-
if(!props.talks) {
88+
if(!props.talks || !allUserFavoritedTalkIds) {
7989
return []
8090
}
8191

mobile/src/components/talk-card/ScheduleTalk.vue

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616

1717
<div class="middle">
1818
<div class="item">
19-
<slot name="upper-middle" :talk="talk" :talkNotes="userTalkNotesHook.talkNotes" :talkStats="userTalkNotesHook.eventTalkStats" :userTalkHook="userTalkNotesHook"></slot>
19+
<slot name="upper-middle" :talk="talk" :talkNotes="talkNotes" :talkStats="talkStats"></slot>
2020
</div>
2121
</div>
2222

2323
<div class="end">
2424
<div class="item">
25-
<slot name="upper-right" :talk="talk" :talkNotes="userTalkNotesHook.talkNotes" :talkStats="userTalkNotesHook.eventTalkStats" :userTalkHook="userTalkNotesHook"></slot>
25+
<slot name="upper-right" :talk="talk" :talkNotes="talkNotes" :talkStats="talkStats"></slot>
2626
</div>
2727
</div>
2828
</div>
@@ -53,15 +53,15 @@
5353
<span class="speakers-list">{{displayedSpeakers}}</span>
5454
</div>
5555
<div class="talkActions">
56-
<slot name="footer-actions" :talk="talk" :talkNotes="userTalkNotesHook.talkNotes" :talkStats="userTalkNotesHook.eventTalkStats" :userTalkHook="userTalkNotesHook" />
56+
<slot name="footer-actions" :talk="talk" :talkNotes="talkNotes" :talkStats="talkStats" />
5757
</div>
5858
</div>
5959
</ion-card>
6060
</template>
6161

6262
<script setup lang="ts">
6363
import {computed, PropType} from "vue";
64-
import {managedRef as ref} from "@/views/vue-utils";
64+
import {managedRef as ref, toManagedRef as toRef} from "@/views/vue-utils";
6565
import {
6666
IonBadge,
6767
IonThumbnail,
@@ -70,8 +70,7 @@ import { VoxxrinTalk} from "@/models/VoxxrinTalk";
7070
import {useRoute} from "vue-router";
7171
import {EventId} from "@/models/VoxxrinEvent";
7272
import {getRouteParamsValue} from "@/views/vue-utils";
73-
import {UserTalkNotesHook, useUserTalkNotes} from "@/state/useUserTalkNotes";
74-
import {TalkNote} from "../../../../shared/feedbacks.firestore";
73+
import {TalkNote, TalkStats} from "../../../../shared/feedbacks.firestore";
7574
import {VoxxrinConferenceDescriptor} from "@/models/VoxxrinConferenceDescriptor";
7675
7776
const baseUrl = import.meta.env.BASE_URL;
@@ -94,6 +93,14 @@ const props = defineProps({
9493
required: true,
9594
type: Object as PropType<VoxxrinConferenceDescriptor>
9695
},
96+
talkStats: {
97+
required: false,
98+
type: Object as PropType<TalkStats|undefined>
99+
},
100+
talkNotes: {
101+
required: false,
102+
type: Object as PropType<TalkNote|undefined>
103+
}
97104
})
98105
99106
defineEmits<{
@@ -107,9 +114,6 @@ const talkLang = computed(() => {
107114
const route = useRoute();
108115
const eventId = ref(new EventId(getRouteParamsValue(route, 'eventId')));
109116
110-
const userTalkNotesHook: UserTalkNotesHook = useUserTalkNotes(eventId, props.talk?.id)
111-
const { talkNotes } = userTalkNotesHook;
112-
113117
const displayedSpeakers = props.talk!.speakers
114118
.map(s => `${s.fullName}${s.companyName?` (${s.companyName})`:``}`)
115119
.join(", ") || "???";

mobile/src/components/talk-card/TalkFavoriteButton.vue

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div class="talkAction">
3-
<ion-button :class="{ 'btnTalk': true, 'btn-favorite': true, '_is-active': !!talkNotes?.isFavorite }" @click.stop="() => userTalkNotes.toggleFavorite()" v-if="confDescriptor?.features.favoritesEnabled">
3+
<ion-button :class="{ 'btnTalk': true, 'btn-favorite': true, '_is-active': !!talkNotes?.isFavorite }" @click.stop="() => toggleFavorite()" v-if="confDescriptor?.features.favoritesEnabled">
44
<span class="btn-favorite-group">
55
<ion-icon class="btn-favorite-group-icon" v-if="!talkNotes?.isFavorite" aria-hidden="true" src="/assets/icons/line/bookmark-line-favorite.svg"></ion-icon>
66
<ion-icon class="btn-favorite-group-icon" v-if="!!talkNotes?.isFavorite" aria-hidden="true" src="/assets/icons/solid/bookmark-favorite.svg"></ion-icon>
@@ -11,23 +11,41 @@
1111
</template>
1212

1313
<script setup lang="ts">
14-
import {computed, PropType} from "vue";
15-
import type {UserTalkNotesHook} from "@/state/useUserTalkNotes";
14+
import {computed, PropType, Ref, toValue} from "vue";
1615
import {VoxxrinConferenceDescriptor} from "@/models/VoxxrinConferenceDescriptor";
16+
import {useUserTalkNoteActions} from "@/state/useUserTalkNotes";
17+
import {managedRef as ref, toManagedRef as toRef} from "@/views/vue-utils";
18+
import {TalkId} from "@/models/VoxxrinTalk";
19+
import {TalkNote, TalkStats} from "../../../../shared/feedbacks.firestore";
1720
1821
const props = defineProps({
1922
confDescriptor: {
2023
required: true,
2124
type: Object as PropType<VoxxrinConferenceDescriptor>,
2225
},
26+
talkStats: {
27+
required: false,
28+
type: Object as PropType<TalkStats|undefined>
29+
},
2330
userTalkNotes: {
2431
required: true,
25-
type: Object as PropType<UserTalkNotesHook>
32+
type: Object as PropType<TalkNote>
2633
}
2734
});
2835
29-
const talkNotes = computed(() => props.userTalkNotes?.talkNotes.value)
30-
const eventTalkStats = computed(() => props.userTalkNotes?.eventTalkStats.value)
36+
const emits = defineEmits<{
37+
(e: 'talkNoteUpdated', updatedTalkNote: TalkNote): void,
38+
}>()
39+
40+
const talkNotes: Ref<TalkNote|undefined> = toRef(() => props.userTalkNotes);
41+
42+
const eventTalkStats = computed(() => props.talkStats)
43+
const {toggleFavorite} = useUserTalkNoteActions(
44+
toRef(() => props.confDescriptor?.id),
45+
toRef(() => props.userTalkNotes?.talkId ? new TalkId(props.userTalkNotes.talkId) : undefined),
46+
talkNotes,
47+
(updatedTalkNote) => emits('talkNoteUpdated', updatedTalkNote)
48+
)
3149
</script>
3250

3351
<style scoped lang="scss">

mobile/src/components/talk-card/TalkWatchLaterButton.vue

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
<template>
22
<div class="talkAction">
3-
<ion-button :class="{ 'btnTalk': true, 'btn-watchLater': true, '_is-active': !!talkNotes?.watchLater }" @click.stop="() => userTalkNotes.toggleWatchLater()" v-if="confDescriptor?.features.remindMeOnceVideosAreAvailableEnabled">
3+
<ion-button :class="{ 'btnTalk': true, 'btn-watchLater': true, '_is-active': !!talkNotes?.watchLater }" @click.stop="() => toggleWatchLater()" v-if="confDescriptor?.features.remindMeOnceVideosAreAvailableEnabled">
44
<ion-icon v-if="!talkNotes?.watchLater" aria-hidden="true" src="/assets/icons/line/video-line.svg"></ion-icon>
55
<ion-icon v-if="!!talkNotes?.watchLater" aria-hidden="true" src="/assets/icons/solid/video.svg"></ion-icon>
66
</ion-button>
77
</div>
88
</template>
99

1010
<script setup lang="ts">
11-
import {computed, PropType} from "vue";
12-
import {UserTalkNotesHook} from "@/state/useUserTalkNotes";
11+
import {PropType} from "vue";
12+
import {
13+
useUserTalkNoteActions
14+
} from "@/state/useUserTalkNotes";
1315
import {VoxxrinConferenceDescriptor} from "@/models/VoxxrinConferenceDescriptor";
16+
import {toManagedRef as toRef} from "@/views/vue-utils";
17+
import {TalkId} from "@/models/VoxxrinTalk";
18+
import {TalkNote} from "../../../../shared/feedbacks.firestore";
1419
1520
const props = defineProps({
1621
confDescriptor: {
@@ -19,11 +24,22 @@ const props = defineProps({
1924
},
2025
userTalkNotes: {
2126
required: true,
22-
type: Object as PropType<UserTalkNotesHook>
27+
type: Object as PropType<TalkNote>
2328
}
2429
});
2530
26-
const talkNotes = computed(() => props.userTalkNotes?.talkNotes.value)
31+
const emits = defineEmits<{
32+
(e: 'talkNoteUpdated', updatedTalkNote: TalkNote): void,
33+
}>()
34+
35+
const talkNotes = toRef(() => props.userTalkNotes)
36+
37+
const {toggleWatchLater} = useUserTalkNoteActions(
38+
toRef(() => props.confDescriptor?.id),
39+
toRef(() => props.userTalkNotes?.talkId ? new TalkId(props.userTalkNotes?.talkId) : undefined),
40+
talkNotes,
41+
updatedTalkNote => emits("talkNoteUpdated", updatedTalkNote)
42+
)
2743
</script>
2844

2945
<style scoped lang="scss">

mobile/src/components/timeslots/TimeSlotAccordion.vue

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<template>
22
<ion-accordion :value="timeslot.id.value"
3+
:style="{ 'animation-delay': `${animationDelay}ms` }"
34
:class="{ 'slot-accordion': true, [`_chronological_status_is_${progress?.status}`]: true, '_feedback-provided': !hasMissingFeedback, '_missing-feedback': hasMissingFeedback, '_is-break': timeslot.type==='break' }">
45
<ion-item slot="header" color="light">
56
<ion-ripple-effect type="bounded"></ion-ripple-effect>
@@ -36,7 +37,7 @@
3637

3738
<script setup lang="ts">
3839
import {computed, PropType} from "vue";
39-
import {managedRef as ref} from "@/views/vue-utils";
40+
import {managedRef as ref, toManagedRef as toRef} from "@/views/vue-utils";
4041
import {
4142
IonProgressBar,
4243
IonAccordion,
@@ -80,6 +81,11 @@ const props = defineProps({
8081
required: false,
8182
type: Object as PropType<Array<"add-feedback-btn">>,
8283
default: []
84+
},
85+
animationDelay: {
86+
required: false,
87+
type: Number as PropType<Number|undefined>,
88+
default: undefined
8389
}
8490
})
8591
@@ -89,7 +95,7 @@ defineEmits<{
8995
9096
const { LL } = typesafeI18n()
9197
92-
const { conferenceDescriptor } = useSharedConferenceDescriptor(props.confDescriptor?.id);
98+
const { conferenceDescriptor } = useSharedConferenceDescriptor(toRef(() => props.confDescriptor?.id));
9399
94100
const progress = ref<TimeslotTimingProgress>()
95101
useInterval(() => {
@@ -111,6 +117,9 @@ const hasMissingFeedback = computed(() => {
111117
112118
// * Base Style Accordion *//
113119
ion-accordion {
120+
transition: var(--app-voxxrin-animations-timeslots-anim-duration);
121+
animation: scale-up-center var(--app-voxxrin-animations-timeslots-anim-duration) cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
122+
114123
border-bottom: 1px solid var(--app-background);
115124
116125
&.accordion-expanded {
@@ -317,4 +326,16 @@ const hasMissingFeedback = computed(() => {
317326
}
318327
}
319328
}
329+
330+
@keyframes scale-up-center {
331+
0% {
332+
opacity: 0;
333+
transform: scale(0.2);
334+
}
335+
100% {
336+
opacity: 1;
337+
transform: scale(1);
338+
}
339+
}
340+
320341
</style>

mobile/src/components/timeslots/TimeSlotSection.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
<script setup lang="ts">
1616
import {PropType} from "vue";
17-
import {managedRef as ref} from "@/views/vue-utils";
17+
import {managedRef as ref, toManagedRef as toRef} from "@/views/vue-utils";
1818
import {
1919
getTimeslotLabel,
2020
getTimeslotTimingProgress,
@@ -48,7 +48,7 @@ defineEmits<{
4848
4949
const { LL } = typesafeI18n()
5050
51-
const { conferenceDescriptor } = useSharedConferenceDescriptor(props.confDescriptor?.id);
51+
const { conferenceDescriptor } = useSharedConferenceDescriptor(toRef(() => props.confDescriptor?.id));
5252
5353
const progress = ref<TimeslotTimingProgress>()
5454
useInterval(() => {

mobile/src/components/timeslots/TimeslotsIterator.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
2-
<slot name="iterator" :timeslot="timeslot"
3-
v-for="(timeslot) in timeslotsRef" :key="timeslot.id.value" />
2+
<slot name="iterator" :timeslot="timeslot" :index="index"
3+
v-for="(timeslot, index) in timeslotsRef" :key="timeslot.id.value" />
44
</template>
55

66
<script setup lang="ts">
@@ -53,7 +53,7 @@ onMounted(async () => {
5353
useInterval(recomputeMissingFeedbacksList, {freq:"low-frequency"}, {immediate: true})
5454
})
5555
56-
const { userFeedbacks: dailyUserFeedbacksRef } = useUserFeedbacks(props.confDescriptor?.id, props.dayId)
56+
const { userFeedbacks: dailyUserFeedbacksRef } = useUserFeedbacks(toRef(() => props.confDescriptor?.id), toRef(() => props.dayId))
5757
const { timeslotsRef } = useLabelledTimeslotWithFeedbacks(
5858
toRef(props, 'dailySchedule'),
5959
dailyUserFeedbacksRef, toRef(props, 'searchTerms'));

0 commit comments

Comments
 (0)