Skip to content

Commit

Permalink
✨ 103 feature show title picture (#108)
Browse files Browse the repository at this point in the history
* ✨ added image preview and fallback image to adlist

* adjusted api to deliver the blob

* ✨ introduced new image component

* 💫 improved lazy loading of image

* 🍺 adjusted image type

---------

Co-authored-by: jannik.lange <[email protected]>
  • Loading branch information
langehm and jannik.lange authored Jan 21, 2025
1 parent 6e1930f commit 50a5bac
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.awt.*;
import java.awt.image.BufferedImage;
Expand Down Expand Up @@ -39,11 +40,13 @@ public class ImageService {
@Autowired
private ImageMapper mapper;

@Transactional
public SwbImageTO getImageTO(final long id) {
final SwbImage image = repository.getOne(id);
return mapper.toSwbImageTO(image);
}

@Transactional
public SwbImage getImage(final long id) {
return repository.getOne(id);
}
Expand Down
1 change: 1 addition & 0 deletions anzeigen-frontend/src/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const DEFAULT_BOARD_QUERIES = {
sortBy: "title",
order: "asc",
};
export const PREVIEW_IMAGE_FILE_URI_PREFIX = "data:image/jpeg;base64,";
export const QUERY_NAME_ORDER = "order";
export const QUERY_NAME_SORTBY = "sortBy";
export const QUERY_NAME_TYPE = "type";
Expand Down
27 changes: 20 additions & 7 deletions anzeigen-frontend/src/components/Ad/AdCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,25 @@
cols="12"
sm="3"
>
<v-img
cover
max-height="200"
src="https://picsum.photos/300"
class="cursor-pointer"
@click="routeTo"
/>
<div class="h-100 d-flex align-content-center">
<v-img
v-if="adTo.imagePreviewBase64"
rounded
cover
max-height="200"
:src="PREVIEW_IMAGE_FILE_URI_PREFIX + adTo.imagePreviewBase64"
class="cursor-pointer"
@click="routeTo"
/>
<v-icon
v-else
class="w-100 h-100 rounded"
style="background-color: #eeeeee"
icon="mdi-camera"
color="accent"
size="164"
/>
</div>
</v-col>
<v-col
cols="12"
Expand Down Expand Up @@ -97,6 +109,7 @@ import AdEditButton from "@/components/Ad/AdEditButton.vue";
import AdPrice from "@/components/Ad/AdPrice.vue";
import AdViewCountChip from "@/components/Ad/AdViewCountChip.vue";
import { useDialogEventBus } from "@/composables/useEventBus";
import { PREVIEW_IMAGE_FILE_URI_PREFIX } from "@/Constants";
import { useUserStore } from "@/stores/user";
const router = useRouter();
Expand Down
34 changes: 34 additions & 0 deletions anzeigen-frontend/src/components/Ad/Details/AdImageDisplay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<template>
<v-img
max-height="500"
class="rounded image-background-color"
:lazy-src="PREVIEW_IMAGE_FILE_URI_PREFIX + adDetails.imagePreviewBase64"
:src="PREVIEW_IMAGE_FILE_URI_PREFIX + adImageData?.imageBase64"
/>
</template>

<script setup lang="ts">
import type { AdTO } from "@/api/swbrett";
import { onMounted } from "vue";
import { useGetAdImage } from "@/composables/api/useFilesApi";
import { PREVIEW_IMAGE_FILE_URI_PREFIX } from "@/Constants";
const { call: getAdImage, data: adImageData } = useGetAdImage();
const { adDetails } = defineProps<{
adDetails: Readonly<AdTO>;
}>();
/**
* Loads the "big" image upon mounting this component
*/
onMounted(async () => {
if (adDetails.adImg?.id) {
await getAdImage({ id: adDetails.adImg?.id });
}
});
</script>

<style scoped></style>
17 changes: 10 additions & 7 deletions anzeigen-frontend/src/components/Ad/Details/AdOverview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@
<v-col>
<ad-display-sheet
class="pa-2 d-flex justify-center"
style="height: 300px"
style="max-height: 500px"
>
<v-img
<ad-image-display
v-if="adDetails.imagePreviewBase64"
max-height="300"
:src="adDetails.imagePreviewBase64"
:ad-details="adDetails"
/>
<v-icon
v-else
class="w-100 h-100"
style="background-color: #eeeeee"
class="w-100 h-100 rounded image-background-color"
icon="mdi-camera"
color="accent"
size="196"
Expand Down Expand Up @@ -142,6 +140,7 @@ import { useDateFormat } from "@vueuse/shared";
import { computed } from "vue";
import AdPrice from "@/components/Ad/AdPrice.vue";
import AdImageDisplay from "@/components/Ad/Details/AdImageDisplay.vue";
import AdDisplayCard from "@/components/common/AdDisplayCard.vue";
import AdDisplaySheet from "@/components/common/AdDisplaySheet.vue";
import IconText from "@/components/common/IconText.vue";
Expand All @@ -166,4 +165,8 @@ const routeToUser = (id: number) => {
};
</script>

<style scoped></style>
<style scoped>
.image-background-color {
background-color: #eeeeee;
}
</style>
15 changes: 15 additions & 0 deletions anzeigen-frontend/src/composables/api/useFilesApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { GetImageRequest, SwbImageTO } from "@/api/swbrett";

import { inject } from "vue";

import { useApiCall } from "@/composables/api/useApiCall";
import { DEFAULT_API_KEY } from "@/composables/useApi";

export const useGetAdImage = () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const api = inject(DEFAULT_API_KEY)!;

return useApiCall<GetImageRequest, SwbImageTO>((params: GetImageRequest) =>
api.getImage(params)
);
};

0 comments on commit 50a5bac

Please sign in to comment.