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

View File

@ -10,7 +10,9 @@
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" 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 <!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues 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 #!/bin/sh
set -x set -x
FLUTTER_VERSION=3.3.4
ROOT_DIR=$1 ROOT_DIR=$1
if [ "$ROOT_DIR" == "" ]; then if [ "$ROOT_DIR" == "" ]; then
ROOT_DIR="/root" ROOT_DIR="/root"
@ -11,11 +13,12 @@ if [ "$DL_DIR" == "" ]; then
DL_DIR="/tmp" DL_DIR="/tmp"
fi fi
sudo pacman -Sy --noconfirm unzip jdk8-openjdk wget 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/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://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-output.params
wget -qP $DL_DIR -N https://download.z.cash/downloads/sapling-spend.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") 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 $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 mkdir -p $HOME/.zcash-params
cp $DL_DIR/sapling-output.params $DL_DIR/sapling-spend.params $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 ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/android-ndk-r21e
export PATH=$PATH:$ROOT_DIR/flutter/bin 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 startHeight = syncStatus.startSyncedHeight;
final timestamp = syncStatus.timestamp?.timeAgo() ?? s.na; final timestamp = syncStatus.timestamp?.timeAgo() ?? s.na;
final latestHeight = syncStatus.latestHeight; final latestHeight = syncStatus.latestHeight;
final remaining = syncedHeight != null ? max(latestHeight-syncedHeight, 0) : 0; final remaining = max(latestHeight-syncedHeight, 0);
final int? percent; final int? percent;
if (startHeight != null) { if (startHeight != null) {
final total = latestHeight - startHeight; final total = latestHeight - startHeight;
@ -301,7 +301,7 @@ class BalanceWidget extends StatelessWidget {
final flat = settings.flat; final flat = settings.flat;
final hide = settings.autoHide && flat; final hide = settings.autoHide && flat;
final showTAddr = active.showTAddr; final showTAddr = active.showTAddr;
final balance = showTAddr ? active.tbalance : active.balances.balance; final balance = showTAddr ? active.tbalance : active.balances?.balance ?? 0;
final balanceColor = !showTAddr final balanceColor = !showTAddr
? theme.colorScheme.primary ? theme.colorScheme.primary
: theme.colorScheme.secondary; : theme.colorScheme.secondary;
@ -345,7 +345,7 @@ class MemPoolWidget extends StatelessWidget {
Widget build(BuildContext context) => Observer(builder: (context) { Widget build(BuildContext context) => Observer(builder: (context) {
final b = active.balances; final b = active.balances;
final theme = Theme.of(context); final theme = Theme.of(context);
final unconfirmedBalance = b.unconfirmedBalance; final unconfirmedBalance = b?.unconfirmedBalance ?? 0;
if (unconfirmedBalance == 0) return Container(); if (unconfirmedBalance == 0) return Container();
final unconfirmedStyle = TextStyle( final unconfirmedStyle = TextStyle(
color: amountColor(context, unconfirmedBalance)); color: amountColor(context, unconfirmedBalance));

View File

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

View File

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

View File

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

View File

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

View File

@ -2691,6 +2691,46 @@ class S {
args: [], 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> { class AppLocalizationDelegate extends LocalizationsDelegate<S> {

View File

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

View File

@ -262,5 +262,9 @@
"blockReorgDetectedRewind": "Block reorg detected. Rewind to {rewindHeight}", "blockReorgDetectedRewind": "Block reorg detected. Rewind to {rewindHeight}",
"goToTransaction": "Show Transaction", "goToTransaction": "Show Transaction",
"transactions": "Transactions", "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}", "blockReorgDetectedRewind": "Block reorg detected. Rewind to {rewindHeight}",
"goToTransaction": "Ver Transacción", "goToTransaction": "Ver Transacción",
"transactions": "Transacciónes", "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}", "blockReorgDetectedRewind": "Réorganisation détectée. Retour à {rewindHeight}",
"goToTransaction": "Voir la Transaction", "goToTransaction": "Voir la Transaction",
"transactions": "Transactions", "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:math';
import 'dart:ui'; import 'dart:ui';
import 'package:audioplayers/audioplayers.dart';
import 'package:csv/csv.dart'; import 'package:csv/csv.dart';
import 'package:currency_text_input_formatter/currency_text_input_formatter.dart'; import 'package:currency_text_input_formatter/currency_text_input_formatter.dart';
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
@ -14,6 +13,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart'; import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter_ringtone_player/flutter_ringtone_player.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:local_auth/local_auth.dart'; import 'package:local_auth/local_auth.dart';
import 'package:key_guardmanager/key_guardmanager.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:shared_preferences/shared_preferences.dart';
import 'package:sqflite/sqflite.dart'; import 'package:sqflite/sqflite.dart';
import 'package:sqflite_common_ffi/sqflite_ffi.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:warp_api/warp_api.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:uni_links/uni_links.dart'; import 'package:uni_links/uni_links.dart';
import 'package:quick_actions/quick_actions.dart'; import 'package:quick_actions/quick_actions.dart';
import 'package:sqlite3/open.dart'; import 'package:sqlite3/open.dart';
import 'package:awesome_notifications/awesome_notifications.dart';
import 'accounts.dart'; import 'accounts.dart';
import 'animated_qr.dart'; import 'animated_qr.dart';
import 'coin/coins.dart'; import 'coin/coins.dart';
import 'db.dart';
import 'devmode.dart'; import 'devmode.dart';
import 'generated/l10n.dart'; import 'generated/l10n.dart';
@ -193,6 +194,19 @@ final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
void main() { void main() {
WidgetsFlutterBinding.ensureInitialized(); 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(); final home = ZWalletApp();
runApp(FutureBuilder( runApp(FutureBuilder(
@ -286,6 +300,26 @@ class ZWalletAppState extends State<ZWalletApp> {
if (mounted && rateMyApp.shouldOpenDialog) { if (mounted && rateMyApp.shouldOpenDialog) {
rateMyApp.showRateDialog(this.context); 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 { else {
@ -562,7 +596,8 @@ bool checkNumber(String s) {
return true; 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 { Future<String?> scanCode(BuildContext context) async {
final s = S.of(context); final s = S.of(context);
@ -611,6 +646,38 @@ void showSnackBar(String msg, { bool autoClose = false, bool quick = false }) {
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar); 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 { enum DeviceWidth {
xs, xs,
sm, sm,
@ -658,8 +725,6 @@ String decimalFormat(double x, int decimalDigits, { String symbol = '' }) =>
NumberFormat.currency(decimalDigits: decimalDigits, symbol: symbol).format( NumberFormat.currency(decimalDigits: decimalDigits, symbol: symbol).format(
x).trimRight(); x).trimRight();
const MAX_PRECISION = 8;
String amountToString(int amount, int decimalDigits) => decimalFormat(amount / ZECUNIT, decimalDigits); String amountToString(int amount, int decimalDigits) => decimalFormat(amount / ZECUNIT, decimalDigits);
DecodedPaymentURI decodeAddress(BuildContext context, String? v) { DecodedPaymentURI decodeAddress(BuildContext context, String? v) {
@ -853,3 +918,27 @@ Future<String> getDbPath() async {
} }
bool isMobile() => Platform.isAndroid || Platform.isIOS; 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 { _newBlockAutorunDispose = autorun((_) async {
final _ = active.dataEpoch; 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 tBalance = active.tbalance;
final excludedBalance = active.balances.excludedBalance; final excludedBalance = balances.excludedBalance;
final underConfirmedBalance = active.balances.underConfirmedBalance; final underConfirmedBalance = balances.underConfirmedBalance;
final unconfirmedSpentBalance = active.balances.unconfirmedBalance; final unconfirmedSpentBalance = balances.unconfirmedBalance;
final unconfirmedBalance = active.balances.unconfirmedBalance; final unconfirmedBalance = balances.unconfirmedBalance;
setState(() { setState(() {
_sBalance = sBalance; _sBalance = sBalance;
_tBalance = tBalance; _tBalance = tBalance;

View File

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

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

View File

@ -99,6 +99,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.0" 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: badges:
dependency: "direct main" dependency: "direct main"
description: description:
@ -510,6 +517,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.0.0" 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: flutter_speed_dial:
dependency: "direct main" dependency: "direct main"
description: 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. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.2.15+289 version: 1.2.15+292
environment: environment:
sdk: ">=2.12.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
@ -79,6 +79,8 @@ dependencies:
flutter_localizations: flutter_localizations:
sdk: flutter sdk: flutter
flutter_foreground_task: ^3.10.0 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. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.