mirror of
https://github.com/tompro/sattle.git
synced 2026-08-27 07:15:59 +00:00
feat: capability layer for clipboard, share and deep links with tests
This commit is contained in:
@@ -130,8 +130,8 @@
|
||||
|
||||
<div v-else class="column items-center q-gutter-sm">
|
||||
<div class="text-caption text-grey-5 text-center">
|
||||
Not watching right now — if the invoice gets paid, the sats are still
|
||||
claimed into your wallet automatically.
|
||||
Not watching right now — if the invoice gets paid, the sats are still claimed into your
|
||||
wallet automatically.
|
||||
</div>
|
||||
<q-btn
|
||||
outline
|
||||
@@ -157,8 +157,8 @@
|
||||
<template #avatar>
|
||||
<q-icon name="warning" color="warning" />
|
||||
</template>
|
||||
The note is in your wallet, but it could not be fully secured yet — the
|
||||
sender may still hold a copy. You can secure it later.
|
||||
The note is in your wallet, but it could not be fully secured yet — the sender may still
|
||||
hold a copy. You can secure it later.
|
||||
</q-banner>
|
||||
|
||||
<q-btn
|
||||
@@ -182,8 +182,8 @@
|
||||
<template v-if="trustNodeAlias"> ({{ trustNodeAlias }})</template>
|
||||
</div>
|
||||
<div class="text-caption text-grey-5 q-mb-md">
|
||||
Trusting saves the mint so it is offered next time. You can manage trusted
|
||||
mints in Settings.
|
||||
Trusting saves the mint so it is offered next time. You can manage trusted mints in
|
||||
Settings.
|
||||
</div>
|
||||
<div class="row q-gutter-sm justify-end">
|
||||
<q-btn flat no-caps color="grey-5" label="Just this once" @click="skipTrust" />
|
||||
@@ -203,9 +203,10 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { Notify, copyToClipboard } from 'quasar';
|
||||
import { Notify } from 'quasar';
|
||||
|
||||
import QrCode from '../QrCode.vue';
|
||||
import { writeClipboard } from '@/capabilities/clipboard';
|
||||
import { prepareMint, claimMintedNote } from '@/lnurlcash/ops';
|
||||
import type { ClaimedNote, PreparedMint } from '@/lnurlcash/ops';
|
||||
import type { NewBearer } from '@/lnurlcash/types';
|
||||
@@ -277,7 +278,9 @@ const defaultChoice = (): string => {
|
||||
|
||||
const formValid = computed(() => {
|
||||
if (!Number.isInteger(amountSats.value) || (amountSats.value ?? 0) < 1) return false;
|
||||
return mintChoice.value === CUSTOM_MINT ? customMint.value.trim() !== '' : mintChoice.value !== '';
|
||||
return mintChoice.value === CUSTOM_MINT
|
||||
? customMint.value.trim() !== ''
|
||||
: mintChoice.value !== '';
|
||||
});
|
||||
|
||||
const createInvoice = async () => {
|
||||
@@ -326,7 +329,7 @@ const feeSats = computed(() => grossSats.value - netSats.value);
|
||||
const copyInvoice = async () => {
|
||||
if (!prepared.value) return;
|
||||
try {
|
||||
await copyToClipboard(prepared.value.invoice);
|
||||
await writeClipboard(prepared.value.invoice);
|
||||
Notify.create({ type: 'positive', message: 'Invoice copied.' });
|
||||
} catch (err) {
|
||||
Notify.create({ type: 'negative', message: errorMessage(err) });
|
||||
@@ -380,7 +383,10 @@ const onClaimed = async (claimed: ClaimedNote, from: PreparedMint) => {
|
||||
receivedSats.value = displaySats(claimed.note.amount);
|
||||
receivedServer.value = server;
|
||||
rotationWarning.value = claimed.rotationError ?? '';
|
||||
activity.log('mint', `Received ${receivedSats.value.toLocaleString()} sats from ${server} over Lightning.`);
|
||||
activity.log(
|
||||
'mint',
|
||||
`Received ${receivedSats.value.toLocaleString()} sats from ${server} over Lightning.`,
|
||||
);
|
||||
const nodeInfo = mintAddressCacheInfo(from.nodeInfo, from.username);
|
||||
if (nodeInfo) mints.cacheNodeInfo(server, nodeInfo);
|
||||
Notify.create({
|
||||
@@ -420,7 +426,8 @@ const skipTrust = () => {
|
||||
showTrust.value = false;
|
||||
Notify.create({
|
||||
type: 'warning',
|
||||
message: 'Note added, but this mint is not in your trusted list yet — you can review it in Settings.',
|
||||
message:
|
||||
'Note added, but this mint is not in your trusted list yet — you can review it in Settings.',
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useQuasar } from 'quasar';
|
||||
import { decodeBolt11AmountMsat, isBolt11Invoice, resolveLnurlInput } from 'lnurlcash-kit';
|
||||
|
||||
import QrScanner from '@/components/QrScanner.vue';
|
||||
import { readClipboard } from '@/capabilities/clipboard';
|
||||
import { payWithBearers, UncertainOutcomeError } from '@/lnurlcash/ops';
|
||||
import type { CarveResult, PayOutcome } from '@/lnurlcash/ops';
|
||||
import type { NewBearer } from '@/lnurlcash/types';
|
||||
@@ -121,7 +122,7 @@ const onScanError = (message: string) => {
|
||||
|
||||
const paste = async () => {
|
||||
try {
|
||||
const text = await navigator.clipboard.readText();
|
||||
const text = await readClipboard();
|
||||
if (text) input.value = text.trim();
|
||||
} catch {
|
||||
toast('negative', "Couldn't read the clipboard - paste manually.");
|
||||
@@ -349,18 +350,11 @@ const closeResult = () => {
|
||||
</q-item>
|
||||
</q-list>
|
||||
<div class="text-caption text-grey-5 q-mt-md">
|
||||
If the mint charges a fee, it comes out of your change - you pay exactly the amount
|
||||
shown.
|
||||
If the mint charges a fee, it comes out of your change - you pay exactly the amount shown.
|
||||
</div>
|
||||
<div class="row justify-end q-gutter-sm q-mt-lg">
|
||||
<q-btn flat label="Back" color="grey-5" @click="step = 'input'" />
|
||||
<q-btn
|
||||
unelevated
|
||||
color="primary"
|
||||
text-color="dark"
|
||||
label="Pay now"
|
||||
@click="pay"
|
||||
/>
|
||||
<q-btn unelevated color="primary" text-color="dark" label="Pay now" @click="pay" />
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ import { useQuasar } from 'quasar';
|
||||
import { toBech32Lnurl } from 'lnurlcash-kit';
|
||||
|
||||
import QrCode from '@/components/QrCode.vue';
|
||||
import { writeClipboard } from '@/capabilities/clipboard';
|
||||
import { canShareText, shareText } from '@/capabilities/share';
|
||||
import { ensureExactAmount, UncertainOutcomeError } from '@/lnurlcash/ops';
|
||||
import type { CarveResult } from '@/lnurlcash/ops';
|
||||
import type { Bearer, NewBearer } from '@/lnurlcash/types';
|
||||
@@ -71,12 +73,9 @@ const canPrepare = computed(
|
||||
() => parsedAmount.value !== null && amountError.value === null && !preparing.value,
|
||||
);
|
||||
|
||||
const noteDisplayValue = computed(() =>
|
||||
prepared.value ? toBech32Lnurl(prepared.value.url) : '',
|
||||
);
|
||||
const noteDisplayValue = computed(() => (prepared.value ? toBech32Lnurl(prepared.value.url) : ''));
|
||||
|
||||
const canShare =
|
||||
typeof navigator !== 'undefined' && typeof navigator.share === 'function';
|
||||
const canShare = canShareText();
|
||||
|
||||
const reset = () => {
|
||||
step.value = 'amount';
|
||||
@@ -153,7 +152,7 @@ const prepare = async () => {
|
||||
|
||||
const copyNote = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(noteDisplayValue.value);
|
||||
await writeClipboard(noteDisplayValue.value);
|
||||
toast('positive', 'Note copied to clipboard.');
|
||||
} catch {
|
||||
toast('negative', "Couldn't copy - reveal the note and copy it manually.");
|
||||
@@ -162,7 +161,7 @@ const copyNote = async () => {
|
||||
|
||||
const shareNote = async () => {
|
||||
try {
|
||||
await navigator.share({ title: 'sattle bearer note', text: noteDisplayValue.value });
|
||||
await shareText('sattle bearer note', noteDisplayValue.value);
|
||||
} catch (err) {
|
||||
// the user dismissing the share sheet is not an error
|
||||
if (err instanceof DOMException && err.name === 'AbortError') return;
|
||||
@@ -302,7 +301,13 @@ const finishKeep = () => {
|
||||
:loading="removing"
|
||||
@click="finishRemove"
|
||||
/>
|
||||
<q-btn flat color="grey-5" label="Keep in wallet" :disable="removing" @click="finishKeep" />
|
||||
<q-btn
|
||||
flat
|
||||
color="grey-5"
|
||||
label="Keep in wallet"
|
||||
:disable="removing"
|
||||
@click="finishKeep"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
|
||||
Reference in New Issue
Block a user