Local Notifications

This commit is contained in:
Hanh 2022-10-13 09:25:29 +08:00
parent 99166c8567
commit d1a761ea73
21 changed files with 306 additions and 104 deletions

View File

@ -34,7 +34,7 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 31
compileSdkVersion 33
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
@ -59,6 +59,7 @@ android {
storePassword key
}
}
buildTypes {
release {
signingConfig signingConfigs.release

View File

@ -10,7 +10,9 @@
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
android:windowSoftInputMode="adjustResize"
android:showWhenLocked="true"
android:turnScreenOn="true">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

View File

@ -1,6 +1,8 @@
#!/bin/sh
set -x
FLUTTER_VERSION=3.3.4
ROOT_DIR=$1
if [ "$ROOT_DIR" == "" ]; then
ROOT_DIR="/root"
@ -11,11 +13,12 @@ if [ "$DL_DIR" == "" ]; then
DL_DIR="/tmp"
fi
sudo pacman -Sy --noconfirm unzip jdk8-openjdk wget
wget -qP $DL_DIR -N https://dl.google.com/android/repository/commandlinetools-linux-7583922_latest.zip
wget -qP $DL_DIR -N https://dl.google.com/android/repository/android-ndk-r21e-linux-x86_64.zip
wget -qP $DL_DIR -N https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.3.3-stable.tar.xz
wget -qP $DL_DIR -N https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_$FLUTTER_VERSION-stable.tar.xz
wget -qP $DL_DIR -N https://download.z.cash/downloads/sapling-output.params
wget -qP $DL_DIR -N https://download.z.cash/downloads/sapling-spend.params
@ -29,7 +32,7 @@ yes | ./sdkmanager --sdk_root=$ANDROID_SDK_ROOT --licenses &&
yes | ./sdkmanager --sdk_root=$ANDROID_SDK_ROOT "platform-tools" "platforms;android-31")
(cd $ANDROID_SDK_ROOT;unzip -o $DL_DIR/android-ndk-r21e-linux-x86_64.zip)
(cd $ROOT_DIR;tar xvf $DL_DIR/flutter_linux_3.3.3-stable.tar.xz)
(cd $ROOT_DIR;tar xvf $DL_DIR/flutter_linux_$FLUTTER_VERSION-stable.tar.xz)
mkdir -p $HOME/.zcash-params
cp $DL_DIR/sapling-output.params $DL_DIR/sapling-spend.params $HOME/.zcash-params
@ -37,4 +40,4 @@ cp $DL_DIR/sapling-output.params $DL_DIR/sapling-spend.params $HOME/.zcash-param
export ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/android-ndk-r21e
export PATH=$PATH:$ROOT_DIR/flutter/bin
rm $DL_DIR/android-ndk-r21e-linux-x86_64.zip $DL_DIR/commandlinetools-linux-7583922_latest.zip $DL_DIR/flutter_linux_3.3.3-stable.tar.xz
rm $DL_DIR/android-ndk-r21e-linux-x86_64.zip $DL_DIR/commandlinetools-linux-7583922_latest.zip $DL_DIR/flutter_linux_$FLUTTER_VERSION-stable.tar.xz

View File

@ -68,7 +68,7 @@ class SyncStatusState extends State<SyncStatusWidget> {
final startHeight = syncStatus.startSyncedHeight;
final timestamp = syncStatus.timestamp?.timeAgo() ?? s.na;
final latestHeight = syncStatus.latestHeight;
final remaining = syncedHeight != null ? max(latestHeight-syncedHeight, 0) : 0;
final remaining = max(latestHeight-syncedHeight, 0);
final int? percent;
if (startHeight != null) {
final total = latestHeight - startHeight;
@ -301,7 +301,7 @@ class BalanceWidget extends StatelessWidget {
final flat = settings.flat;
final hide = settings.autoHide && flat;
final showTAddr = active.showTAddr;
final balance = showTAddr ? active.tbalance : active.balances.balance;
final balance = showTAddr ? active.tbalance : active.balances?.balance ?? 0;
final balanceColor = !showTAddr
? theme.colorScheme.primary
: theme.colorScheme.secondary;
@ -345,7 +345,7 @@ class MemPoolWidget extends StatelessWidget {
Widget build(BuildContext context) => Observer(builder: (context) {
final b = active.balances;
final theme = Theme.of(context);
final unconfirmedBalance = b.unconfirmedBalance;
final unconfirmedBalance = b?.unconfirmedBalance ?? 0;
if (unconfirmedBalance == 0) return Container();
final unconfirmedStyle = TextStyle(
color: amountColor(context, unconfirmedBalance));

View File

@ -129,7 +129,7 @@ abstract class _ActiveAccount with Store {
Account account = emptyAccount;
CoinBase coinDef = zcash;
bool canPay = false;
@observable Balances balances = Balances.zero;
@observable Balances? balances = null;
@observable String taddress = "";
int tbalance = 0;
@ -247,7 +247,7 @@ abstract class _ActiveAccount with Store {
}
showTAddr = false;
balances = Balances.zero;
balances = null;
draftRecipient = null;
await update();
@ -286,13 +286,18 @@ abstract class _ActiveAccount with Store {
@action
Future<void> updateBalances() async {
final dbr = DbReader(coin, id);
balances = await dbr.getBalance(syncStatus.confirmHeight);
final curBalances = await dbr.getBalance(syncStatus.confirmHeight);
final prevBalances = balances;
if (prevBalances != null) {
showBalanceNotification(prevBalances, curBalances);
}
balances = curBalances;
}
@action
Future<void> updateUnconfirmedBalance() async {
final unconfirmedBalance = await WarpApi.mempoolSync();
balances = balances.updateUnconfirmed(unconfirmedBalance);
balances = balances?.updateUnconfirmed(unconfirmedBalance);
}
@action
@ -423,7 +428,7 @@ abstract class _ActiveAccount with Store {
final dbr = DbReader(active.coin, active.id);
pnls = await dbr.getPNL(active.id);
spendings = await dbr.getSpending(active.id);
accountBalances = await dbr.getAccountBalanceTimeSeries(active.id, active.balances.balance);
accountBalances = await dbr.getAccountBalanceTimeSeries(active.id, active.balances?.balance ?? 0);
}
@action

View File

@ -46,29 +46,33 @@ class MessageLookup extends MessageLookupByLibrary {
static String m10(ticker) => "Receive ${ticker}";
static String m11(height) => "Rescan Requested from ${height}...";
static String m11(amount, ticker) => "Received ${amount} ${ticker}";
static String m12(ticker) => "Send ${ticker}";
static String m12(height) => "Rescan Requested from ${height}...";
static String m13(ticker) => "Send ${ticker} to...";
static String m13(ticker) => "Send ${ticker}";
static String m14(app) => "Sent from ${app}";
static String m14(ticker) => "Send ${ticker} to...";
static String m15(amount, ticker, count) =>
static String m15(app) => "Sent from ${app}";
static String m16(amount, ticker, count) =>
"Sending a total of ${amount} ${ticker} to ${count} recipients";
static String m16(aZEC, ticker, address) =>
static String m17(aZEC, ticker, address) =>
"Sending ${aZEC} ${ticker} to ${address}";
static String m17(index, name) => "Sub Account ${index} of ${name}";
static String m18(amount, ticker) => "Spent ${amount} ${ticker}";
static String m18(name) => "Sub Account of ${name}";
static String m19(index, name) => "Sub Account ${index} of ${name}";
static String m19(text) => "${text} copied to clipboard";
static String m20(name) => "Sub Account of ${name}";
static String m20(txid) => "TX ID: ${txid}";
static String m21(text) => "${text} copied to clipboard";
static String m21(currency) => "Use ${currency}";
static String m22(txid) => "TX ID: ${txid}";
static String m23(currency) => "Use ${currency}";
final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
@ -228,6 +232,7 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Include Fee in Amount"),
"includeReplyTo":
MessageLookupByLibrary.simpleMessage("Include My Address in Memo"),
"incomingFunds": MessageLookupByLibrary.simpleMessage("Incoming funds"),
"inputBarcodeValue":
MessageLookupByLibrary.simpleMessage("Input barcode"),
"invalidAddress":
@ -294,6 +299,7 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Open in Explorer"),
"paymentInProgress":
MessageLookupByLibrary.simpleMessage("Payment in progress..."),
"paymentMade": MessageLookupByLibrary.simpleMessage("Payment made"),
"pink": MessageLookupByLibrary.simpleMessage("Pink"),
"pl": MessageLookupByLibrary.simpleMessage("P/L"),
"pleaseAuthenticateToSend":
@ -325,12 +331,13 @@ class MessageLookup extends MessageLookupByLibrary {
"receive": m10,
"receivePayment":
MessageLookupByLibrary.simpleMessage("Receive Payment"),
"received": m11,
"recipient": MessageLookupByLibrary.simpleMessage("Recipient"),
"reply": MessageLookupByLibrary.simpleMessage("Reply"),
"rescan": MessageLookupByLibrary.simpleMessage("Rescan"),
"rescanFrom": MessageLookupByLibrary.simpleMessage("Rescan from..."),
"rescanNeeded": MessageLookupByLibrary.simpleMessage("Rescan Needed"),
"rescanRequested": m11,
"rescanRequested": m12,
"rescanning": MessageLookupByLibrary.simpleMessage("Rescanning..."),
"reset": MessageLookupByLibrary.simpleMessage("RESET"),
"restart": MessageLookupByLibrary.simpleMessage("Restart"),
@ -355,12 +362,12 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage(
"Select notes to EXCLUDE from payments"),
"send": MessageLookupByLibrary.simpleMessage("Send"),
"sendCointicker": m12,
"sendCointickerTo": m13,
"sendFrom": m14,
"sendCointicker": m13,
"sendCointickerTo": m14,
"sendFrom": m15,
"sender": MessageLookupByLibrary.simpleMessage("Sender"),
"sendingATotalOfAmountCointickerToCountRecipients": m15,
"sendingAzecCointickerToAddress": m16,
"sendingATotalOfAmountCointickerToCountRecipients": m16,
"sendingAzecCointickerToAddress": m17,
"server": MessageLookupByLibrary.simpleMessage("Server"),
"settings": MessageLookupByLibrary.simpleMessage("Settings"),
"shieldTranspBalance":
@ -384,9 +391,10 @@ class MessageLookup extends MessageLookupByLibrary {
"spendable": MessageLookupByLibrary.simpleMessage("Spendable"),
"spendableBalance":
MessageLookupByLibrary.simpleMessage("Spendable Balance"),
"spent": m18,
"splitAccount": MessageLookupByLibrary.simpleMessage("Split Account"),
"subAccountIndexOf": m17,
"subAccountOf": m18,
"subAccountIndexOf": m19,
"subAccountOf": m20,
"subject": MessageLookupByLibrary.simpleMessage("Subject"),
"syncPaused": MessageLookupByLibrary.simpleMessage("Sync Paused"),
"synching": MessageLookupByLibrary.simpleMessage("Synching"),
@ -404,7 +412,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Tap QR Code for Transparent Address"),
"tapTransactionForDetails":
MessageLookupByLibrary.simpleMessage("Tap Transaction for Details"),
"textCopiedToClipboard": m19,
"textCopiedToClipboard": m21,
"thePrivateWalletMessenger": MessageLookupByLibrary.simpleMessage(
"The private wallet & messenger"),
"theme": MessageLookupByLibrary.simpleMessage("Theme"),
@ -428,7 +436,7 @@ class MessageLookup extends MessageLookupByLibrary {
"transactionHistory":
MessageLookupByLibrary.simpleMessage("Transaction History"),
"transactions": MessageLookupByLibrary.simpleMessage("Transactions"),
"txId": m20,
"txId": m22,
"underConfirmed":
MessageLookupByLibrary.simpleMessage("Under Confirmed"),
"unshielded": MessageLookupByLibrary.simpleMessage("Unshielded"),
@ -441,7 +449,7 @@ class MessageLookup extends MessageLookupByLibrary {
"useGpu": MessageLookupByLibrary.simpleMessage("Use GPU"),
"useQrForOfflineSigning":
MessageLookupByLibrary.simpleMessage("Use QR for offline signing"),
"useSettingscurrency": m21,
"useSettingscurrency": m23,
"useTransparentBalance":
MessageLookupByLibrary.simpleMessage("Use Transparent Balance"),
"useUa": MessageLookupByLibrary.simpleMessage("Use UA"),

View File

@ -45,29 +45,33 @@ class MessageLookup extends MessageLookupByLibrary {
static String m10(ticker) => "Recibir ${ticker}";
static String m11(height) => "Escaneo solicitado desde ${height}";
static String m11(amount, ticker) => "Recibido ${amount} ${ticker}";
static String m12(ticker) => "Enviar ${ticker}";
static String m12(height) => "Escaneo solicitado desde ${height}";
static String m13(ticker) => "Enviar ${ticker} a…";
static String m13(ticker) => "Enviar ${ticker}";
static String m14(app) => "Enviado desde ${app}";
static String m14(ticker) => "Enviar ${ticker} a…";
static String m15(amount, ticker, count) =>
static String m15(app) => "Enviado desde ${app}";
static String m16(amount, ticker, count) =>
"Enviando un total de ${amount} ${ticker} a ${count} direcciones";
static String m16(aZEC, ticker, address) =>
static String m17(aZEC, ticker, address) =>
"Enviado ${aZEC} ${ticker} a ${address}";
static String m17(index, name) => "Subcuenta ${index} de ${name}";
static String m18(amount, ticker) => "Enviado ${amount} ${ticker}";
static String m18(name) => "Subcuenta de ${name}";
static String m19(index, name) => "Subcuenta ${index} de ${name}";
static String m19(text) => "${text} copiado al portapapeles";
static String m20(name) => "Subcuenta de ${name}";
static String m20(txid) => "TX ID: ${txid}";
static String m21(text) => "${text} copiado al portapapeles";
static String m21(currency) => "Utilizar ${currency}";
static String m22(txid) => "TX ID: ${txid}";
static String m23(currency) => "Utilizar ${currency}";
final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
@ -232,6 +236,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Incluir comisión en la cantidad"),
"includeReplyTo": MessageLookupByLibrary.simpleMessage(
"Incluir mi dirección en el memo"),
"incomingFunds": MessageLookupByLibrary.simpleMessage("Pago recibido"),
"inputBarcodeValue":
MessageLookupByLibrary.simpleMessage("Escriba el Código de barras"),
"invalidAddress":
@ -297,6 +302,7 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Abrir en el Explorador"),
"paymentInProgress":
MessageLookupByLibrary.simpleMessage("Pago en curso..."),
"paymentMade": MessageLookupByLibrary.simpleMessage("Payment enviado"),
"pink": MessageLookupByLibrary.simpleMessage("Rosado"),
"pl": MessageLookupByLibrary.simpleMessage("G/P"),
"pleaseAuthenticateToSend": MessageLookupByLibrary.simpleMessage(
@ -328,6 +334,7 @@ class MessageLookup extends MessageLookupByLibrary {
"receive": m10,
"receivePayment":
MessageLookupByLibrary.simpleMessage("Recibir un pago"),
"received": m11,
"recipient": MessageLookupByLibrary.simpleMessage("Destinatario"),
"reply": MessageLookupByLibrary.simpleMessage("Responder"),
"rescan": MessageLookupByLibrary.simpleMessage("Escanear"),
@ -335,7 +342,7 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("¿Escanear desde...?"),
"rescanNeeded":
MessageLookupByLibrary.simpleMessage("Necesita escanear"),
"rescanRequested": m11,
"rescanRequested": m12,
"rescanning": MessageLookupByLibrary.simpleMessage("Escanear..."),
"reset": MessageLookupByLibrary.simpleMessage("RESTABLECER"),
"restart": MessageLookupByLibrary.simpleMessage("Reiniciar"),
@ -362,12 +369,12 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage(
"Seleccionar Notas a EXCLUIR de los pagos"),
"send": MessageLookupByLibrary.simpleMessage("Enviar"),
"sendCointicker": m12,
"sendCointickerTo": m13,
"sendFrom": m14,
"sendCointicker": m13,
"sendCointickerTo": m14,
"sendFrom": m15,
"sender": MessageLookupByLibrary.simpleMessage("Remitente"),
"sendingATotalOfAmountCointickerToCountRecipients": m15,
"sendingAzecCointickerToAddress": m16,
"sendingATotalOfAmountCointickerToCountRecipients": m16,
"sendingAzecCointickerToAddress": m17,
"server": MessageLookupByLibrary.simpleMessage("Servidor"),
"settings": MessageLookupByLibrary.simpleMessage("Ajustes"),
"shieldTranspBalance":
@ -388,9 +395,10 @@ class MessageLookup extends MessageLookupByLibrary {
"spendable": MessageLookupByLibrary.simpleMessage("Disponible"),
"spendableBalance":
MessageLookupByLibrary.simpleMessage("Saldo disponible"),
"spent": m18,
"splitAccount": MessageLookupByLibrary.simpleMessage("Cuenta dividida"),
"subAccountIndexOf": m17,
"subAccountOf": m18,
"subAccountIndexOf": m19,
"subAccountOf": m20,
"subject": MessageLookupByLibrary.simpleMessage("Asunto"),
"syncPaused": MessageLookupByLibrary.simpleMessage("Escaneo en pausa"),
"synching": MessageLookupByLibrary.simpleMessage("Sincronizando"),
@ -408,7 +416,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Toca el QR para Dirección transparente"),
"tapTransactionForDetails": MessageLookupByLibrary.simpleMessage(
"Toca una Transacción para ver detalles"),
"textCopiedToClipboard": m19,
"textCopiedToClipboard": m21,
"thePrivateWalletMessenger": MessageLookupByLibrary.simpleMessage(
"Billetera & Mensajería Privada"),
"theme": MessageLookupByLibrary.simpleMessage("Tema"),
@ -432,7 +440,7 @@ class MessageLookup extends MessageLookupByLibrary {
"transactionHistory":
MessageLookupByLibrary.simpleMessage("Historial de transacciones"),
"transactions": MessageLookupByLibrary.simpleMessage("Transacciónes"),
"txId": m20,
"txId": m22,
"underConfirmed":
MessageLookupByLibrary.simpleMessage("Confirmaciones insuficiente"),
"unshielded": MessageLookupByLibrary.simpleMessage("Sin blindaje"),
@ -445,7 +453,7 @@ class MessageLookup extends MessageLookupByLibrary {
"useGpu": MessageLookupByLibrary.simpleMessage("Utilizar GPU"),
"useQrForOfflineSigning": MessageLookupByLibrary.simpleMessage(
"Usar QR para firmar sin conexión"),
"useSettingscurrency": m21,
"useSettingscurrency": m23,
"useTransparentBalance":
MessageLookupByLibrary.simpleMessage("Usar saldo transp."),
"useUa": MessageLookupByLibrary.simpleMessage("Usar DU"),

View File

@ -45,29 +45,33 @@ class MessageLookup extends MessageLookupByLibrary {
static String m10(ticker) => "Recevoir ${ticker}";
static String m11(height) => "Parcours demandé à partir de ${height}...";
static String m11(amount, ticker) => "Reçu ${amount} {}";
static String m12(ticker) => "Envoyer ${ticker}";
static String m12(height) => "Parcours demandé à partir de ${height}...";
static String m13(ticker) => "Envoyer ${ticker} à...";
static String m13(ticker) => "Envoyer ${ticker}";
static String m14(app) => "Envoyé via ${app}";
static String m14(ticker) => "Envoyer ${ticker} à...";
static String m15(amount, ticker, count) =>
static String m15(app) => "Envoyé via ${app}";
static String m16(amount, ticker, count) =>
"Envoi d\'un total de ${amount} ${ticker} à ${count} destinataires";
static String m16(aZEC, ticker, address) =>
static String m17(aZEC, ticker, address) =>
"Envoi de ${aZEC} ${ticker} à ${address}";
static String m17(index, name) => "Sous Compte ${index} de ${name}";
static String m18(amount, ticker) => "Envoyé ${amount} {}";
static String m18(name) => "Sous Compte de ${name}";
static String m19(index, name) => "Sous Compte ${index} de ${name}";
static String m19(text) => "${text} copié au presse-papier";
static String m20(name) => "Sous Compte de ${name}";
static String m20(txid) => "ID de tx: ${txid}";
static String m21(text) => "${text} copié au presse-papier";
static String m21(currency) => "Utiliser ${currency}";
static String m22(txid) => "ID de tx: ${txid}";
static String m23(currency) => "Utiliser ${currency}";
final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
@ -233,6 +237,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Inclure les frais dans le montant"),
"includeReplyTo": MessageLookupByLibrary.simpleMessage(
"Inclure mon Adresse de Réponse"),
"incomingFunds": MessageLookupByLibrary.simpleMessage("Payment Reçu"),
"inputBarcodeValue":
MessageLookupByLibrary.simpleMessage("Entrer le Code Barre"),
"invalidAddress":
@ -298,6 +303,7 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Ouvrir dans l\'explorateur"),
"paymentInProgress":
MessageLookupByLibrary.simpleMessage("Payment en cours..."),
"paymentMade": MessageLookupByLibrary.simpleMessage("Payment Envoyé"),
"pink": MessageLookupByLibrary.simpleMessage("Rose"),
"pl": MessageLookupByLibrary.simpleMessage("Profit/Perte"),
"pleaseAuthenticateToSend": MessageLookupByLibrary.simpleMessage(
@ -330,13 +336,14 @@ class MessageLookup extends MessageLookupByLibrary {
"receive": m10,
"receivePayment":
MessageLookupByLibrary.simpleMessage("Recevoir un payment"),
"received": m11,
"recipient": MessageLookupByLibrary.simpleMessage("Destinataire"),
"reply": MessageLookupByLibrary.simpleMessage("Répondre"),
"rescan": MessageLookupByLibrary.simpleMessage("Parcourir à nouveau"),
"rescanFrom":
MessageLookupByLibrary.simpleMessage("Reparcourir à partir de...?"),
"rescanNeeded": MessageLookupByLibrary.simpleMessage("Scan nécessaire"),
"rescanRequested": m11,
"rescanRequested": m12,
"rescanning":
MessageLookupByLibrary.simpleMessage("Rescannage en cours..."),
"reset": MessageLookupByLibrary.simpleMessage("RESET"),
@ -364,12 +371,12 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage(
"Sélectionnez les billets à EXCLURE des paiements"),
"send": MessageLookupByLibrary.simpleMessage("Envoyer"),
"sendCointicker": m12,
"sendCointickerTo": m13,
"sendFrom": m14,
"sendCointicker": m13,
"sendCointickerTo": m14,
"sendFrom": m15,
"sender": MessageLookupByLibrary.simpleMessage("Envoyeur"),
"sendingATotalOfAmountCointickerToCountRecipients": m15,
"sendingAzecCointickerToAddress": m16,
"sendingATotalOfAmountCointickerToCountRecipients": m16,
"sendingAzecCointickerToAddress": m17,
"server": MessageLookupByLibrary.simpleMessage("Serveur"),
"settings": MessageLookupByLibrary.simpleMessage("Paramètres"),
"shieldTranspBalance": MessageLookupByLibrary.simpleMessage(
@ -390,9 +397,10 @@ class MessageLookup extends MessageLookupByLibrary {
"spendable": MessageLookupByLibrary.simpleMessage("Dépensable"),
"spendableBalance":
MessageLookupByLibrary.simpleMessage("Montant dépensable"),
"spent": m18,
"splitAccount": MessageLookupByLibrary.simpleMessage("Split Account"),
"subAccountIndexOf": m17,
"subAccountOf": m18,
"subAccountIndexOf": m19,
"subAccountOf": m20,
"subject": MessageLookupByLibrary.simpleMessage("Sujet"),
"syncPaused": MessageLookupByLibrary.simpleMessage("Sync en Pause"),
"synching":
@ -411,7 +419,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Appuyez sur le code QR pour l\'adresse transparente"),
"tapTransactionForDetails": MessageLookupByLibrary.simpleMessage(
"Presser sur une Transaction pour plus de details"),
"textCopiedToClipboard": m19,
"textCopiedToClipboard": m21,
"thePrivateWalletMessenger": MessageLookupByLibrary.simpleMessage(
"Le Portefeuille et Messagerie Privé"),
"theme": MessageLookupByLibrary.simpleMessage("Thème"),
@ -435,7 +443,7 @@ class MessageLookup extends MessageLookupByLibrary {
"transactionHistory":
MessageLookupByLibrary.simpleMessage("Historique des Transactions"),
"transactions": MessageLookupByLibrary.simpleMessage("Transactions"),
"txId": m20,
"txId": m22,
"underConfirmed":
MessageLookupByLibrary.simpleMessage("Pas assez de confs"),
"unshielded": MessageLookupByLibrary.simpleMessage("Transparent"),
@ -448,7 +456,7 @@ class MessageLookup extends MessageLookupByLibrary {
"useGpu": MessageLookupByLibrary.simpleMessage("Utiliser le GPU"),
"useQrForOfflineSigning": MessageLookupByLibrary.simpleMessage(
"Utiliser des QR pour signer sans connexion"),
"useSettingscurrency": m21,
"useSettingscurrency": m23,
"useTransparentBalance": MessageLookupByLibrary.simpleMessage(
"Utiliser le Solde Transparent"),
"useUa": MessageLookupByLibrary.simpleMessage("Utiliser UA"),

View File

@ -2691,6 +2691,46 @@ class S {
args: [],
);
}
/// `Incoming funds`
String get incomingFunds {
return Intl.message(
'Incoming funds',
name: 'incomingFunds',
desc: '',
args: [],
);
}
/// `Payment made`
String get paymentMade {
return Intl.message(
'Payment made',
name: 'paymentMade',
desc: '',
args: [],
);
}
/// `Received {amount} {ticker}`
String received(Object amount, Object ticker) {
return Intl.message(
'Received $amount $ticker',
name: 'received',
desc: '',
args: [amount, ticker],
);
}
/// `Spent {amount} {ticker}`
String spent(Object amount, Object ticker) {
return Intl.message(
'Spent $amount $ticker',
name: 'spent',
desc: '',
args: [amount, ticker],
);
}
}
class AppLocalizationDelegate extends LocalizationsDelegate<S> {

View File

@ -30,6 +30,8 @@ class HomePage extends StatefulWidget {
class HomeState extends State<HomePage> {
StreamSubscription? _syncDispose;
Timer? _syncTimer;
Timer? _priceTimer;
@override
void initState() {
@ -43,14 +45,17 @@ class HomeState extends State<HomePage> {
await syncStatus.sync(false);
await contacts.fetchContacts();
Timer.periodic(Duration(seconds: 15), (Timer t) async {
_syncTimer?.cancel();
_syncTimer = Timer.periodic(Duration(seconds: 15), (Timer t) async {
syncStatus.sync(false);
if (active.id != 0) {
await active.updateBalances();
await active.updateUnconfirmedBalance();
}
});
Timer.periodic(Duration(minutes: 5), (Timer t) async {
_priceTimer?.cancel();
_priceTimer = Timer.periodic(Duration(minutes: 5), (Timer t) async {
await priceStore.updateChart();
});
});
@ -81,6 +86,8 @@ class HomeState extends State<HomePage> {
@override
void dispose() {
_syncDispose?.cancel();
_syncTimer?.cancel();
_priceTimer?.cancel();
super.dispose();
}
@ -106,7 +113,7 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
@override
void initState() {
super.initState();
if (isMobile())
if (Platform.isAndroid)
_initForegroundTask();
final tabController = TabController(length: settings.simpleMode ? 4 : 7, vsync: this);
tabController.addListener(() {
@ -392,15 +399,15 @@ class HomeInnerState extends State<HomeInnerPage> with SingleTickerProviderState
void _initForegroundTask() {
FlutterForegroundTask.init(
androidNotificationOptions: AndroidNotificationOptions(
channelId: 'notification_channel_id',
channelName: 'Foreground Notification',
channelId: '${APP_NAME} Sync',
channelName: '${APP_NAME} Foreground Notification',
channelDescription: 'YWallet Synchronization',
channelImportance: NotificationChannelImportance.LOW,
priority: NotificationPriority.LOW,
priority: NotificationPriority.HIGH,
iconData: const NotificationIconData(
resType: ResourceType.mipmap,
resType: ResourceType.drawable,
resPrefix: ResourcePrefix.ic,
name: 'launcher',
name: 'notification',
),
),
iosNotificationOptions: const IOSNotificationOptions(

View File

@ -262,5 +262,9 @@
"blockReorgDetectedRewind": "Block reorg detected. Rewind to {rewindHeight}",
"goToTransaction": "Show Transaction",
"transactions": "Transactions",
"synchronizationInProgress": "Synchronization in Progress"
"synchronizationInProgress": "Synchronization in Progress",
"incomingFunds": "Incoming funds",
"paymentMade": "Payment made",
"received": "Received {amount} {ticker}",
"spent": "Spent {amount} {ticker}"
}

View File

@ -260,5 +260,9 @@
"blockReorgDetectedRewind": "Block reorg detected. Rewind to {rewindHeight}",
"goToTransaction": "Ver Transacción",
"transactions": "Transacciónes",
"synchronizationInProgress": "Sincronización en progreso"
"synchronizationInProgress": "Sincronización en progreso",
"incomingFunds": "Pago recibido",
"paymentMade": "Payment enviado",
"received": "Recibido {amount} {ticker}",
"spent": "Enviado {amount} {ticker}"
}

View File

@ -260,5 +260,9 @@
"blockReorgDetectedRewind": "Réorganisation détectée. Retour à {rewindHeight}",
"goToTransaction": "Voir la Transaction",
"transactions": "Transactions",
"synchronizationInProgress": "Synchronization en Cours"
"synchronizationInProgress": "Synchronization en Cours",
"incomingFunds": "Payment Reçu",
"paymentMade": "Payment Envoyé",
"received": "Reçu {amount} {}",
"spent": "Envoyé {amount} {}"
}

View File

@ -5,7 +5,6 @@ import 'dart:io';
import 'dart:math';
import 'dart:ui';
import 'package:audioplayers/audioplayers.dart';
import 'package:csv/csv.dart';
import 'package:currency_text_input_formatter/currency_text_input_formatter.dart';
import 'package:decimal/decimal.dart';
@ -14,6 +13,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter_ringtone_player/flutter_ringtone_player.dart';
import 'package:intl/intl.dart';
import 'package:local_auth/local_auth.dart';
import 'package:key_guardmanager/key_guardmanager.dart';
@ -24,15 +24,16 @@ import 'package:share_plus/share_plus.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sqflite/sqflite.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:velocity_x/velocity_x.dart';
import 'package:warp_api/warp_api.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:uni_links/uni_links.dart';
import 'package:quick_actions/quick_actions.dart';
import 'package:sqlite3/open.dart';
import 'package:awesome_notifications/awesome_notifications.dart';
import 'accounts.dart';
import 'animated_qr.dart';
import 'coin/coins.dart';
import 'db.dart';
import 'devmode.dart';
import 'generated/l10n.dart';
@ -193,6 +194,19 @@ final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
void main() {
WidgetsFlutterBinding.ensureInitialized();
AwesomeNotifications().initialize(
'resource://drawable/res_notification',
[
NotificationChannel(
channelKey: APP_NAME,
channelName: APP_NAME,
channelDescription: 'Notification channel for ${APP_NAME}',
defaultColor: Color(0xFFB3F0FF),
ledColor: Colors.white,
)
],
debug: true
);
final home = ZWalletApp();
runApp(FutureBuilder(
@ -286,6 +300,26 @@ class ZWalletAppState extends State<ZWalletApp> {
if (mounted && rateMyApp.shouldOpenDialog) {
rateMyApp.showRateDialog(this.context);
}
final isAllowed = await AwesomeNotifications().isNotificationAllowed();
if (!isAllowed) {
AwesomeNotifications().requestPermissionToSendNotifications(
permissions: [
NotificationPermission.Sound,
NotificationPermission.Alert,
NotificationPermission.FullScreenIntent,
NotificationPermission.Badge,
NotificationPermission.Vibration,
NotificationPermission.Light,
],
);
}
// Only after at least the action method is set, the notification events are delivered
AwesomeNotifications().setListeners(
onActionReceivedMethod: NotificationController.onActionReceivedMethod,
onNotificationCreatedMethod: NotificationController.onNotificationCreatedMethod,
onNotificationDisplayedMethod: NotificationController.onNotificationDisplayedMethod,
onDismissActionReceivedMethod: NotificationController.onDismissActionReceivedMethod
);
});
}
else {
@ -562,7 +596,8 @@ bool checkNumber(String s) {
return true;
}
int precision(bool? mZEC) => (mZEC == null || mZEC) ? 3 : 8;
const MAX_PRECISION = 8;
int precision(bool? mZEC) => (mZEC == null || mZEC) ? 3 : MAX_PRECISION;
Future<String?> scanCode(BuildContext context) async {
final s = S.of(context);
@ -611,6 +646,38 @@ void showSnackBar(String msg, { bool autoClose = false, bool quick = false }) {
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar);
}
void showBalanceNotification(Balances prevBalances, Balances curBalances) {
final s = S.current;
if (Platform.isAndroid &&
prevBalances.balance != curBalances.balance) {
final amount = (prevBalances.balance - curBalances.balance).abs();
final amountStr = amountToString(amount, MAX_PRECISION);
final ticker = active.coinDef.ticker;
final NotificationContent content;
if (curBalances.balance > prevBalances.balance) {
content = NotificationContent(
id: 1,
channelKey: APP_NAME,
title: s.incomingFunds,
body: s.received(amountStr, ticker),
actionType: ActionType.Default,
);
}
else {
content = NotificationContent(
id: 1,
channelKey: APP_NAME,
title: s.paymentMade,
body: s.spent(amountStr, ticker),
actionType: ActionType.Default,
);
}
AwesomeNotifications().createNotification(
content: content
);
}
}
enum DeviceWidth {
xs,
sm,
@ -658,8 +725,6 @@ String decimalFormat(double x, int decimalDigits, { String symbol = '' }) =>
NumberFormat.currency(decimalDigits: decimalDigits, symbol: symbol).format(
x).trimRight();
const MAX_PRECISION = 8;
String amountToString(int amount, int decimalDigits) => decimalFormat(amount / ZECUNIT, decimalDigits);
DecodedPaymentURI decodeAddress(BuildContext context, String? v) {
@ -853,3 +918,27 @@ Future<String> getDbPath() async {
}
bool isMobile() => Platform.isAndroid || Platform.isIOS;
class NotificationController {
/// Use this method to detect when a new notification or a schedule is created
@pragma("vm:entry-point")
static Future <void> onNotificationCreatedMethod(ReceivedNotification receivedNotification) async {
}
/// Use this method to detect every time that a new notification is displayed
@pragma("vm:entry-point")
static Future <void> onNotificationDisplayedMethod(ReceivedNotification receivedNotification) async {
FlutterRingtonePlayer.playNotification();
}
/// Use this method to detect if the user dismissed a notification
@pragma("vm:entry-point")
static Future <void> onDismissActionReceivedMethod(ReceivedAction receivedAction) async {
}
/// Use this method to detect when the user taps on a notification or action button
@pragma("vm:entry-point")
static Future <void> onActionReceivedMethod(ReceivedAction receivedAction) async {
}
}

View File

@ -89,12 +89,14 @@ class SendState extends State<SendPage> {
_newBlockAutorunDispose = autorun((_) async {
final _ = active.dataEpoch;
final sBalance = active.balances.shieldedBalance;
final balances = active.balances;
if (balances == null) return;
final sBalance = balances.shieldedBalance;
final tBalance = active.tbalance;
final excludedBalance = active.balances.excludedBalance;
final underConfirmedBalance = active.balances.underConfirmedBalance;
final unconfirmedSpentBalance = active.balances.unconfirmedBalance;
final unconfirmedBalance = active.balances.unconfirmedBalance;
final excludedBalance = balances.excludedBalance;
final underConfirmedBalance = balances.underConfirmedBalance;
final unconfirmedSpentBalance = balances.unconfirmedBalance;
final unconfirmedBalance = balances.unconfirmedBalance;
setState(() {
_sBalance = sBalance;
_tBalance = tBalance;

View File

@ -1,3 +1,4 @@
import 'dart:io';
import 'dart:isolate';
import 'dart:math';
import 'package:flutter/foundation.dart';
@ -743,7 +744,7 @@ abstract class _SyncStatus with Store {
isRescan = _isRescan;
final currentSyncedHeight = syncedHeight;
if (!isSynced()) {
if (isMobile()) {
if (Platform.isAndroid) {
await FlutterForegroundTask.startService(
notificationTitle: S.current.synchronizationInProgress,
notificationText: '',
@ -773,7 +774,7 @@ abstract class _SyncStatus with Store {
finally {
syncing = false;
eta.reset();
if (isMobile())
if (Platform.isAndroid)
await FlutterForegroundTask.stopService();
}
}

@ -1 +1 @@
Subproject commit bba488a5019837b5cd84356a09b51e849b636a56
Subproject commit 152fe56a1e0d47bf86d2ec4b9c953dd294e0787a

View File

@ -99,6 +99,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
awesome_notifications:
dependency: "direct main"
description:
name: awesome_notifications
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.2"
badges:
dependency: "direct main"
description:
@ -510,6 +517,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
flutter_ringtone_player:
dependency: "direct main"
description:
name: flutter_ringtone_player
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.0"
flutter_speed_dial:
dependency: "direct main"
description:

View File

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.2.15+289
version: 1.2.15+292
environment:
sdk: ">=2.12.0 <3.0.0"
@ -79,6 +79,8 @@ dependencies:
flutter_localizations:
sdk: flutter
flutter_foreground_task: ^3.10.0
awesome_notifications: ^0.7.2
flutter_ringtone_player: ^3.2.0
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.