Skip to content

Commit

Permalink
1172 lecture week view (#1411)
Browse files Browse the repository at this point in the history
* basic funtionality for grouping vods by week; group names are not updating correctly yet

* uglier, but functional implementation of week view; revert to last commit if same result can be achieved with better code quality

* removed unused code

* removed unused import

* linter fix

* prettier fix

* fixed buttons looking weird in mobile view

* removed unnecessary attribute
  • Loading branch information
karjo24 authored Dec 5, 2024
1 parent d99062c commit 1a5939d
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 6 deletions.
9 changes: 7 additions & 2 deletions web/template/home.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@
:class="plannedStreams.hasElements() ? 'col-span-2' : 'col-span-full'">
<header>
<h3 class="font-bold">VODs</h3>
<section class="space-x-2">
<section class="button-area space-y-1">
<button type="button" @click="sortNewestFirst()"
class="tum-live-button tum-live-button-tertiary"
:class="{'active' : isNewestFirst() }">
Expand All @@ -433,6 +433,11 @@
:class="{'active' : isListView() }">
List View
</button>
<button type="button" @click="toggleWeekView()"
class="tum-live-button tum-live-button-tertiary"
:class="{'active' : isWeekView() }">
Week View
</button>
</section>
</header>
<section>
Expand All @@ -442,7 +447,7 @@
x-for="group in courseStreams.get(sortFn(streamSortMode), filterPred(streamFilterMode))">
<article class="mb-8">
<header class="mb-2">
<h6 class="font-semibold" x-text="group[0].GetMonthName()"></h6>
<h6 class="font-semibold" x-text="groupNames.get(group[0].ID);"></h6>
</header>
<section class="grid gap-3 grid-cols-1"
:class="isListView() ? 'xl:grid-cols-1 lg:grid-cols-1 md:grid-cols-1 grid-cols-1' : plannedStreams.hasElements()
Expand Down
6 changes: 6 additions & 0 deletions web/ts/api/courses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ type DownloadableVOD = {
readonly DownloadURL: string;
};

const MS_IN_DAY = 1000 * 60 * 60 * 24;

export class Stream implements Identifiable {
readonly ID: number;
readonly Name: string;
Expand Down Expand Up @@ -118,6 +120,10 @@ export class Stream implements Identifiable {
][this.StartDate().getMonth()];
}

public GetWeekNumber(dateOfFirstWeek: Date): number {
return Math.floor((this.StartDate().getTime() - dateOfFirstWeek.getTime()) / MS_IN_DAY / 7) + 1;
}

private static TimeOf(d: string): string {
return new Date(d).toLocaleTimeString("default", { hour: "2-digit", minute: "2-digit" });
}
Expand Down
85 changes: 81 additions & 4 deletions web/ts/components/course.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export enum ViewMode {
List,
}

export enum GroupMode {
Month,
Week,
}

export function courseContext(slug: string, year: number, term: string, userId: number): AlpineComponent {
return {
userId: userId as number,
Expand All @@ -41,6 +46,11 @@ export function courseContext(slug: string, year: number, term: string, userId:
streamSortMode: +getFromStorage("streamSortMode") ?? StreamSortMode.NewestFirst,
streamFilterMode: +getFromStorage("streamFilterMode") ?? StreamFilterMode.ShowWatched,
viewMode: (+getFromStorage("viewMode") ?? ViewMode.Grid) as number,
groupMode: (+getFromStorage("groupMode") ?? GroupMode.Month) as number,

dateOfFirstWeek: new Date(),
weekCountWithoutEmptyWeeks: new Map<number, number>(),
groupNames: new Map<number, string>(),

/**
* AlpineJS init function which is called automatically in addition to 'x-init'
Expand Down Expand Up @@ -68,10 +78,12 @@ export function courseContext(slug: string, year: number, term: string, userId:
this.loadPinned();
this.plannedStreams.set(this.course.Planned.reverse()).reset();
this.upcomingStreams.set(this.course.Upcoming).reset();
this.loadProgresses(this.course.Recordings.map((s: Stream) => s.ID)).then((progresses) => {
this.course.Recordings.forEach((s: Stream, i) => (s.Progress = progresses[i]));
this.courseStreams.set(this.course.Recordings, (s: Stream) => s.StartDate().getMonth());
});
this.loadProgresses(this.course.Recordings.map((s: Stream) => s.ID))
.then((progresses) => {
this.course.Recordings.forEach((s: Stream, i) => (s.Progress = progresses[i]));
})
.then(() => this.initializeWeekMap())
.then(() => this.applyGroupView());
console.log("🌑 init course", this.course);
});
},
Expand Down Expand Up @@ -132,6 +144,71 @@ export function courseContext(slug: string, year: number, term: string, userId:
return this.viewMode == ViewMode.List;
},

toggleWeekView() {
this.groupMode = this.groupMode === GroupMode.Month ? GroupMode.Week : GroupMode.Month;
setInStorage("groupMode", this.groupMode.toString());
this.applyGroupView();
},

isWeekView() {
return this.groupMode == GroupMode.Week;
},

applyGroupView() {
if (this.groupMode === GroupMode.Month) {
this.courseStreams.set(this.course.Recordings, (s: Stream) => s.StartDate().getMonth());
} else {
this.courseStreams.set(this.course.Recordings, (s: Stream) =>
this.getTrueWeek(s.GetWeekNumber(this.dateOfFirstWeek)),
);
}

// update group names
const groups = this.courseStreams.get(
this.sortFn(this.streamSortMode),
this.filterPred(this.streamFilterMode),
);
this.groupNames.clear();
for (let i = 0; i < groups.length; i++) {
const s1 = groups[i][0];
this.groupNames.set(s1.ID, this.getGroupName(s1));
const s2 = groups[i][groups[i].length - 1];
this.groupNames.set(s2.ID, this.getGroupName(s2));
}
},

/**
* Maps the difference in Weeks between any lecture and the first lecture to the true week count ignoring weeks without lectures (e.g. Christmas Break)
*/
initializeWeekMap() {
let latestWeek = 1;
this.course.Recordings.sort(this.sortFn(StreamSortMode.OldestFirst)).forEach((s: Stream, i: number) => {
if (i === 0) {
this.dateOfFirstWeek = s.StartDate();
this.dateOfFirstWeek = new Date(
this.dateOfFirstWeek.getTime() - this.dateOfFirstWeek.getDay() * 1000 * 60 * 60 * 24,
);
this.dateOfFirstWeek.setHours(0, 1); // avoids errors e.g. in case week1 has vod on Monday at 10am, week2 at 8am
}
const week = s.GetWeekNumber(this.dateOfFirstWeek);
if (!this.weekCountWithoutEmptyWeeks.has(week)) {
this.weekCountWithoutEmptyWeeks.set(week, latestWeek++);
}
});
},

getTrueWeek(n: number): number {
return this.weekCountWithoutEmptyWeeks.get(n);
},

getGroupName(s: Stream): string {
if (this.groupMode === GroupMode.Month) {
return s.GetMonthName();
} else {
return "Week " + this.getTrueWeek(s.GetWeekNumber(this.dateOfFirstWeek)).toString();
}
},

/**
* Depending on the pinned value, pin or unpin course
*/
Expand Down

0 comments on commit 1a5939d

Please sign in to comment.