update
This commit is contained in:
@@ -122,7 +122,14 @@ def ziehen():
|
|||||||
if not eintraege:
|
if not eintraege:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
treffer = random.randrange(len(eintraege))
|
# Schon gelaufene Filme überspringen. Sind alle Vorschläge gesehen,
|
||||||
|
# bleibt es bei der vollen Auswahl — sonst gäbe es keinen Gewinner.
|
||||||
|
with connect() as conn:
|
||||||
|
gesehen = {
|
||||||
|
r["movie_id"] for r in conn.execute("SELECT movie_id FROM watched")
|
||||||
|
}
|
||||||
|
frisch = [i for i, e in enumerate(eintraege) if e["movie_id"] not in gesehen]
|
||||||
|
treffer = random.choice(frisch) if frisch else random.randrange(len(eintraege))
|
||||||
schritt = 360 / len(eintraege)
|
schritt = 360 / len(eintraege)
|
||||||
runden = 5 + random.randrange(3)
|
runden = 5 + random.randrange(3)
|
||||||
# Der Zeiger steht oben, also muss die Mitte des Zielsegments dorthin
|
# Der Zeiger steht oben, also muss die Mitte des Zielsegments dorthin
|
||||||
|
|||||||
@@ -331,6 +331,11 @@ async function ladeGesehen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Für die Karten: nur die Kennungen, als Menge zum schnellen Nachschlagen
|
||||||
|
const gesehenIds = computed(
|
||||||
|
() => new Set(gesehen.value.map((e) => e.movie_id))
|
||||||
|
)
|
||||||
|
|
||||||
// Ausgeblendete Filme zählen für Gäste nicht mit
|
// Ausgeblendete Filme zählen für Gäste nicht mit
|
||||||
const gesehenZahl = computed(
|
const gesehenZahl = computed(
|
||||||
() => gesehen.value.filter((e) => host.value || !e.hidden).length
|
() => gesehen.value.filter((e) => host.value || !e.hidden).length
|
||||||
@@ -659,12 +664,14 @@ onUnmounted(() => {
|
|||||||
<div v-if="activeTab === 'search' || activeTab === 'aehnlich'" class="layout">
|
<div v-if="activeTab === 'search' || activeTab === 'aehnlich'" class="layout">
|
||||||
<SearchTab
|
<SearchTab
|
||||||
v-if="activeTab === 'search'"
|
v-if="activeTab === 'search'"
|
||||||
|
:gesehen-ids="gesehenIds"
|
||||||
:filter="suchFilter"
|
:filter="suchFilter"
|
||||||
:ansicht="ansicht"
|
:ansicht="ansicht"
|
||||||
@open="selected = $event"
|
@open="selected = $event"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<AehnlichTab
|
<AehnlichTab
|
||||||
|
:gesehen-ids="gesehenIds"
|
||||||
v-else
|
v-else
|
||||||
:filter="suchFilter"
|
:filter="suchFilter"
|
||||||
:ansicht="ansicht"
|
:ansicht="ansicht"
|
||||||
@@ -696,6 +703,7 @@ onUnmounted(() => {
|
|||||||
:host="host"
|
:host="host"
|
||||||
:merkliste="merkliste"
|
:merkliste="merkliste"
|
||||||
:mine="meinVorschlag?.id ?? null"
|
:mine="meinVorschlag?.id ?? null"
|
||||||
|
:gesehen-ids="gesehenIds"
|
||||||
@open="selected = $event"
|
@open="selected = $event"
|
||||||
@reset="meinVorschlag = null"
|
@reset="meinVorschlag = null"
|
||||||
/>
|
/>
|
||||||
@@ -709,6 +717,7 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
<MerklisteTab
|
<MerklisteTab
|
||||||
v-else-if="activeTab === 'merkliste'"
|
v-else-if="activeTab === 'merkliste'"
|
||||||
|
:gesehen-ids="gesehenIds"
|
||||||
:items="merkliste"
|
:items="merkliste"
|
||||||
:ich="ich"
|
:ich="ich"
|
||||||
@open="selected = $event"
|
@open="selected = $event"
|
||||||
@@ -743,6 +752,7 @@ onUnmounted(() => {
|
|||||||
<MovieCard
|
<MovieCard
|
||||||
v-if="entry.parts.length === 1"
|
v-if="entry.parts.length === 1"
|
||||||
:movie="entry.parts[0]"
|
:movie="entry.parts[0]"
|
||||||
|
:gesehen="gesehenIds.has(entry.parts[0].id)"
|
||||||
:auf-dem-rad="aufDemRad.includes(entry.parts[0].id)"
|
:auf-dem-rad="aufDemRad.includes(entry.parts[0].id)"
|
||||||
:ansicht="ansicht"
|
:ansicht="ansicht"
|
||||||
@open="filmOeffnen"
|
@open="filmOeffnen"
|
||||||
@@ -750,6 +760,7 @@ onUnmounted(() => {
|
|||||||
<SeriesCard
|
<SeriesCard
|
||||||
v-else
|
v-else
|
||||||
:parts="entry.parts"
|
:parts="entry.parts"
|
||||||
|
:gesehen-ids="gesehenIds"
|
||||||
:start="entry.best"
|
:start="entry.best"
|
||||||
:auf-dem-rad="aufDemRad"
|
:auf-dem-rad="aufDemRad"
|
||||||
:ansicht="ansicht"
|
:ansicht="ansicht"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ const VORSCHLAEGE = { kompakt: 20, details: 8 }
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
filter: { type: Object, default: () => ({}) },
|
filter: { type: Object, default: () => ({}) },
|
||||||
ansicht: { type: String, default: 'kompakt' },
|
ansicht: { type: String, default: 'kompakt' },
|
||||||
|
gesehenIds: { type: Set, default: () => new Set() },
|
||||||
// Kommt aus der Filmansicht: von diesem Film soll es losgehen
|
// Kommt aus der Filmansicht: von diesem Film soll es losgehen
|
||||||
start: { type: Object, default: null },
|
start: { type: Object, default: null },
|
||||||
})
|
})
|
||||||
@@ -177,6 +178,7 @@ async function oeffnen(movie) {
|
|||||||
:key="film.id"
|
:key="film.id"
|
||||||
:movie="film"
|
:movie="film"
|
||||||
:ansicht="ansicht"
|
:ansicht="ansicht"
|
||||||
|
:gesehen="gesehenIds.has(film.id)"
|
||||||
@open="waehlen"
|
@open="waehlen"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -203,6 +205,7 @@ async function oeffnen(movie) {
|
|||||||
:key="film.id"
|
:key="film.id"
|
||||||
:movie="film"
|
:movie="film"
|
||||||
:ansicht="ansicht"
|
:ansicht="ansicht"
|
||||||
|
:gesehen="gesehenIds.has(film.id)"
|
||||||
@open="oeffnen"
|
@open="oeffnen"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { posterUrl } from '../images'
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
items: { type: Array, default: () => [] },
|
items: { type: Array, default: () => [] },
|
||||||
ich: { type: Object, default: null },
|
ich: { type: Object, default: null },
|
||||||
|
gesehenIds: { type: Set, default: () => new Set() },
|
||||||
})
|
})
|
||||||
|
|
||||||
// Nach Person gruppiert, die eigene Sammlung zuerst
|
// Nach Person gruppiert, die eigene Sammlung zuerst
|
||||||
@@ -87,7 +88,12 @@ async function oeffnen(item) {
|
|||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<article v-for="item in gefiltert(gruppe)" :key="item.id" class="karte">
|
<article
|
||||||
|
v-for="item in gefiltert(gruppe)"
|
||||||
|
:key="item.id"
|
||||||
|
class="karte"
|
||||||
|
:class="{ gesehen: gesehenIds.has(item.movie_id) }"
|
||||||
|
>
|
||||||
<button type="button" class="cover" @click="oeffnen(item)">
|
<button type="button" class="cover" @click="oeffnen(item)">
|
||||||
<img
|
<img
|
||||||
v-if="posterUrl(item.poster_path, 'w342')"
|
v-if="posterUrl(item.poster_path, 'w342')"
|
||||||
@@ -126,6 +132,15 @@ async function oeffnen(item) {
|
|||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Schon gelaufen — die Karte tritt zurück, kommt beim Überfahren wieder */
|
||||||
|
.karte.gesehen {
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.karte.gesehen:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.karte {
|
.karte {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.9rem;
|
gap: 0.9rem;
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { backdropUrl, posterUrl } from '../images'
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
movie: { type: Object, required: true },
|
movie: { type: Object, required: true },
|
||||||
aufDemRad: { type: Boolean, default: false },
|
aufDemRad: { type: Boolean, default: false },
|
||||||
|
// Schon gelaufen — die Karte tritt dann zurück
|
||||||
|
gesehen: { type: Boolean, default: false },
|
||||||
ansicht: { type: String, default: 'kompakt' },
|
ansicht: { type: String, default: 'kompakt' },
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -30,7 +32,7 @@ const meta = computed(() =>
|
|||||||
<template>
|
<template>
|
||||||
<button
|
<button
|
||||||
class="card"
|
class="card"
|
||||||
:class="[ansicht, { 'auf-dem-rad': aufDemRad }]"
|
:class="[ansicht, { 'auf-dem-rad': aufDemRad, gesehen }]"
|
||||||
type="button"
|
type="button"
|
||||||
@click="$emit('open', movie)"
|
@click="$emit('open', movie)"
|
||||||
>
|
>
|
||||||
@@ -69,6 +71,16 @@ const meta = computed(() =>
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
/* Schon gelaufen — die Karte tritt zurück, bleibt aber lesbar.
|
||||||
|
Beim Überfahren kommt sie zurück. */
|
||||||
|
.card.gesehen {
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card.gesehen:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Details: breite Karte, Poster links, alles lesbar statt abgeschnitten */
|
/* Details: breite Karte, Poster links, alles lesbar statt abgeschnitten */
|
||||||
.haupt {
|
.haupt {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const props = defineProps({
|
|||||||
// Was die Filterleiste eingestellt hat
|
// Was die Filterleiste eingestellt hat
|
||||||
filter: { type: Object, default: () => ({}) },
|
filter: { type: Object, default: () => ({}) },
|
||||||
ansicht: { type: String, default: 'kompakt' },
|
ansicht: { type: String, default: 'kompakt' },
|
||||||
|
gesehenIds: { type: Set, default: () => new Set() },
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['open'])
|
const emit = defineEmits(['open'])
|
||||||
@@ -122,6 +123,7 @@ async function open(movie) {
|
|||||||
:key="movie.id"
|
:key="movie.id"
|
||||||
:movie="movie"
|
:movie="movie"
|
||||||
:ansicht="ansicht"
|
:ansicht="ansicht"
|
||||||
|
:gesehen="gesehenIds.has(movie.id)"
|
||||||
@open="open"
|
@open="open"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ const props = defineProps({
|
|||||||
// Die Karte öffnet mit dem stärksten Teil, nicht mit dem ersten
|
// Die Karte öffnet mit dem stärksten Teil, nicht mit dem ersten
|
||||||
start: { type: Number, default: 0 },
|
start: { type: Number, default: 0 },
|
||||||
aufDemRad: { type: Array, default: () => [] },
|
aufDemRad: { type: Array, default: () => [] },
|
||||||
|
// Kennungen der schon gelaufenen Filme
|
||||||
|
gesehenIds: { type: Set, default: () => new Set() },
|
||||||
ansicht: { type: String, default: 'kompakt' },
|
ansicht: { type: String, default: 'kompakt' },
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -21,6 +23,8 @@ const rating = computed(() =>
|
|||||||
|
|
||||||
const stehtAufDemRad = computed(() => props.aufDemRad.includes(current.value.id))
|
const stehtAufDemRad = computed(() => props.aufDemRad.includes(current.value.id))
|
||||||
|
|
||||||
|
const schonGesehen = computed(() => props.gesehenIds.has(current.value.id))
|
||||||
|
|
||||||
const shots = computed(() =>
|
const shots = computed(() =>
|
||||||
(current.value.images || []).slice(0, 4).map((pfad) => backdropUrl(pfad, 'w300'))
|
(current.value.images || []).slice(0, 4).map((pfad) => backdropUrl(pfad, 'w300'))
|
||||||
)
|
)
|
||||||
@@ -38,7 +42,7 @@ function step(delta) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<article class="card" :class="[ansicht, { 'auf-dem-rad': stehtAufDemRad }]">
|
<article class="card" :class="[ansicht, { 'auf-dem-rad': stehtAufDemRad, gesehen: schonGesehen }]">
|
||||||
<span v-if="stehtAufDemRad" class="rad-marke" title="Steht auf dem Rad">Rad</span>
|
<span v-if="stehtAufDemRad" class="rad-marke" title="Steht auf dem Rad">Rad</span>
|
||||||
<div class="haupt">
|
<div class="haupt">
|
||||||
<button class="poster" type="button" @click="$emit('open', current)">
|
<button class="poster" type="button" @click="$emit('open', current)">
|
||||||
@@ -91,6 +95,16 @@ function step(delta) {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
/* Schon gelaufen — die Karte tritt zurück, bleibt aber lesbar.
|
||||||
|
Beim Überfahren kommt sie zurück. */
|
||||||
|
.card.gesehen {
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card.gesehen:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const props = defineProps({
|
|||||||
// Beides hält die App schon aktuell — auch nach einem Namenswechsel
|
// Beides hält die App schon aktuell — auch nach einem Namenswechsel
|
||||||
merkliste: { type: Array, default: () => [] },
|
merkliste: { type: Array, default: () => [] },
|
||||||
mine: { type: Number, default: null },
|
mine: { type: Number, default: null },
|
||||||
|
gesehenIds: { type: Set, default: () => new Set() },
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['open', 'reset'])
|
const emit = defineEmits(['open', 'reset'])
|
||||||
|
|
||||||
@@ -319,7 +320,7 @@ async function oeffnen(item) {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="eintrag"
|
class="eintrag"
|
||||||
:class="{ eigen: item.id === mine }"
|
:class="{ eigen: item.id === mine, gesehen: gesehenIds.has(item.movie_id) }"
|
||||||
@click="oeffnen(item)"
|
@click="oeffnen(item)"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -563,6 +564,15 @@ async function oeffnen(item) {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Schon gelaufen — die Ziehung überspringt diesen Film */
|
||||||
|
.eintrag.gesehen {
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eintrag.gesehen:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.eintrag:hover {
|
.eintrag:hover {
|
||||||
background: var(--bg-soft);
|
background: var(--bg-soft);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user