display raw content read from qr

This commit is contained in:
tamaina 2025-08-31 20:00:48 +09:00
parent 83016acd3e
commit f72e3f61e9
2 changed files with 73 additions and 13 deletions

View File

@ -0,0 +1,43 @@
<template>
<MkFolder defaultOpen :withSpacer="false">
<template #label>{{ data.split('\n')[0] }}</template>
<template #header>
<MkTabs
v-model:tab="tab"
:tabs="[{
key: 'raw',
title: 'Raw',
}, {
key: 'mfm',
title: 'MFM',
}]"
/>
</template>
<div v-show="tab === 'raw'" class="_spacer" style="--MI_SPACER-min: 14px; --MI_SPACER-max: 22px;">
<MkCode :code="data" lang="text"/>
</div>
<div v-show="tab === 'mfm'" class="_gaps _spacer">
<Mfm :text="data" :nyaize="false"/>
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false"/>
</div>
</MkFolder>
</template>
<script lang="ts" setup>
import { defineProps, ref, computed } from 'vue';
import * as mfm from 'mfm-js';
import MkFolder from '@/components/MkFolder.vue';
import MkTabs from '@/components/MkTabs.vue';
import { extractUrlFromMfm } from '@/utility/extract-url-from-mfm';
import MkCode from '@/components/MkCode.vue';
import MkUrlPreview from '@/components/MkUrlPreview.vue';
const props = defineProps<{
data: string;
}>();
const tab = ref<'mfm' | 'raw'>('raw');
const parsed = computed(() => mfm.parse(props.data));
const urls = computed(() => extractUrlFromMfm(parsed.value));
</script>

View File

@ -41,6 +41,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkTab v-model="tab" :class="$style.tab">
<option value="users">{{ i18n.ts.users }}</option>
<option value="notes">{{ i18n.ts.notes }}</option>
<option value="all">{{ i18n.ts.all }}</option>
</MkTab>
</template>
<div v-if="tab === 'users'" :class="[$style.users, '_margin']" style="padding-bottom: var(--MI-margin);">
@ -49,6 +50,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-else-if="tab === 'notes'" class="_margin _gaps" style="padding-bottom: var(--MI-margin);">
<MkNote v-for="note in notes" :key="note.id" :note="note" :class="$style.note"/>
</div>
<div v-else-if="tab === 'all'" class="_margin _gaps" style="padding-bottom: var(--MI-margin);">
<MkQrReadRawViewer v-for="result in Array.from(results).reverse()" :key="result" :data="result"/>
</div>
</MkStickyContainer>
</div>
</MkStickyContainer>
@ -68,6 +72,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
import MkNote from '@/components/MkNote.vue';
import MkTab from '@/components/MkTab.vue';
import MkButton from '@/components/MkButton.vue';
import MkQrReadRawViewer from '@/pages/qr.read.raw-viewer.vue';
const LIST_RERENDER_INTERVAL = 1500;
@ -80,8 +85,11 @@ const scrollHeight = ref(window.innerHeight);
const scannerInstance = shallowRef<QrScanner | null>(null);
const tab = ref<'users' | 'notes'>('users');
const tab = ref<'users' | 'notes' | 'all'>('users');
// higher is recent
const results = ref(new Set<string>());
// lower is recent
const uris = ref<string[]>([]);
const sources = new Map<string, ApShowResponse | null>();
const users = ref<(misskey.entities.UserDetailed)[]>([]);
@ -92,10 +100,10 @@ const notesCount = ref(0);
const timer = ref<number | null>(null);
function updateLists() {
const results = uris.value.map(uri => sources.get(uri)).filter((r): r is ApShowResponse => !!r);
users.value = results.filter(r => r.type === 'User').map(r => r.object).filter((u): u is misskey.entities.UserDetailed => !!u);
const responses = uris.value.map(uri => sources.get(uri)).filter((r): r is ApShowResponse => !!r);
users.value = responses.filter(r => r.type === 'User').map(r => r.object).filter((u): u is misskey.entities.UserDetailed => !!u);
usersCount.value = users.value.length;
notes.value = results.filter(r => r.type === 'Note').map(r => r.object).filter((n): n is misskey.entities.Note => !!n);
notes.value = responses.filter(r => r.type === 'Note').map(r => r.object).filter((n): n is misskey.entities.Note => !!n);
notesCount.value = notes.value.length;
updateRequired.value = false;
}
@ -128,29 +136,38 @@ watch(tab, () => {
async function processResult(result: QrScanner.ScanResult) {
if (!result) return;
const uri = result.data.trim();
const trimmed = result.data.trim();
if (!trimmed) return;
const haveExisted = results.value.has(trimmed);
results.value.add(trimmed);
try {
new URL(uri);
new URL(trimmed);
} catch {
if (!haveExisted) {
tab.value = 'all';
}
return;
}
if (uris.value[0] !== uri) {
if (uris.value[0] !== trimmed) {
//
uris.value = [uri, ...uris.value.slice(0, 29).filter(u => u !== uri)];
uris.value = [trimmed, ...uris.value.slice(0, 29).filter(u => u !== trimmed)];
}
if (sources.has(uri)) return;
if (sources.has(trimmed)) return;
// Start fetching user info
sources.set(uri, null);
sources.set(trimmed, null);
await misskeyApi('ap/show', { uri })
await misskeyApi('ap/show', { uri: trimmed })
.then(data => {
if (data.type === 'User') {
sources.set(uri, data);
sources.set(trimmed, data);
tab.value = 'users';
} else if (data.type === 'Note') {
sources.set(uri, data);
sources.set(trimmed, data);
tab.value = 'notes';
}
updateLists();