Skip to content

Commit de421f9

Browse files
authored
Merge pull request #2383 from rommapp/console-ui-improvements-2
Selecting collections should change background
2 parents 5d702c0 + d5eebfe commit de421f9

13 files changed

Lines changed: 159 additions & 112 deletions

File tree

backend/handler/filesystem/resources_handler.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ async def _store_cover(
7979

8080
if ENABLE_SCHEDULED_CONVERT_IMAGES_TO_WEBP:
8181
self.image_converter.convert_to_webp(
82-
self.validate_path(f"{cover_file}/{size.value}.png")
82+
self.validate_path(f"{cover_file}/{size.value}.png"),
83+
force=True,
8384
)
8485
except httpx.TransportError as exc:
8586
log.error(f"Unable to fetch cover at {url_cover}: {str(exc)}")
@@ -93,7 +94,7 @@ async def _store_cover(
9394

9495
if ENABLE_SCHEDULED_CONVERT_IMAGES_TO_WEBP:
9596
self.image_converter.convert_to_webp(
96-
self.validate_path(f"{cover_file}/{size.value}.png")
97+
self.validate_path(f"{cover_file}/{size.value}.png"), force=True
9798
)
9899
except UnidentifiedImageError as exc:
99100
log.error(f"Unable to identify image {cover_file}: {str(exc)}")
@@ -173,6 +174,10 @@ async def store_artwork(
173174
with Image.open(artwork) as img:
174175
img.save(path_cover_l)
175176
self.resize_cover_to_small(img, save_path=str(path_cover_s))
177+
178+
if ENABLE_SCHEDULED_CONVERT_IMAGES_TO_WEBP:
179+
self.image_converter.convert_to_webp(path_cover_l, force=True)
180+
self.image_converter.convert_to_webp(path_cover_s, force=True)
176181
except UnidentifiedImageError as exc:
177182
log.error(
178183
f"Unable to identify image for {entity.fs_resources_path}: {str(exc)}"

backend/tasks/scheduled/convert_images_to_webp.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def _convert_image_mode(self, img: Image.Image) -> Image.Image:
5858
target_mode = self.MODE_CONVERSIONS.get(img.mode, "RGB")
5959
return img.convert(target_mode)
6060

61-
def convert_to_webp(self, image_path: Path) -> bool:
61+
def convert_to_webp(self, image_path: Path, force: bool = False) -> bool:
6262
"""Convert a single image to WebP format.
6363
Args:
6464
image_path: Path to the source image
@@ -68,7 +68,7 @@ def convert_to_webp(self, image_path: Path) -> bool:
6868
webp_path = image_path.with_suffix(".webp")
6969

7070
# Skip if WebP already exists
71-
if webp_path.exists():
71+
if webp_path.exists() and not force:
7272
log.debug(f"WebP already exists for {image_path}")
7373
return True
7474

frontend/src/components/Gallery/AppBar/Collection/CollectionInfoDrawer.vue

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,8 @@ const collectionCoverImage = computed(() =>
4747
getCollectionCoverImage(updatedCollection.value.name),
4848
);
4949
50-
emitter?.on("updateUrlCover", (url_cover) => {
51-
updatedCollection.value.url_cover = url_cover;
52-
setArtwork(url_cover);
50+
emitter?.on("updateUrlCover", (coverUrl) => {
51+
setArtwork(coverUrl);
5352
});
5453
5554
function showEditable() {
@@ -83,9 +82,10 @@ function previewImage(event: Event) {
8382
}
8483
}
8584
86-
function setArtwork(imageUrl: string) {
87-
if (!imageUrl) return;
88-
imagePreviewUrl.value = imageUrl;
85+
function setArtwork(coverUrl: string) {
86+
if (!coverUrl) return;
87+
updatedCollection.value.url_cover = coverUrl;
88+
imagePreviewUrl.value = coverUrl;
8989
removeCover.value = false;
9090
}
9191
@@ -185,7 +185,7 @@ async function updateCollection() {
185185
:show-title="false"
186186
:with-link="false"
187187
:collection="currentCollection"
188-
:src="imagePreviewUrl"
188+
:coverSrc="imagePreviewUrl"
189189
>
190190
<template v-if="isEditable" #append-inner>
191191
<v-btn-group rounded="0" divided density="compact">

frontend/src/components/common/Collection/Card.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const EXTENSION_REGEX = /\.png|\.jpg|\.jpeg$/;
2121
const props = withDefaults(
2222
defineProps<{
2323
collection: CollectionType;
24+
coverSrc?: string;
2425
transformScale?: boolean;
2526
showTitle?: boolean;
2627
titleOnHover?: boolean;
@@ -29,6 +30,7 @@ const props = withDefaults(
2930
enable3DTilt?: boolean;
3031
}>(),
3132
{
33+
coverSrc: undefined,
3234
transformScale: false,
3335
showTitle: true,
3436
titleOnHover: false,
@@ -54,6 +56,14 @@ const collectionCoverImage = computed(() =>
5456
);
5557
5658
watchEffect(() => {
59+
if (props.coverSrc) {
60+
memoizedCovers.value = {
61+
large: [props.coverSrc, props.coverSrc],
62+
small: [props.coverSrc, props.coverSrc],
63+
};
64+
return;
65+
}
66+
5767
// Check if it's a regular collection with covers or a smart collection with covers
5868
const isRegularOrSmartWithCovers =
5969
!props.collection.is_virtual &&

frontend/src/components/common/Collection/Dialog/CreateCollection.vue

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,8 @@ emitter?.on("showCreateCollectionDialog", () => {
2929
show.value = true;
3030
removeCover.value = false;
3131
});
32-
emitter?.on("updateUrlCover", (url_cover) => {
33-
if (!collection.value) return;
34-
collection.value.url_cover = url_cover;
35-
setArtwork(url_cover);
32+
emitter?.on("updateUrlCover", (coverUrl) => {
33+
setArtwork(coverUrl);
3634
});
3735
3836
const missingCoverImage = computed(() =>
@@ -57,9 +55,10 @@ function previewImage(event: Event) {
5755
}
5856
}
5957
60-
function setArtwork(imageUrl: string) {
61-
if (!imageUrl) return;
62-
imagePreviewUrl.value = imageUrl;
58+
function setArtwork(coverUrl: string) {
59+
if (!coverUrl || !collection.value) return;
60+
collection.value.url_cover = coverUrl;
61+
imagePreviewUrl.value = coverUrl;
6362
removeCover.value = false;
6463
}
6564
@@ -165,7 +164,7 @@ function closeDialog() {
165164
:show-title="false"
166165
:with-link="false"
167166
:collection="collection"
168-
:src="imagePreviewUrl"
167+
:coverSrc="imagePreviewUrl"
169168
title-on-hover
170169
>
171170
<template #append-inner>

frontend/src/components/common/Game/Card/Base.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const EXTENSION_REGEX = /\.png|\.jpg|\.jpeg$/;
3333
const props = withDefaults(
3434
defineProps<{
3535
rom: SimpleRom | SearchRomSchema;
36+
coverSrc?: string;
3637
aspectRatio?: string | number;
3738
width?: string | number;
3839
height?: string | number;
@@ -49,6 +50,7 @@ const props = withDefaults(
4950
enable3DTilt?: boolean;
5051
}>(),
5152
{
53+
coverSrc: undefined,
5254
aspectRatio: undefined,
5355
width: undefined,
5456
height: undefined,
@@ -142,6 +144,7 @@ const isWebpEnabled = computed(
142144
);
143145
144146
const largeCover = computed(() => {
147+
if (props.coverSrc) return props.coverSrc;
145148
if (!romsStore.isSimpleRom(props.rom))
146149
return (
147150
props.rom.igdb_url_cover ||
@@ -155,6 +158,7 @@ const largeCover = computed(() => {
155158
});
156159
157160
const smallCover = computed(() => {
161+
if (props.coverSrc) return props.coverSrc;
158162
if (!romsStore.isSimpleRom(props.rom)) return "";
159163
const pathCoverSmall = isWebpEnabled.value
160164
? props.rom.path_cover_small?.replace(EXTENSION_REGEX, ".webp")

frontend/src/components/common/Game/Dialog/EditRom.vue

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ emitter?.on("showEditRomDialog", (romToEdit: UpdateRom | undefined) => {
3636
removeCover.value = false;
3737
});
3838
emitter?.on("updateUrlCover", (url_cover) => {
39-
if (!rom.value) return;
40-
rom.value.url_cover = url_cover;
4139
setArtwork(url_cover);
4240
});
4341
const computedAspectRatio = computed(() => {
@@ -68,9 +66,10 @@ function previewImage(event: Event) {
6866
}
6967
}
7068
71-
function setArtwork(imageUrl: string) {
72-
if (!imageUrl) return;
73-
imagePreviewUrl.value = imageUrl;
69+
function setArtwork(coverUrl: string) {
70+
if (!coverUrl || !rom.value) return;
71+
rom.value.url_cover = coverUrl;
72+
imagePreviewUrl.value = coverUrl;
7473
removeCover.value = false;
7574
}
7675
@@ -211,7 +210,7 @@ function closeDialog() {
211210
<game-card
212211
width="240"
213212
:rom="rom"
214-
:src="imagePreviewUrl"
213+
:coverSrc="imagePreviewUrl"
215214
disableViewTransition
216215
:showPlatformIcon="false"
217216
:showActionBar="false"

frontend/src/console/components/CollectionCard.vue

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
<script setup lang="ts">
2-
import { computed, onMounted, ref, watchEffect, useTemplateRef } from "vue";
2+
import {
3+
computed,
4+
onMounted,
5+
ref,
6+
watchEffect,
7+
useTemplateRef,
8+
watch,
9+
} from "vue";
310
import {
411
collectionElementRegistry,
512
smartCollectionElementRegistry,
@@ -17,7 +24,14 @@ const props = defineProps<{
1724
selected?: boolean;
1825
loaded?: boolean;
1926
}>();
20-
const emit = defineEmits(["click", "mouseenter", "focus", "loaded"]);
27+
const emit = defineEmits([
28+
"click",
29+
"mouseenter",
30+
"focus",
31+
"loaded",
32+
"select",
33+
"deselect",
34+
]);
2135
const collectionCardRef = useTemplateRef<HTMLButtonElement>(
2236
"collection-card-ref",
2337
);
@@ -29,7 +43,7 @@ const memoizedCovers = ref({
2943
small: ["", ""],
3044
});
3145
32-
const collectionCoverImage = computed(() =>
46+
const fallbackCollectionCover = computed(() =>
3347
props.collection.name?.toLowerCase() == "favourites"
3448
? getFavoriteCoverImage(props.collection.name)
3549
: getCollectionCoverImage(props.collection.name),
@@ -69,8 +83,8 @@ watchEffect(() => {
6983
7084
if (largeCoverUrls.length < 2) {
7185
memoizedCovers.value = {
72-
large: [collectionCoverImage.value, collectionCoverImage.value],
73-
small: [collectionCoverImage.value, collectionCoverImage.value],
86+
large: [fallbackCollectionCover.value, fallbackCollectionCover.value],
87+
small: [fallbackCollectionCover.value, fallbackCollectionCover.value],
7488
};
7589
return;
7690
}
@@ -87,6 +101,22 @@ watchEffect(() => {
87101
const firstLargeCover = computed(() => memoizedCovers.value.large[0]);
88102
const secondLargeCover = computed(() => memoizedCovers.value.large[1]);
89103
104+
watch(
105+
() => props.selected,
106+
(isSelected) => {
107+
if (
108+
isSelected &&
109+
firstLargeCover.value &&
110+
firstLargeCover.value !== fallbackCollectionCover.value
111+
) {
112+
emit("select", firstLargeCover.value);
113+
} else if (isSelected) {
114+
emit("deselect");
115+
}
116+
},
117+
{ immediate: true },
118+
);
119+
90120
onMounted(() => {
91121
if (!collectionCardRef.value) return;
92122
if (props.collection.is_smart) {

frontend/src/console/components/GameCard.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const props = defineProps<{
1515
isRecent?: boolean;
1616
registry?: "recent" | "gamesList";
1717
}>();
18+
1819
const coverSrc = computed(
1920
() =>
2021
props.rom.path_cover_large ||
@@ -43,7 +44,9 @@ watch(
4344
() => props.selected,
4445
(isSelected) => {
4546
if (isSelected && coverSrc.value) {
46-
emit("select", props.rom);
47+
emit("select", coverSrc.value);
48+
} else if (isSelected) {
49+
emit("deselect");
4750
}
4851
},
4952
{ immediate: true },
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { ref } from "vue";
2+
import { useConsoleTheme } from "@/stores/consoleTheme";
3+
4+
const selectedBackgroundArt = ref<string | null>(null);
5+
6+
export default function useBackgroundArt() {
7+
const consoleTheme = useConsoleTheme();
8+
const setSelectedBackgroundArt = (url: string) => {
9+
selectedBackgroundArt.value = url;
10+
if (url) {
11+
document.documentElement.style.setProperty(
12+
"--theme-background",
13+
`url("${url}")`,
14+
);
15+
}
16+
};
17+
18+
const clearSelectedBackgroundArt = () => {
19+
selectedBackgroundArt.value = null;
20+
consoleTheme.updateBackgroundCSS();
21+
};
22+
23+
return {
24+
setSelectedBackgroundArt,
25+
clearSelectedBackgroundArt,
26+
selectedBackgroundArt,
27+
};
28+
}

0 commit comments

Comments
 (0)