Skip to content

Commit 4ac94d1

Browse files
committed
Improve images in coin list
1 parent bf95760 commit 4ac94d1

4 files changed

Lines changed: 136 additions & 3 deletions

File tree

frontend/src/components/CoinListView.vue

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,17 @@ import {onMounted, onUnmounted, ref} from "vue";
33
import {useRouter} from "vue-router";
44
import {arrayBufferToBase64} from "@/utils/bytes2img.js"
55
import StatusItem from "./StatusItem.vue"
6+
import {useSQLite} from "@/composables/useSQLite.js"
7+
import { useImageViewStore } from '@/stores/imageView'
68
79
const router = useRouter()
10+
const imageViewStore = useImageViewStore()
11+
12+
const {isLoading,
13+
error,
14+
status,
15+
openDatabase,
16+
executeQuery} = useSQLite()
817
918
const props = defineProps({
1019
coins_list: {
@@ -23,6 +32,7 @@ onUnmounted(async () => {
2332
})
2433
2534
const onOpenFile = () => {
35+
images.value = new Array(props.coins_list.length).fill('')
2636
}
2737
2838
defineExpose({
@@ -47,20 +57,100 @@ function generateDescription( coin_data ) {
4757
4858
return desc;
4959
}
60+
61+
const images = ref([])
62+
63+
const loadImage = async (index, coinId) => {
64+
let sql
65+
if (imageViewStore.currentImageView === 'obverse') {
66+
sql = `SELECT obverseimg.image FROM coins
67+
LEFT JOIN photos AS obverseimg ON coins.obverseimg = obverseimg.id
68+
WHERE coins.id=?`
69+
}
70+
else if (imageViewStore.currentImageView === 'reverse') {
71+
sql = `SELECT reverseimg.image FROM coins
72+
LEFT JOIN photos AS reverseimg ON coins.reverseimg = reverseimg.id
73+
WHERE coins.id=?`
74+
}
75+
else {
76+
sql = `SELECT obverseimg.image, reverseimg.image FROM coins
77+
LEFT JOIN photos AS obverseimg ON coins.obverseimg = obverseimg.id
78+
LEFT JOIN photos AS reverseimg ON coins.reverseimg = reverseimg.id
79+
WHERE coins.id=?`
80+
}
81+
82+
const results = await executeQuery(sql, [coinId,])
83+
let img
84+
if (imageViewStore.currentImageView === 'both') {
85+
const maxHeight = 100 // Step-down scaling for better quality
86+
let aspectRatio
87+
let img1 = null, img2 = null
88+
let newWidth1 = 0, newWidth2 = 0
89+
90+
if (results[0][0]) {
91+
const b64_img1 = arrayBufferToBase64(results[0][0])
92+
img1 = new Image()
93+
img1.src = b64_img1
94+
await img1.decode()
95+
aspectRatio = img1.naturalWidth / img1.naturalHeight
96+
newWidth1 = maxHeight * aspectRatio
97+
}
98+
99+
if (results[0][1]) {
100+
const b64_img2 = arrayBufferToBase64(results[0][1])
101+
img2 = new Image()
102+
img2.src = b64_img2
103+
await img2.decode()
104+
aspectRatio = img2.naturalWidth / img2.naturalHeight
105+
newWidth2 = maxHeight * aspectRatio
106+
}
107+
108+
const canvas = document.createElement('canvas')
109+
const ctx = canvas.getContext('2d')
110+
111+
canvas.width = newWidth1 + newWidth2
112+
canvas.height = maxHeight
113+
if (img1)
114+
ctx.drawImage(img1, 0, 0, newWidth1, maxHeight)
115+
if (img2)
116+
ctx.drawImage(img2, newWidth1, 0, newWidth2, maxHeight)
117+
img = canvas.toDataURL('image/png')
118+
}
119+
else {
120+
img = arrayBufferToBase64(results[0][0])
121+
}
122+
123+
images.value[index] = img
124+
}
50125
</script>
51126

52127
<template>
53128
<v-container class="pa-0 ma-0">
54129
<v-list lines="two">
55130
<v-list-item
56-
v-for="coin in coins_list"
131+
v-for="(coin, index) in coins_list"
57132
:key="coin[0]"
58133
:subtitle="generateDescription(coin).join(', ')"
59134
:title="coin[2]"
60135
@click="router.push('/coin/' + coin[0])"
61136
class="pa-1"
62137
>
63-
<template v-slot:prepend>
138+
<template v-slot:prepend v-if="imageViewStore.currentImageView === 'obverse'">
139+
<v-lazy :width="56">
140+
<v-img :src="images[index]" :width="56" max-height="56" :tmp="loadImage(index, coin[0])" />
141+
</v-lazy>
142+
</template>
143+
<template v-slot:prepend v-else-if="imageViewStore.currentImageView === 'reverse'">
144+
<v-lazy :width="56">
145+
<v-img :src="images[index]" :width="56" max-height="56" :tmp="loadImage(index, coin[0])" />
146+
</v-lazy>
147+
</template>
148+
<template v-slot:prepend v-else-if="imageViewStore.currentImageView === 'both'">
149+
<v-lazy :width="100">
150+
<v-img :src="images[index]" :width="100" max-height="56" :tmp="loadImage(index, coin[0])" />
151+
</v-lazy>
152+
</template>
153+
<template v-slot:prepend v-else>
64154
<v-img :src="arrayBufferToBase64(coin[1])" :width="100" max-height="56" />
65155
</template>
66156
<template v-slot:append>

frontend/src/components/SettingsView.vue

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<script setup>
2-
import {onMounted, onUnmounted, nextTick} from "vue";
2+
import {onMounted, onUnmounted} from "vue";
33
import { useTheme } from 'vuetify'
44
import { useThemeStore } from '@/stores/theme'
55
import { useStatusStore } from '@/stores/status'
6+
import { useImageViewStore } from '@/stores/imageView'
67
import { languageList, setLocale } from '@/i18n'
78
import i18n from '../i18n'
89
import {appTitle} from "@/composables/appTitle.js"
@@ -19,6 +20,14 @@ const statusItems = [
1920
]
2021
const statusStore = useStatusStore()
2122
23+
const imageViewItems = [
24+
{value: 'image', title: 'image_view_image'},
25+
{value: 'obverse', title: 'image_view_obverse'},
26+
{value: 'reverse', title: 'image_view_reverse'},
27+
{value: 'both', title: 'image_view_both'},
28+
]
29+
const imageViewStore = useImageViewStore()
30+
2231
const themeStore = useThemeStore()
2332
const appTheme = useTheme()
2433
@@ -84,6 +93,18 @@ const handleThemeChange = (theme) => {
8493
</v-list-item-action>
8594
</template>
8695
</v-list-item>
96+
<v-list-item :title="i18n.global.t('settings_image_view')">
97+
<template v-slot:append>
98+
<v-list-item-action start>
99+
<v-select
100+
v-model="imageViewStore.currentImageView"
101+
:items="imageViewItems"
102+
:item-title="item => i18n.global.t(item.title)"
103+
>
104+
</v-select>
105+
</v-list-item-action>
106+
</template>
107+
</v-list-item>
87108
</v-list>
88109
</v-container>
89110
</template>

frontend/src/i18n/en.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
"settings_theme": "Theme",
1010
"settings_language": "Language",
1111
"settings_status": "Show status as",
12+
"settings_image_view": "Show images in list",
13+
"image_view_image": "Image (faster)",
14+
"image_view_obverse": "Obverse",
15+
"image_view_reverse": "Reverse",
16+
"image_view_both": "Both",
1217
"wrong_version": "File has wrong or unknown format",
1318
"too_old_version": "File has an too old version. Please update it with desktop version of OpenNumismat",
1419
"old_version": "File has an old version. Please update it with desktop version of OpenNumismat",

frontend/src/stores/imageView.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { defineStore } from 'pinia'
2+
import { ref } from 'vue'
3+
4+
export const useImageViewStore = defineStore('imageView', () => {
5+
const currentImageView = ref('image')
6+
7+
const setImageView = (status) => {
8+
currentImageView.value = status
9+
}
10+
11+
return {
12+
currentImageView,
13+
setImageView,
14+
}
15+
}, {
16+
persist: true,
17+
})

0 commit comments

Comments
 (0)