Skip to content

Commit 6f6112f

Browse files
committed
feat(badge): adds calendar badge summary
1 parent dc8ac91 commit 6f6112f

File tree

14 files changed

+237
-38
lines changed

14 files changed

+237
-38
lines changed

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@
5252
},
5353
"dependencies": {
5454
"@dvcol/base-http-client": "^1.10.0",
55-
"@dvcol/common-utils": "^1.7.0",
55+
"@dvcol/common-utils": "^1.8.0",
5656
"@dvcol/tmdb-http-client": "^1.2.3",
5757
"@dvcol/trakt-http-client": "^1.4.5",
5858
"@dvcol/tvdb-http-client": "^1.1.3",
59-
"@dvcol/web-extension-utils": "^3.2.0",
59+
"@dvcol/web-extension-utils": "^3.3.0",
6060
"@vue/devtools": "^7.0.15",
6161
"iso-3166-2": "^1.0.0",
6262
"naive-ui": "^2.38.1",

pnpm-lock.yaml

+15-15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<script lang="ts" setup>
2+
import { NSwitch } from 'naive-ui';
3+
4+
import SettingsFormItem from '~/components/views/settings/SettingsFormItem.vue';
5+
import { useBadgeStoreRefs } from '~/stores/settings/badge.store';
6+
import { useI18n } from '~/utils/i18n.utils';
7+
8+
const i18n = useI18n('settings', 'badge');
9+
10+
const { enableBadge } = useBadgeStoreRefs();
11+
</script>
12+
13+
<template>
14+
<div class="badge-container">
15+
<!-- Enable -->
16+
<SettingsFormItem :label="i18n('label_enable_badge')">
17+
<NSwitch v-model:value="enableBadge" class="form-switch">
18+
<template #checked>{{ i18n('on', 'common', 'button') }}</template>
19+
<template #unchecked>{{ i18n('off', 'common', 'button') }}</template>
20+
</NSwitch>
21+
</SettingsFormItem>
22+
</div>
23+
</template>
24+
25+
<style lang="scss" scoped>
26+
.badge-container {
27+
display: flex;
28+
flex-direction: column;
29+
gap: 1.5rem;
30+
}
31+
</style>

src/components/views/settings/SettingsComponent.vue

+3
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ import { type Component, onDeactivated, type Ref, ref } from 'vue';
55
66
import SettingsAccount from '~/components/views/settings/SettingsAccount.vue';
77
import SettingsActivity from '~/components/views/settings/SettingsActivity.vue';
8+
import SettingsBadge from '~/components/views/settings/SettingsBadge.vue';
89
import SettingsCache from '~/components/views/settings/SettingsCache.vue';
910
import SettingsExport from '~/components/views/settings/SettingsExport.vue';
1011
import SettingsLinks from '~/components/views/settings/SettingsLinks.vue';
1112
import SettingsLogs from '~/components/views/settings/SettingsLogs.vue';
1213
import SettingsMenus from '~/components/views/settings/SettingsMenus.vue';
1314
import SettingsTabs from '~/components/views/settings/SettingsTabs.vue';
1415
import SettingsWatching from '~/components/views/settings/SettingsWatching.vue';
16+
1517
import { useI18n } from '~/utils/i18n.utils';
1618
1719
const i18n = useI18n('settings');
@@ -29,6 +31,7 @@ const sections: Section[] = [
2931
{ title: 'menu__menus', reference: ref(), component: SettingsMenus },
3032
{ title: 'menu__watching', reference: ref(), component: SettingsWatching },
3133
{ title: 'menu__activity', reference: ref(), component: SettingsActivity },
34+
{ title: 'menu__badge', reference: ref(), component: SettingsBadge },
3235
{ title: 'menu__cache', reference: ref(), component: SettingsCache },
3336
{ title: 'menu__export', reference: ref(), component: SettingsExport },
3437
{ title: 'menu__logs', reference: ref(), component: SettingsLogs },
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"settings__badge__label_enable_badge": {
3+
"message": "Enable badge (daily calendar releases)",
4+
"description": "Label for enabling badge."
5+
}
6+
}

src/i18n/en/settings/settings-menu.json

+4
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,9 @@
3434
"settings__menu__activity": {
3535
"message": "Activity",
3636
"description": "Activity ui menu item"
37+
},
38+
"settings__menu__badge": {
39+
"message": "Badge",
40+
"description": "Badge ui menu item"
3741
}
3842
}

src/models/message/message-type.model.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,28 @@ import type { ContextMenuIds } from '~/models/context/context-menu.model';
44
export const MessageType = {
55
ContextMenu: 'context-menu',
66
VersionUpdate: 'version-update',
7+
AppReady: 'app-ready',
8+
BadgeUpdate: 'badge-update',
79
} as const;
810

911
export type MessageTypes = (typeof MessageType)[keyof typeof MessageType];
1012

13+
export type BadgeUpdatePayload = {
14+
title?: string;
15+
text?: string;
16+
color?: string;
17+
backgroundColor?: string;
18+
};
19+
1120
/**
1221
* Type union of possible message payloads
1322
*/
1423
export type MessagePayload<T extends MessageTypes = MessageTypes> = T extends typeof MessageType.ContextMenu
1524
? Record<ContextMenuIds, boolean>
1625
: T extends typeof MessageType.VersionUpdate
1726
? VersionUpdateDetails & { date: number }
18-
: MessageTypes;
27+
: T extends typeof MessageType.AppReady
28+
? boolean
29+
: T extends typeof MessageType.BadgeUpdate
30+
? BadgeUpdatePayload
31+
: MessageTypes;

src/scripts/background/index.ts

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { setBadgeBackgroundColor, setBadgeText, setBadgeTextColor, setTitle } from '@dvcol/web-extension-utils/chrome/action';
12
import { onContextMenuClicked } from '@dvcol/web-extension-utils/chrome/context';
23
import { onInstalledEvent, onVersionUpdate } from '@dvcol/web-extension-utils/chrome/runtime';
34

@@ -46,3 +47,16 @@ try {
4647
} catch (error) {
4748
console.error('Failed to handle context menu click event', error);
4849
}
50+
51+
try {
52+
onMessage(MessageType.BadgeUpdate, async message => {
53+
if (!message.payload) return;
54+
const { title, text, color, backgroundColor } = message.payload;
55+
if (title !== undefined) setTitle?.({ title });
56+
if (text !== undefined) setBadgeText?.({ text });
57+
if (color !== undefined) setBadgeTextColor?.({ color });
58+
if (backgroundColor !== undefined) setBadgeBackgroundColor?.({ color: backgroundColor });
59+
});
60+
} catch (error) {
61+
console.error('Failed to handle badge update message', error);
62+
}

src/stores/app-state.store.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { defineStore, storeToRefs } from 'pinia';
22
import { ref } from 'vue';
33

4+
import { MessageType } from '~/models/message/message-type.model';
5+
import { sendMessage } from '~/utils/browser/browser-message.utils';
6+
47
export const useAppStateStore = defineStore('app.state', () => {
58
const isAppReady = ref(false);
69
const panelOpen = ref(false);
@@ -14,10 +17,11 @@ export const useAppStateStore = defineStore('app.state', () => {
1417
}),
1518
);
1619

17-
const setAppReady = (ready: boolean) => {
20+
const setAppReady = async (ready: boolean) => {
1821
isAppReady.value = ready;
1922
resolve(ready);
2023
waitAppReady.value = Promise.resolve(ready);
24+
return sendMessage({ type: MessageType.AppReady, payload: ready });
2125
};
2226

2327
return { isAppReady, setAppReady, waitAppReady, panelOpen, panelDirty, footerOpen };

src/stores/data/calendar.store.ts

+17-15
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { defineStore, storeToRefs } from 'pinia';
44
import { computed, reactive, ref } from 'vue';
55

66
import { ListScrollItemType } from '~/models/list-scroll.model';
7-
87
import { ErrorService } from '~/services/error.service';
98
import { Logger } from '~/services/logger.service';
109
import { NotificationService } from '~/services/notification.service';
@@ -25,6 +24,22 @@ type CalendarState = {
2524
extended?: boolean;
2625
};
2726

27+
export const fetchCalendarData = async (query: TraktCalendarQuery): Promise<CalendarItem[]> => {
28+
const [shows, movies] = await Promise.all([TraktService.calendar(query, 'shows'), TraktService.calendar(query, 'movies')]);
29+
return [
30+
...(shows as TraktCalendarShow[]).map(show => ({
31+
...show,
32+
id: show.episode.ids.trakt ?? show.show.ids.trakt,
33+
date: new Date(show.first_aired),
34+
})),
35+
...(movies as TraktCalendarMovie[]).map(movie => ({
36+
...movie,
37+
id: movie.movie.ids.trakt,
38+
date: new Date(movie.released),
39+
})),
40+
].sort((a, b) => a.date.getTime() - b.date.getTime());
41+
};
42+
2843
export const useCalendarStore = defineStore(CalendarStoreConstants.Store, () => {
2944
const firstLoad = ref(true);
3045
const loading = ref(true);
@@ -104,21 +119,8 @@ export const useCalendarStore = defineStore(CalendarStoreConstants.Store, () =>
104119
if (extended.value) query.extended = TraktApiExtended.Full;
105120

106121
try {
107-
const [shows, movies] = await Promise.all([TraktService.calendar(query, 'shows'), TraktService.calendar(query, 'movies')]);
122+
const newData: CalendarItem[] = await fetchCalendarData(query);
108123
delete calendarErrors[JSON.stringify(query)];
109-
const newData: CalendarItem[] = [
110-
...(shows as TraktCalendarShow[]).map(show => ({
111-
...show,
112-
id: show.episode.ids.trakt ?? show.show.ids.trakt,
113-
date: new Date(show.first_aired),
114-
})),
115-
...(movies as TraktCalendarMovie[]).map(movie => ({
116-
...movie,
117-
id: movie.movie.ids.trakt,
118-
date: new Date(movie.released),
119-
})),
120-
].sort((a, b) => a.date.getTime() - b.date.getTime());
121-
122124
const spacedData = spaceDate(newData, startDate, endDate);
123125

124126
if (mode === 'reload') {

0 commit comments

Comments
 (0)