Cashu: PWA install button (#1455)
This commit is contained in:
parent
9f177dea98
commit
754db04d99
1 changed files with 87 additions and 47 deletions
|
|
@ -370,7 +370,7 @@ page_container %}
|
||||||
<div class="col-4 q-pt-xs">
|
<div class="col-4 q-pt-xs">
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<q-btn
|
<q-btn
|
||||||
class="q-mx-xs q-px-none"
|
class="q-mx-xs q-px-none q-my-sm"
|
||||||
size="0.5rem"
|
size="0.5rem"
|
||||||
rectangle
|
rectangle
|
||||||
color="warning"
|
color="warning"
|
||||||
|
|
@ -380,7 +380,7 @@ page_container %}
|
||||||
><q-tooltip>Warning</q-tooltip></q-btn
|
><q-tooltip>Warning</q-tooltip></q-btn
|
||||||
>
|
>
|
||||||
<q-btn
|
<q-btn
|
||||||
class="q-mx-xs q-px-none"
|
class="q-mx-xs q-px-none q-my-sm"
|
||||||
size="0.5rem"
|
size="0.5rem"
|
||||||
outline
|
outline
|
||||||
rectangle
|
rectangle
|
||||||
|
|
@ -389,6 +389,15 @@ page_container %}
|
||||||
@click="getLocalstorageToFile"
|
@click="getLocalstorageToFile"
|
||||||
><q-tooltip>Download wallet backup</q-tooltip></q-btn
|
><q-tooltip>Download wallet backup</q-tooltip></q-btn
|
||||||
>
|
>
|
||||||
|
<q-btn
|
||||||
|
class="q-mx-xs q-px-none q-my-sm"
|
||||||
|
outline
|
||||||
|
size="0.5rem"
|
||||||
|
v-if="getPWADisplayMode()=='browser' && deferredPWAInstallPrompt != null"
|
||||||
|
color="primary"
|
||||||
|
@click="triggerPWAInstall()"
|
||||||
|
><b>Install</b><q-tooltip>Install Cashu</q-tooltip></q-btn
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4 q-pt-none">
|
<div class="col-4 q-pt-none">
|
||||||
|
|
@ -708,8 +717,20 @@ page_container %}
|
||||||
Backup button to download a copy of your tokens.
|
Backup button to download a copy of your tokens.
|
||||||
</p>
|
</p>
|
||||||
<div class="row q-mt-lg">
|
<div class="row q-mt-lg">
|
||||||
<q-btn outline color="grey" @click="copyText(baseURL)"
|
<q-btn
|
||||||
>Copy wallet URL</q-btn
|
outline
|
||||||
|
class="q-mx-sm"
|
||||||
|
v-if="getPWADisplayMode()=='browser' && deferredPWAInstallPrompt != null"
|
||||||
|
color="primary"
|
||||||
|
@click="triggerPWAInstall()"
|
||||||
|
>Install Cashu</q-btn
|
||||||
|
>
|
||||||
|
<q-btn
|
||||||
|
outline
|
||||||
|
color="grey"
|
||||||
|
class="q-mx-sm"
|
||||||
|
@click="copyText(baseURL)"
|
||||||
|
>Copy URL</q-btn
|
||||||
>
|
>
|
||||||
<q-btn
|
<q-btn
|
||||||
v-close-popup
|
v-close-popup
|
||||||
|
|
@ -1033,6 +1054,7 @@ page_container %}
|
||||||
keys: '',
|
keys: '',
|
||||||
proofs: [],
|
proofs: [],
|
||||||
activeProofs: [],
|
activeProofs: [],
|
||||||
|
deferredPWAInstallPrompt: null,
|
||||||
invoicesCashu: [],
|
invoicesCashu: [],
|
||||||
historyTokens: [],
|
historyTokens: [],
|
||||||
invoiceData: {
|
invoiceData: {
|
||||||
|
|
@ -1771,8 +1793,8 @@ page_container %}
|
||||||
|
|
||||||
requestMint: async function () {
|
requestMint: async function () {
|
||||||
/*
|
/*
|
||||||
gets an invoice from the mint to get new tokens
|
gets an invoice from the mint to get new tokens
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
const {data} = await axios.get(
|
const {data} = await axios.get(
|
||||||
`${this.activeMintURL}/mint?amount=${this.invoiceData.amount}`
|
`${this.activeMintURL}/mint?amount=${this.invoiceData.amount}`
|
||||||
|
|
@ -1802,9 +1824,9 @@ page_container %}
|
||||||
|
|
||||||
mintApi: async function (amounts, payment_hash, verbose = true) {
|
mintApi: async function (amounts, payment_hash, verbose = true) {
|
||||||
/*
|
/*
|
||||||
asks the mint to check whether the invoice with payment_hash has been paid
|
asks the mint to check whether the invoice with payment_hash has been paid
|
||||||
and requests signing of the attached outputs.
|
and requests signing of the attached outputs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let secrets = await this.generateSecrets(amounts)
|
let secrets = await this.generateSecrets(amounts)
|
||||||
|
|
@ -1870,9 +1892,9 @@ page_container %}
|
||||||
|
|
||||||
split: async function (proofs, amount) {
|
split: async function (proofs, amount) {
|
||||||
/*
|
/*
|
||||||
supplies proofs and requests a split from the mint of these
|
supplies proofs and requests a split from the mint of these
|
||||||
proofs at a specific amount
|
proofs at a specific amount
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
if (proofs.length == 0) {
|
if (proofs.length == 0) {
|
||||||
throw new Error('no proofs provided.')
|
throw new Error('no proofs provided.')
|
||||||
|
|
@ -1945,11 +1967,11 @@ page_container %}
|
||||||
|
|
||||||
splitToSend: async function (proofs, amount, invlalidate = false) {
|
splitToSend: async function (proofs, amount, invlalidate = false) {
|
||||||
/*
|
/*
|
||||||
splits proofs so the user can keep firstProofs, send scndProofs.
|
splits proofs so the user can keep firstProofs, send scndProofs.
|
||||||
then sets scndProofs as reserved.
|
then sets scndProofs as reserved.
|
||||||
|
|
||||||
if invalidate, scndProofs (the one to send) are invalidated
|
if invalidate, scndProofs (the one to send) are invalidated
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
const spendableProofs = proofs.filter(p => !p.reserved)
|
const spendableProofs = proofs.filter(p => !p.reserved)
|
||||||
if (this.sumProofs(spendableProofs) < amount) {
|
if (this.sumProofs(spendableProofs) < amount) {
|
||||||
|
|
@ -1992,8 +2014,8 @@ page_container %}
|
||||||
|
|
||||||
redeem: async function () {
|
redeem: async function () {
|
||||||
/*
|
/*
|
||||||
uses split to receive new tokens.
|
uses split to receive new tokens.
|
||||||
*/
|
*/
|
||||||
this.showReceiveTokens = false
|
this.showReceiveTokens = false
|
||||||
console.log('### receive tokens', this.receiveData.tokensBase64)
|
console.log('### receive tokens', this.receiveData.tokensBase64)
|
||||||
try {
|
try {
|
||||||
|
|
@ -2055,8 +2077,8 @@ page_container %}
|
||||||
|
|
||||||
sendTokens: async function () {
|
sendTokens: async function () {
|
||||||
/*
|
/*
|
||||||
calls splitToSend, displays token and kicks off the spendableWorker
|
calls splitToSend, displays token and kicks off the spendableWorker
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
// keep firstProofs, send scndProofs and delete them (invalidate=true)
|
// keep firstProofs, send scndProofs and delete them (invalidate=true)
|
||||||
let {fristProofs, scndProofs} = await this.splitToSend(
|
let {fristProofs, scndProofs} = await this.splitToSend(
|
||||||
|
|
@ -2165,9 +2187,9 @@ page_container %}
|
||||||
|
|
||||||
checkProofsSpendable: async function (proofs, update_history = false) {
|
checkProofsSpendable: async function (proofs, update_history = false) {
|
||||||
/*
|
/*
|
||||||
checks with the mint whether an array of proofs is still
|
checks with the mint whether an array of proofs is still
|
||||||
spendable or already invalidated
|
spendable or already invalidated
|
||||||
*/
|
*/
|
||||||
if (proofs.length == 0) {
|
if (proofs.length == 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -2323,9 +2345,9 @@ page_container %}
|
||||||
|
|
||||||
checkTokenSpendable: async function (token, verbose = true) {
|
checkTokenSpendable: async function (token, verbose = true) {
|
||||||
/*
|
/*
|
||||||
checks whether a base64-encoded token (from the history table) has been spent already.
|
checks whether a base64-encoded token (from the history table) has been spent already.
|
||||||
if it is spent, the appropraite entry in the history table is set to paid.
|
if it is spent, the appropraite entry in the history table is set to paid.
|
||||||
*/
|
*/
|
||||||
const tokenJson = JSON.parse(atob(token))
|
const tokenJson = JSON.parse(atob(token))
|
||||||
const proofs = tokenJson.proofs
|
const proofs = tokenJson.proofs
|
||||||
|
|
||||||
|
|
@ -2443,7 +2465,6 @@ page_container %}
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
////////////// UI HELPERS /////////////
|
|
||||||
assertMintError: function (response, verbose = true) {
|
assertMintError: function (response, verbose = true) {
|
||||||
if (response.error != null) {
|
if (response.error != null) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
|
@ -2452,6 +2473,32 @@ page_container %}
|
||||||
throw new Error(`Mint error: ${response.error}`)
|
throw new Error(`Mint error: ${response.error}`)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
////////////// UI HELPERS /////////////
|
||||||
|
getPWADisplayMode: function () {
|
||||||
|
const isStandalone = window.matchMedia(
|
||||||
|
'(display-mode: standalone)'
|
||||||
|
).matches
|
||||||
|
if (document.referrer.startsWith('android-app://')) {
|
||||||
|
return 'twa'
|
||||||
|
} else if (navigator.standalone || isStandalone) {
|
||||||
|
return 'standalone'
|
||||||
|
}
|
||||||
|
return 'browser'
|
||||||
|
},
|
||||||
|
triggerPWAInstall: function () {
|
||||||
|
// Show the install prompt
|
||||||
|
this.deferredPWAInstallPrompt.prompt()
|
||||||
|
// Wait for the user to respond to the prompt
|
||||||
|
this.deferredPWAInstallPrompt.userChoice.then(choiceResult => {
|
||||||
|
if (choiceResult.outcome === 'accepted') {
|
||||||
|
console.log('User accepted the install prompt')
|
||||||
|
this.setWelcomeDialogSeen()
|
||||||
|
} else {
|
||||||
|
console.log('User dismissed the install prompt')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
showNoMintsWarning: function () {
|
showNoMintsWarning: function () {
|
||||||
if (!this.activeMintURL) {
|
if (!this.activeMintURL) {
|
||||||
this.walletURL = this.baseURL
|
this.walletURL = this.baseURL
|
||||||
|
|
@ -2680,26 +2727,6 @@ page_container %}
|
||||||
await this.fetchMintKeys()
|
await this.fetchMintKeys()
|
||||||
}
|
}
|
||||||
|
|
||||||
// const keysJson = localStorage.getItem(this.mintKey(this.mintId, 'keys'))
|
|
||||||
// if (!keysJson) {
|
|
||||||
// if (this.activeMintURL.length) {
|
|
||||||
// this.fetchMintKeys()
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// this.keys = JSON.parse(keysJson)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// this.invoicesCashu = JSON.parse(
|
|
||||||
// localStorage.getItem(this.mintKey(this.mintId, 'invoicesCashu')) || '[]'
|
|
||||||
// )
|
|
||||||
|
|
||||||
// this.historyTokens = JSON.parse(
|
|
||||||
// localStorage.getItem(this.mintKey(this.mintId, 'historyTokens')) || '[]'
|
|
||||||
// )
|
|
||||||
// this.proofs = JSON.parse(
|
|
||||||
// localStorage.getItem(this.mintKey(this.mintId, 'proofs')) || '[]'
|
|
||||||
// )
|
|
||||||
|
|
||||||
this.invoicesCashu = JSON.parse(
|
this.invoicesCashu = JSON.parse(
|
||||||
localStorage.getItem('cashu.invoicesCashu') || '[]'
|
localStorage.getItem('cashu.invoicesCashu') || '[]'
|
||||||
)
|
)
|
||||||
|
|
@ -2752,7 +2779,20 @@ page_container %}
|
||||||
this.activateMint(startupMintUrl)
|
this.activateMint(startupMintUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize deferredPWAInstallPrompt for use later to show browser install prompt.
|
||||||
this.showWelcomeDialog()
|
this.showWelcomeDialog()
|
||||||
|
|
||||||
|
// register event listener for PWA install prompt
|
||||||
|
window.addEventListener('beforeinstallprompt', e => {
|
||||||
|
// Prevent the mini-infobar from appearing on mobile
|
||||||
|
// e.preventDefault()
|
||||||
|
// Stash the event so it can be triggered later.
|
||||||
|
this.deferredPWAInstallPrompt = e
|
||||||
|
console.log(
|
||||||
|
`'beforeinstallprompt' event was fired.`,
|
||||||
|
this.getPWADisplayMode()
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue