Skip to content

Commit cf8ee0c

Browse files
committed
Add artist chart view
1 parent 4a58abd commit cf8ee0c

File tree

3 files changed

+75
-33
lines changed

3 files changed

+75
-33
lines changed

src/renderer/src/App.vue

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,7 @@
6868

6969
<script lang="ts" setup>
7070
// todo
71-
// check if tokens needs deep watch for persistent ref
72-
// possibly replace color thief with something without vulnerabilities
73-
// theme light/dark broke
7471
// show individual artist stats graph
75-
// recent searches is broken
7672
7773
import TopMenu from "./components/main-ui/TopMenu.vue";
7874
import MusicPlayer from "./components/player/MusicPlayer.vue";

src/renderer/src/store/UI/UIStore.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ export const useUIStore = defineStore("UI", () => {
6969
});
7070
}
7171
let { themeString, msToSwitch } = getThemeFromLocalStorage();
72-
console.log("Applied from LS", themeString, msToSwitch);
7372
theme.global.name.value = themeString;
7473
if (msToSwitch !== -1) {
7574
clearTimeout(scheduleTimeout);

src/renderer/src/views/Wrapped.vue

Lines changed: 75 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -35,28 +35,49 @@
3535
<v-list class="stat-list">
3636
<div class="item-stat pa-4">
3737
<p class="minutes-stat">Artist</p>
38-
<p class="minutes-stat">Listened minutes</p>
38+
<p class="minutes-stat align-right">Listened minutes</p>
3939
</div>
40-
<v-list-item
41-
v-for="({ artist, minutes }, i) of artistsTop"
42-
:to="itemUrl(artist)"
43-
rounded
44-
@click.right="
45-
dialog.setContextMenuItem($event as MouseEvent, artist)
46-
"
40+
<template
41+
v-for="({ artist, listenMinutes, history }, i) of artistsTop"
4742
>
48-
<v-list-item-title class="item-stat">
49-
<p class="item-rank">{{ i + 1 }}</p>
50-
<v-avatar :image="itemImage(artist)" size="36px" />
51-
<p class="flex-grow-1">{{ artist.name }}</p>
52-
<p class="minutes-stat">
53-
<span class="font-weight-bold">{{
54-
minutes.toLocaleString()
55-
}}</span>
56-
mins
57-
</p>
58-
</v-list-item-title>
59-
</v-list-item>
43+
<v-list-item
44+
rounded
45+
@click.right="
46+
dialog.setContextMenuItem($event as MouseEvent, artist)
47+
"
48+
>
49+
<v-list-item-title class="item-stat">
50+
<p class="item-rank">{{ i + 1 }}</p>
51+
<v-avatar
52+
:image="
53+
itemImage(artist as SpotifyApi.ArtistObjectFull)
54+
"
55+
size="36px"
56+
/>
57+
<router-link
58+
no-style
59+
:to="itemUrl(artist)"
60+
class="flex-grow-1"
61+
>{{ artist.name }}
62+
</router-link>
63+
<p class="minutes-stat align-right">
64+
<span class="font-weight-bold">{{
65+
listenMinutes.toLocaleString()
66+
}}</span>
67+
mins
68+
</p>
69+
<v-btn
70+
@click="toggleChart(artist.id)"
71+
icon="mdi-chart-line-variant"
72+
density="compact"
73+
variant="text"
74+
/>
75+
</v-list-item-title>
76+
</v-list-item>
77+
<div v-if="expandedArtists.has(artist.id)">
78+
<line-chart :chart-data="artistChart(`Minutes listened to ${artist.name}`, history)"/>
79+
</div>
80+
</template>
6081
</v-list>
6182

6283
<v-divider class="mt-5 mb-5" />
@@ -177,7 +198,12 @@
177198
import LineChart from "../components/LineChart.vue";
178199
import { computed, ref } from "vue";
179200
import { useStatsStore } from "../store/player/playStats";
180-
import { ChartData, ItemCollection, TrackStat } from "../scripts/types";
201+
import {
202+
ArtistStat,
203+
ChartData,
204+
ItemCollection,
205+
TrackStat,
206+
} from "../scripts/types";
181207
import { useUIStore } from "../store/UI/UIStore";
182208
import { useSpotifyApiStore } from "../store/spotify-api";
183209
import TrackListItem from "../components/track-list/TrackListItem.vue";
@@ -204,11 +230,27 @@ const shownCharts = ref([2, 9, 11]);
204230
const trackLimit = ref(10);
205231
const artistLimit = ref(5);
206232
207-
const artistsTop = ref(
208-
[] as { artist: SpotifyApi.ArtistObjectFull; minutes: number }[],
209-
);
233+
const artistsTop = ref([] as ArtistStat[]);
210234
const tracksTop = ref([] as TrackStat[]);
211235
const tracksSkip = ref([] as TrackStat[]);
236+
const expandedArtists = ref(new Set<string>());
237+
238+
function toggleChart(artistId: string) {
239+
if (expandedArtists.value.has(artistId)) {
240+
expandedArtists.value.delete(artistId);
241+
} else {
242+
expandedArtists.value.add(artistId);
243+
}
244+
}
245+
246+
function artistChart(label:string, history: { [key: string]: number }) {
247+
return {
248+
labels: Object.keys(history).map((k) => new Date(k)),
249+
values: Object.values(history),
250+
yAxis: "Minutes",
251+
dataLabel: label,
252+
};
253+
}
212254
213255
async function generate() {
214256
let { topArtists, topTracks, skipTracks, statistics } =
@@ -221,10 +263,10 @@ async function generate() {
221263
: spotify.getArtist(a.id, true),
222264
),
223265
);
224-
artistsTop.value = artists.map((artist, i) => ({
225-
artist,
226-
minutes: topArtists[i].listenMinutes,
227-
}));
266+
artistsTop.value = artists.map((artist, i) => {
267+
topArtists[i].artist = artist;
268+
return topArtists[i];
269+
});
228270
tracksTop.value = topTracks;
229271
tracksSkip.value = skipTracks;
230272
@@ -344,6 +386,7 @@ h1 {
344386
opacity: 0.7;
345387
text-transform: uppercase;
346388
font-size: 13px;
389+
width: 130px;
347390
}
348391
349392
.track-list-item {
@@ -364,4 +407,8 @@ h1 {
364407
.track-list-item-parent.odd-item {
365408
background-color: rgba(var(--v-theme-on-background), 0.06);
366409
}
410+
411+
.align-right {
412+
text-align: right;
413+
}
367414
</style>

0 commit comments

Comments
 (0)