diff --git a/__tests__/LoadedApp.snapshot.tsx b/__tests__/LoadedApp.snapshot.tsx
index b9a2c929a..e2a8d93e2 100644
--- a/__tests__/LoadedApp.snapshot.tsx
+++ b/__tests__/LoadedApp.snapshot.tsx
@@ -13,7 +13,7 @@ import { ThemeType } from '../app/types';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { I18n } from 'i18n-js';
import { StackScreenProps } from '@react-navigation/stack';
-import { ServerType } from '../app/AppState';
+import { BackgroundType, ServerType } from '../app/AppState';
// Crea un mock para el constructor de I18n
jest.mock('i18n-js', () => ({
@@ -121,10 +121,11 @@ describe('Component LoadedApp - test', () => {
const sendAll = false;
const privacy = false;
const mode = 'basic';
- const background = {
+ const background: BackgroundType = {
batches: 0,
message: '',
date: 0,
+ dateEnd: 0,
};
const readOnly = false;
const receive = render(
diff --git a/__tests__/LoadingApp.snapshot.tsx b/__tests__/LoadingApp.snapshot.tsx
index 55c628222..36a9ba9e0 100644
--- a/__tests__/LoadingApp.snapshot.tsx
+++ b/__tests__/LoadingApp.snapshot.tsx
@@ -13,7 +13,7 @@ import { ThemeType } from '../app/types';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { I18n } from 'i18n-js';
import { StackScreenProps } from '@react-navigation/stack';
-import { ServerType } from '../app/AppState';
+import { BackgroundType, ServerType } from '../app/AppState';
// Crea un mock para el constructor de I18n
jest.mock('i18n-js', () => ({
@@ -121,10 +121,11 @@ describe('Component LoadingApp - test', () => {
const sendAll = false;
const privacy = false;
const mode = 'basic';
- const background = {
+ const background: BackgroundType = {
batches: 0,
message: '',
date: 0,
+ dateEnd: 0,
};
const firstLaunchingMessage = false;
const receive = render(
diff --git a/android/app/build.gradle b/android/app/build.gradle
index c53d08a18..986cf0229 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -144,9 +144,9 @@ android {
//applicationId 'com.ZingoMobile' // @Test
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
- versionCode 131 // Real
+ versionCode 145 // Real
//versionCode 117 // @Test
- versionName "zingo-1.3.3" // Real
+ versionName "zingo-1.3.4" // Real
missingDimensionStrategy 'react-native-camera', 'general'
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
@@ -297,6 +297,7 @@ dependencies {
implementation jscFlavor
}
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
+ implementation "org.jetbrains.kotlinx:kotlinx-datetime:0.5.0"
def work_version = "2.7.1"
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index a0b43f231..de88364e4 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -38,7 +38,6 @@
-
diff --git a/android/app/src/main/java/org/ZingoLabs/Zingo/BackgroundSync.kt b/android/app/src/main/java/org/ZingoLabs/Zingo/BackgroundSync.kt
deleted file mode 100644
index 940058f97..000000000
--- a/android/app/src/main/java/org/ZingoLabs/Zingo/BackgroundSync.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.ZingoLabs.Zingo
-
-import android.content.Intent
-import com.facebook.react.HeadlessJsTaskService
-import com.facebook.react.bridge.Arguments
-import com.facebook.react.jstasks.HeadlessJsTaskConfig
-
- class BackgroundSync : HeadlessJsTaskService() {
- override fun getTaskConfig(intent: Intent): HeadlessJsTaskConfig? {
- return intent.extras?.let {
- HeadlessJsTaskConfig(
- "BackgroundSync",
- Arguments.fromBundle(it),
- 0, // timeout for the task
- true // optional: defines whether or not the task is allowed in foreground.
- // Default is false
- )
- }
- }
-}
-
diff --git a/android/app/src/main/java/org/ZingoLabs/Zingo/BackgroundSyncWorker.kt b/android/app/src/main/java/org/ZingoLabs/Zingo/BackgroundSyncWorker.kt
new file mode 100644
index 000000000..26caf9213
--- /dev/null
+++ b/android/app/src/main/java/org/ZingoLabs/Zingo/BackgroundSyncWorker.kt
@@ -0,0 +1,254 @@
+package org.ZingoLabs.Zingo
+
+import android.content.Context
+import android.os.Build
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.work.Constraints
+import androidx.work.ExistingPeriodicWorkPolicy
+import androidx.work.NetworkType
+import androidx.work.PeriodicWorkRequest
+import androidx.work.WorkManager
+import java.io.File
+import java.util.*
+import org.json.JSONObject
+import java.nio.charset.StandardCharsets
+import com.facebook.react.bridge.ReactApplicationContext
+import kotlinx.datetime.Clock
+import kotlinx.datetime.DateTimeUnit
+import kotlinx.datetime.Instant
+import kotlinx.datetime.TimeZone
+import kotlinx.datetime.atTime
+import kotlinx.datetime.toInstant
+import kotlinx.datetime.toLocalDateTime
+import kotlinx.datetime.until
+import kotlin.random.Random
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.days
+import kotlin.time.Duration.Companion.hours
+import kotlin.time.Duration.Companion.minutes
+import kotlin.time.DurationUnit
+import kotlin.time.toDuration
+import kotlin.time.toJavaDuration
+
+class BackgroundSyncWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ override fun doWork(): Result {
+ val reactContext = ReactApplicationContext(MainApplication.getAppContext())
+ val rpcModule = RPCModule(reactContext)
+
+ Log.i("SCHEDULED_TASK_RUN", "Task running")
+
+ // save the background JSON file
+ val timeStampStart = Date().time / 1000
+ val timeStampStrStart = timeStampStart.toString()
+ val jsonBackgroundStart = "{\"batches\": \"0\", \"message\": \"Starting OK.\", \"date\": \"$timeStampStrStart\", \"dateEnd\": \"0\"}"
+ rpcModule.saveBackgroundFile(jsonBackgroundStart)
+ Log.i("SCHEDULED_TASK_RUN", "background json file SAVED $jsonBackgroundStart")
+
+ // checking if the wallet file exists
+ val exists: Boolean = walletExists()
+
+ if (exists) {
+ RustFFI.initlogging()
+
+ // check the Server, because the task can run without the App.
+ val balance = RustFFI.execute("balance", "")
+ Log.i("SCHEDULED_TASK_RUN", "Testing if server is active: $balance")
+ if (balance.lowercase().startsWith("error")) {
+ // this means this task is running with the App closed
+ loadWalletFile(rpcModule)
+ } else {
+ // this means the App is open,
+ // stop syncing first, just in case.
+ stopSyncingProcess()
+ }
+
+ // interrupt sync to false, just in case it is true.
+ val noInterrupting = RustFFI.execute("interrupt_sync_after_batch", "false")
+ Log.i("SCHEDULED_TASK_RUN", "Not interrupting sync: $noInterrupting")
+
+ // the task is running here blocking this execution until this process finished:
+ // 1. finished the syncing.
+
+ Log.i("SCHEDULED_TASK_RUN", "sync BEGIN")
+ val syncing = RustFFI.execute("sync", "")
+ Log.i("SCHEDULED_TASK_RUN", "sync END: $syncing")
+
+ } else {
+ Log.i("SCHEDULED_TASK_RUN", "No exists wallet file END")
+ // save the background JSON file
+ val timeStampError = Date().time / 1000
+ val timeStampStrError = timeStampError.toString()
+ val jsonBackgroundError = "{\"batches\": \"0\", \"message\": \"No active wallet KO.\", \"date\": \"$timeStampStrStart\", \"dateEnd\": \"$timeStampStrError\"}"
+ rpcModule.saveBackgroundFile(jsonBackgroundError)
+ Log.i("SCHEDULED_TASK_RUN", "background json file SAVED $jsonBackgroundError")
+ return Result.failure()
+
+ }
+
+ // save the wallet file with the new data from the sync process
+ rpcModule.saveWallet()
+ Log.i("SCHEDULED_TASK_RUN", "wallet file SAVED")
+
+ // save the background JSON file
+ val timeStampEnd = Date().time / 1000
+ val timeStampStrEnd = timeStampEnd.toString()
+ val jsonBackgroundEnd = "{\"batches\": \"0\", \"message\": \"Finished OK.\", \"date\": \"$timeStampStrStart\", \"dateEnd\": \"$timeStampStrEnd\"}"
+ rpcModule.saveBackgroundFile(jsonBackgroundEnd)
+ Log.i("SCHEDULED_TASK_RUN", "background json file SAVED $jsonBackgroundEnd")
+
+ return Result.success()
+ }
+
+ private fun loadWalletFile(rpcModule: RPCModule) {
+ // I have to init from wallet file in order to do the sync
+ // and I need to read the settings.json to find the server & chain type
+ MainApplication.getAppContext()?.openFileInput("settings.json")?.use { file ->
+ val settingsBytes = file.readBytes()
+ file.close()
+ val settingsString = settingsBytes.toString(Charsets.UTF_8)
+ val jsonObject = JSONObject(settingsString)
+ val server = jsonObject.getJSONObject("server").getString("uri")
+ val chainhint = jsonObject.getJSONObject("server").getString("chain_name")
+ Log.i(
+ "SCHEDULED_TASK_RUN",
+ "Opening the wallet file - No App active - server: $server chain: $chainhint"
+ )
+ rpcModule.loadExistingWalletNative(server, chainhint)
+ }
+ }
+
+ private fun stopSyncingProcess() {
+ var status = RustFFI.execute("syncstatus", "")
+ Log.i("SCHEDULED_TASK_RUN", "status response $status")
+
+ var data: ByteArray = status.toByteArray(StandardCharsets.UTF_8)
+ var jsonResp = JSONObject(String(data, StandardCharsets.UTF_8))
+ var inProgressStr: String = jsonResp.optString("in_progress")
+ var inProgress: Boolean = inProgressStr.toBoolean()
+
+ Log.i("SCHEDULED_TASK_RUN", "in progress value $inProgress")
+
+ while (inProgress) {
+ // interrupt
+ val interrupting = RustFFI.execute("interrupt_sync_after_batch", "true")
+ Log.i("SCHEDULED_TASK_RUN", "Interrupting sync: $interrupting")
+
+ // blocking the thread for 0.5 seconds.
+ Thread.sleep(500)
+
+ status = RustFFI.execute("syncstatus", "")
+ Log.i("SCHEDULED_TASK_RUN", "status response $status")
+
+ data = status.toByteArray(StandardCharsets.UTF_8)
+ jsonResp = JSONObject(String(data, StandardCharsets.UTF_8))
+ inProgressStr = jsonResp.optString("in_progress")
+ inProgress = inProgressStr.toBoolean()
+
+ Log.i("SCHEDULED_TASK_RUN", "in progress value $inProgress")
+ }
+
+ Log.i("SCHEDULED_TASK_RUN", "sync process STOPPED")
+
+ }
+
+ private fun walletExists(): Boolean {
+ // Check if a wallet already exists
+ val file = File(MainApplication.getAppContext()?.filesDir, "wallet.dat")
+ return if (file.exists()) {
+ Log.i("SCHEDULED_TASK_RUN", "Wallet exists")
+ true
+ } else {
+ Log.i("SCHEDULED_TASK_RUN", "Wallet DOES NOT exist")
+ false
+ }
+ }
+}
+
+class BSCompanion {
+ companion object {
+ private const val taskID = "Zingo_Processing_Task_ID"
+ private val SYNC_PERIOD = 24.hours
+ private val SYNC_DAY_SHIFT = 1.days // Move to tomorrow
+ private val SYNC_START_TIME_HOURS = 3.hours // Start around 3 a.m. at night
+ private val SYNC_START_TIME_MINUTES = 60.minutes // Randomize with minutes until 4 a.m.
+ @RequiresApi(Build.VERSION_CODES.O)
+ fun scheduleBackgroundTask() {
+ val reactContext = ReactApplicationContext(MainApplication.getAppContext())
+
+ // zancas requeriment, not plug-in, reverted.
+ val constraints = Constraints.Builder()
+ .setRequiresStorageNotLow(false) // less restricted
+ .setRequiredNetworkType(NetworkType.UNMETERED)
+ .setRequiresCharging(true)
+ .build()
+
+ // PRODUCTION - next day between 3:00 and 4:00 am.
+ val targetTimeDiff = calculateTargetTimeDifference()
+
+ Log.i("SCHEDULING_TASK", "calculated target time DIFF $targetTimeDiff")
+
+ val workRequest = PeriodicWorkRequest.Builder(BackgroundSyncWorker::class.java, SYNC_PERIOD.toJavaDuration())
+ .setConstraints(constraints)
+ .setInitialDelay(targetTimeDiff.toJavaDuration())
+ .build()
+
+ Log.i("SCHEDULING_TASK", "Enqueuing the background task - Background")
+ WorkManager.getInstance(reactContext)
+ .enqueueUniquePeriodicWork(
+ taskID,
+ ExistingPeriodicWorkPolicy.REPLACE,
+ workRequest
+ )
+
+ Log.i("SCHEDULING_TASK", "Task info ${WorkManager.getInstance(reactContext).getWorkInfosForUniqueWork(
+ taskID).get()}")
+ }
+
+ private fun calculateTargetTimeDifference(): Duration {
+ val currentTimeZone: TimeZone = TimeZone.currentSystemDefault()
+
+ val now: Instant = Clock.System.now()
+
+ val targetTime =
+ now
+ .plus(SYNC_DAY_SHIFT)
+ .toLocalDateTime(currentTimeZone)
+ .date
+ .atTime(
+ hour = SYNC_START_TIME_HOURS.inWholeHours.toInt(),
+ // Even though the WorkManager will trigger the work approximately at the set time, it's
+ // better to randomize time in 3-4 a.m. This generates a number between 0 (inclusive) and 60
+ // (exclusive)
+ minute = Random.nextInt(0, SYNC_START_TIME_MINUTES.inWholeMinutes.toInt())
+ )
+
+ val targetTimeTime = targetTime.time
+ val targetTimeDate = targetTime.date
+ Log.i("SCHEDULING_TASK", "calculated target time $targetTimeTime and date $targetTimeDate")
+
+ return now.until(
+ other = targetTime.toInstant(currentTimeZone),
+ unit = DateTimeUnit.MILLISECOND,
+ timeZone = currentTimeZone
+ ).toDuration(DurationUnit.MILLISECONDS)
+ }
+
+ fun cancelExecutingTask() {
+ val reactContext = ReactApplicationContext(MainApplication.getAppContext())
+
+ // run interrupt sync, just in case.
+ val interrupting = RustFFI.execute("interrupt_sync_after_batch", "true")
+ Log.i("SCHEDULED_TASK_RUN", "Interrupting sync: $interrupting")
+
+ Log.i("SCHEDULING_TASK", "Cancel background Task")
+ WorkManager.getInstance(reactContext)
+ .cancelUniqueWork(taskID)
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/java/org/ZingoLabs/Zingo/MainActivity.kt b/android/app/src/main/java/org/ZingoLabs/Zingo/MainActivity.kt
index 9633ecded..0342e1aeb 100644
--- a/android/app/src/main/java/org/ZingoLabs/Zingo/MainActivity.kt
+++ b/android/app/src/main/java/org/ZingoLabs/Zingo/MainActivity.kt
@@ -1,44 +1,46 @@
package org.ZingoLabs.Zingo
-import android.content.Intent
+import android.os.Build
import android.os.Bundle
import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.work.*
import com.facebook.react.ReactActivity
-import java.util.concurrent.TimeUnit
+
class MainActivity : ReactActivity() {
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
- override fun getMainComponentName(): String? {
+
+ private var isStarting = true;
+ override fun getMainComponentName(): String {
return "Zingo!"
}
override fun onCreate(savedInstanceState: Bundle?) {
- Log.w("", "Starting main activity")
- val service = Intent(applicationContext, BackgroundSync::class.java)
- applicationContext.stopService(service)
+ Log.i("ON_CREATE", "Starting main activity")
super.onCreate(null)
}
+ @RequiresApi(Build.VERSION_CODES.O)
override fun onPause() {
- Log.w("", "Pausing main activity")
- val service = Intent(applicationContext, BackgroundSync::class.java)
- val bundle = Bundle()
-
- bundle.putString("BS: start syncing", "Native")
-
- service.putExtras(bundle)
-
- applicationContext.startService(service)
+ Log.i("ON_PAUSE", "Pausing main activity - Background")
+ BSCompanion.scheduleBackgroundTask()
super.onPause()
- //val backgroundRequest = PeriodicWorkRequest.Builder(BackgroundWorker::class.java, 15, TimeUnit.MINUTES).build()
- //WorkManager.getInstance(application).enqueue(backgroundRequest)
}
+ @RequiresApi(Build.VERSION_CODES.O)
override fun onResume() {
- val service = Intent(applicationContext, BackgroundSync::class.java)
- applicationContext.stopService(service)
+ Log.i("ON_RESUME", "Resuming main activity - Foreground")
+ // cancel the task if it is in execution now
+ if (isStarting) {
+ // this is the time the App is launching.
+ isStarting = false
+ } else {
+ BSCompanion.cancelExecutingTask()
+ }
super.onResume()
}
+
}
\ No newline at end of file
diff --git a/android/app/src/main/java/org/ZingoLabs/Zingo/RPCModule.kt b/android/app/src/main/java/org/ZingoLabs/Zingo/RPCModule.kt
index e47dd66e6..bb130285e 100644
--- a/android/app/src/main/java/org/ZingoLabs/Zingo/RPCModule.kt
+++ b/android/app/src/main/java/org/ZingoLabs/Zingo/RPCModule.kt
@@ -3,7 +3,6 @@ package org.ZingoLabs.Zingo
import android.content.Context
import android.util.Log
import android.util.Base64
-import androidx.work.PeriodicWorkRequest
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
@@ -12,15 +11,10 @@ import com.facebook.react.bridge.Promise
//import android.util.Log
import java.io.File
import java.io.InputStream
-import java.util.concurrent.TimeUnit
import kotlin.concurrent.thread
class RPCModule internal constructor(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
- //companion object {
- // const val TAG = "RPCModule"
- //}
-
override fun getName(): String {
return "RPCModule"
}
@@ -30,10 +24,10 @@ class RPCModule internal constructor(private val reactContext: ReactApplicationC
// Check if a wallet already exists
val file = File(MainApplication.getAppContext()?.filesDir, "wallet.dat")
if (file.exists()) {
- // Log.w("MAIN", "Wallet exists")
+ // Log.i("MAIN", "Wallet exists")
promise.resolve(true)
} else {
- // Log.w("MAIN", "Wallet DOES NOT exist")
+ // Log.i("MAIN", "Wallet DOES NOT exist")
promise.resolve(false)
}
}
@@ -43,25 +37,25 @@ class RPCModule internal constructor(private val reactContext: ReactApplicationC
// Check if a wallet backup already exists
val file = File(MainApplication.getAppContext()?.filesDir, "wallet.backup.dat")
if (file.exists()) {
- // Log.w("MAIN", "Wallet backup exists")
+ // Log.i("MAIN", "Wallet backup exists")
promise.resolve(true)
} else {
- // Log.w("MAIN", "Wallet backup DOES NOT exist")
+ // Log.i("MAIN", "Wallet backup DOES NOT exist")
promise.resolve(false)
}
}
@ReactMethod
fun createNewWallet(server: String, chainhint: String, promise: Promise) {
- // Log.w("MAIN", "Creating new wallet")
+ // Log.i("MAIN", "Creating new wallet")
RustFFI.initlogging()
// Create a seed
val seed = RustFFI.initnew(server, reactContext.applicationContext.filesDir.absolutePath, chainhint, "true")
- // Log.w("MAIN-Seed", seed)
+ // Log.i("MAIN-Seed", seed)
- if (!seed.startsWith("Error")) {
+ if (!seed.lowercase().startsWith("error")) {
saveWallet()
}
@@ -70,14 +64,14 @@ class RPCModule internal constructor(private val reactContext: ReactApplicationC
@ReactMethod
fun restoreWalletFromSeed(seed: String, birthday: String, server: String, chainhint: String, promise: Promise) {
- // Log.w("MAIN", "Restoring wallet with seed $seed")
+ // Log.i("MAIN", "Restoring wallet with seed $seed")
RustFFI.initlogging()
val rseed = RustFFI.initfromseed(server, seed, birthday, reactContext.applicationContext.filesDir.absolutePath, chainhint, "true")
- // Log.w("MAIN", rseed)
+ // Log.i("MAIN", rseed)
- if (!rseed.startsWith("Error")) {
+ if (!rseed.lowercase().startsWith("Error")) {
saveWallet()
}
@@ -86,14 +80,14 @@ class RPCModule internal constructor(private val reactContext: ReactApplicationC
@ReactMethod
fun restoreWalletFromUfvk(ufvk: String, birthday: String, server: String, chainhint: String, promise: Promise) {
- // Log.w("MAIN", "Restoring wallet with ufvk $ufvk")
+ // Log.i("MAIN", "Restoring wallet with ufvk $ufvk")
RustFFI.initlogging()
val rufvk = RustFFI.initfromufvk(server, ufvk, birthday, reactContext.applicationContext.filesDir.absolutePath, chainhint, "true")
- // Log.w("MAIN", rufvk)
+ // Log.i("MAIN", rufvk)
- if (!rufvk.startsWith("Error")) {
+ if (!rufvk.lowercase().startsWith("Error")) {
saveWallet()
}
@@ -102,13 +96,17 @@ class RPCModule internal constructor(private val reactContext: ReactApplicationC
@ReactMethod
fun loadExistingWallet(server: String, chainhint: String, promise: Promise) {
+ promise.resolve(loadExistingWalletNative(server, chainhint))
+ }
+
+ fun loadExistingWalletNative(server: String, chainhint: String): String {
// Read the file
val file: InputStream = MainApplication.getAppContext()?.openFileInput("wallet.dat")!!
var fileBytes = file.readBytes()
file.close()
- val middle0w = 0
- val middle1w = 6000000 // 6_000_000 - 8 pieces
+ val middle0w = 0
+ val middle1w = 6000000 // 6_000_000 - 8 pieces
val middle2w = 12000000
val middle3w = 18000000
val middle4w = 24000000
@@ -119,34 +117,139 @@ class RPCModule internal constructor(private val reactContext: ReactApplicationC
var fileb64 = StringBuilder("")
if (middle8w <= middle1w) {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle0w, middle8w - middle0w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle0w,
+ middle8w - middle0w,
+ Base64.NO_WRAP
+ )
+ )
} else {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle0w, middle1w - middle0w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle0w,
+ middle1w - middle0w,
+ Base64.NO_WRAP
+ )
+ )
if (middle8w <= middle2w) {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle1w, middle8w - middle1w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle1w,
+ middle8w - middle1w,
+ Base64.NO_WRAP
+ )
+ )
} else {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle1w, middle2w - middle1w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle1w,
+ middle2w - middle1w,
+ Base64.NO_WRAP
+ )
+ )
if (middle8w <= middle3w) {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle2w, middle8w - middle2w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle2w,
+ middle8w - middle2w,
+ Base64.NO_WRAP
+ )
+ )
} else {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle2w, middle3w - middle2w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle2w,
+ middle3w - middle2w,
+ Base64.NO_WRAP
+ )
+ )
if (middle8w <= middle4w) {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle3w, middle8w - middle3w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle3w,
+ middle8w - middle3w,
+ Base64.NO_WRAP
+ )
+ )
} else {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle3w, middle4w - middle3w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle3w,
+ middle4w - middle3w,
+ Base64.NO_WRAP
+ )
+ )
if (middle8w <= middle5w) {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle4w, middle8w - middle4w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle4w,
+ middle8w - middle4w,
+ Base64.NO_WRAP
+ )
+ )
} else {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle4w, middle5w - middle4w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle4w,
+ middle5w - middle4w,
+ Base64.NO_WRAP
+ )
+ )
if (middle8w <= middle6w) {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle5w, middle8w - middle5w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle5w,
+ middle8w - middle5w,
+ Base64.NO_WRAP
+ )
+ )
} else {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle5w, middle6w - middle5w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle5w,
+ middle6w - middle5w,
+ Base64.NO_WRAP
+ )
+ )
if (middle8w <= middle7w) {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle6w, middle8w - middle6w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle6w,
+ middle8w - middle6w,
+ Base64.NO_WRAP
+ )
+ )
} else {
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle6w, middle7w - middle6w, Base64.NO_WRAP))
- fileb64 = fileb64.append(Base64.encodeToString(fileBytes, middle7w, middle8w - middle7w, Base64.NO_WRAP))
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle6w,
+ middle7w - middle6w,
+ Base64.NO_WRAP
+ )
+ )
+ fileb64 = fileb64.append(
+ Base64.encodeToString(
+ fileBytes,
+ middle7w,
+ middle8w - middle7w,
+ Base64.NO_WRAP
+ )
+ )
}
}
}
@@ -157,13 +260,14 @@ class RPCModule internal constructor(private val reactContext: ReactApplicationC
RustFFI.initlogging()
- val wseed = RustFFI.initfromb64(server,
+ // Log.i("MAIN", wseed)
+
+ return RustFFI.initfromb64(
+ server,
fileb64.toString(),
reactContext.applicationContext.filesDir.absolutePath,
- chainhint, "true")
- // Log.w("MAIN", wseed)
-
- promise.resolve(wseed)
+ chainhint, "true"
+ )
}
@ReactMethod
@@ -225,9 +329,9 @@ class RPCModule internal constructor(private val reactContext: ReactApplicationC
RustFFI.initlogging()
- // Log.w("send", "Trying to send $sendJSON")
+ // Log.i("send", "Trying to send $sendJSON")
val result = RustFFI.execute("send", sendJSON)
- // Log.w("send", "Send Result: $result")
+ // Log.i("send", "Send Result: $result")
promise.resolve(result)
}
@@ -239,12 +343,12 @@ class RPCModule internal constructor(private val reactContext: ReactApplicationC
RustFFI.initlogging()
- // Log.w("execute", "Executing $cmd with $args")
+ // Log.i("execute", "Executing $cmd with $args")
val resp = RustFFI.execute(cmd, args)
- // Log.w("execute", "Response to $cmd : $resp")
+ // Log.i("execute", "Response to $cmd : $resp")
// And save it if it was a sync
- if (cmd == "sync" && !resp.startsWith("Error")) {
+ if (cmd == "sync" && !resp.lowercase().startsWith("Error")) {
saveWallet()
}
@@ -266,14 +370,14 @@ class RPCModule internal constructor(private val reactContext: ReactApplicationC
promise.resolve(true)
}
- private fun saveWallet() {
+ fun saveWallet() {
// Get the encoded wallet file
val b64encoded = RustFFI.save()
- // Log.w("MAIN", b64encoded)
+ // Log.i("MAIN", b64encoded)
try {
val fileBytes = Base64.decode(b64encoded, Base64.NO_WRAP)
- Log.w("MAIN", "file size: ${fileBytes.size} bytes")
+ Log.i("MAIN", "file size: ${fileBytes.size} bytes")
// Save file to disk
val file = MainApplication.getAppContext()?.openFileOutput("wallet.dat", Context.MODE_PRIVATE)
@@ -291,11 +395,11 @@ class RPCModule internal constructor(private val reactContext: ReactApplicationC
val fileRead = MainApplication.getAppContext()!!.openFileInput("wallet.dat")
val fileBytes = fileRead.readBytes()
// val fileb64 = Base64.encodeToString(fileBytes, Base64.NO_WRAP)
- // Log.w("MAIN", b64encoded)
+ // Log.i("MAIN", b64encoded)
try {
// val fileBytes = Base64.decode(b64encoded, Base64.NO_WRAP)
- // Log.w("MAIN", "file size${fileBytes.size}")
+ // Log.i("MAIN", "file size${fileBytes.size}")
// Save file to disk
val file = MainApplication.getAppContext()?.openFileOutput("wallet.backup.dat", Context.MODE_PRIVATE)
@@ -306,9 +410,25 @@ class RPCModule internal constructor(private val reactContext: ReactApplicationC
}
}
+ fun saveBackgroundFile(json: String) {
+ // Log.i("MAIN", b64encoded)
+
+ try {
+ val fileBytes: ByteArray = json.toByteArray()
+ Log.i("MAIN", "file background size: ${fileBytes.size} bytes")
+
+ // Save file to disk
+ val file = MainApplication.getAppContext()?.openFileOutput("background.json", Context.MODE_PRIVATE)
+ file?.write(fileBytes)
+ file?.close()
+ } catch (e: IllegalArgumentException) {
+ Log.e("MAIN", "Couldn't save the background file")
+ }
+ }
+
@ReactMethod
fun getLatestBlock(server: String, promise: Promise) {
- // Log.w("MAIN", "Initialize Light Client")
+ // Log.i("MAIN", "Initialize Light Client")
RustFFI.initlogging()
diff --git a/android/build.gradle b/android/build.gradle
index 6cae882ac..12b8eed52 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -7,7 +7,7 @@ buildscript {
compileSdkVersion = 33
targetSdkVersion = 33
ndkVersion = "23.2.8568313"
- kotlinVersion = '1.6.21'
+ kotlinVersion = '1.9.0'
}
repositories {
google()
diff --git a/app/AppState/types/BackgroundType.ts b/app/AppState/types/BackgroundType.ts
index 901a27fe0..4ed0c3acf 100644
--- a/app/AppState/types/BackgroundType.ts
+++ b/app/AppState/types/BackgroundType.ts
@@ -2,5 +2,6 @@ export default interface BackgroundType {
batches: number;
message: string;
date: number;
+ dateEnd: number;
// eslint-disable-next-line semi
}
diff --git a/app/BackgroundSync.ts b/app/BackgroundSync.ts
deleted file mode 100644
index e051f7be9..000000000
--- a/app/BackgroundSync.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-import RPCModule from './RPCModule';
-import AsyncStorage from '@react-native-async-storage/async-storage';
-import NetInfo, { NetInfoStateType } from '@react-native-community/netinfo';
-import { RPCSyncStatusType } from './rpc/types/RPCSyncStatusType';
-
-const BackgroundSync = async (task_data: any) => {
- // this not interact with the server.
- const exists = await RPCModule.walletExists();
-
- // only if exists the wallet file make sense to do the sync.
- if (exists && exists !== 'false') {
- // only if we have connection make sense to call RPCModule.
- const networkState = await NetInfo.fetch();
- if (
- !networkState.isConnected ||
- networkState.type === NetInfoStateType.cellular ||
- (networkState.details !== null && networkState.details.isConnectionExpensive)
- ) {
- //console.log(
- // 'BS: Not started (connected: ' + networkState.isConnected,
- // +', type: ' +
- // networkState.type +
- // +', expensive connection: ' +
- // networkState.details?.isConnectionExpensive +
- // ')',
- //);
- return;
- }
- // if the App goes to Foreground kill the interval
- const background = await AsyncStorage.getItem('@background');
- if (background === 'no') {
- //console.log('BS: Not started (going to foreground)');
- return;
- }
-
- let batch_num = -1;
- console.log('BS:', task_data);
-
- // finishEarly has two fields: wait, and done.
- // wait() returns a promise, which is resolved when
- // done() is called
- let finishEarly = manuallyResolve();
-
- let saver = setInterval(async () => {
- const networkStateSaver = await NetInfo.fetch();
- if (
- !networkStateSaver.isConnected ||
- networkStateSaver.type === NetInfoStateType.cellular ||
- (networkStateSaver.details !== null && networkStateSaver.details.isConnectionExpensive)
- ) {
- //console.log(
- // 'BS: Interrupted (connected: ' + networkStateSaver.isConnected,
- // +', type: ' +
- // networkStateSaver.type +
- // +', expensive connection: ' +
- // networkStateSaver.details?.isConnectionExpensive +
- // ')',
- //);
- clearInterval(saver);
- finishEarly.done();
- return;
- }
- // if the App goes to Foreground kill the interval
- const backgroundSaver = await AsyncStorage.getItem('@background');
- if (backgroundSaver === 'no') {
- clearInterval(saver);
- //console.log('BS: Finished (going to foreground)');
- finishEarly.done();
- return;
- }
-
- const syncStatusStr: string = await RPCModule.execute('syncstatus', '');
- if (syncStatusStr) {
- if (syncStatusStr.toLowerCase().startsWith('error')) {
- //console.log(`BS: Error sync status ${syncStatusStr}`);
- return;
- }
- } else {
- //console.log('BS: Internal Error sync status');
- return;
- }
-
- let ss = {} as RPCSyncStatusType;
- try {
- ss = await JSON.parse(syncStatusStr);
- } catch (e) {
- //console.log('BS: Error parsing syncstatus JSON', e);
- return;
- }
-
- //console.log('BS:', ss);
- if (ss.batch_num && ss.batch_num > -1 && batch_num !== ss.batch_num) {
- await RPCModule.doSave();
- //console.log('BS: saving...');
- // update batch_num with the new value, otherwise never change
- batch_num = ss.batch_num;
- }
- }, 5000);
-
- await Promise.race([RPCModule.execute('sync', ''), finishEarly.wait()]);
- clearInterval(saver);
- } else {
- console.log('BS: wallet file does not exist');
- }
- //console.log('BS: Finished (end of syncing)');
-};
-
-export default BackgroundSync;
-
-function manuallyResolve() {
- let resolve: Function;
- // new Promise takes a function as an argument. When that function is called
- // the promise resolves with the value output by that function.
- // By passing the function out of the promise, we can call it later
- // in order to resolve the promise at will
- const promise = new Promise(fun => {
- resolve = fun;
- });
-
- function done() {
- resolve();
- }
-
- function wait() {
- return promise;
- }
-
- return { wait, done };
-}
diff --git a/app/LoadedApp/LoadedApp.tsx b/app/LoadedApp/LoadedApp.tsx
index 42a7bd70f..79d4dfae3 100644
--- a/app/LoadedApp/LoadedApp.tsx
+++ b/app/LoadedApp/LoadedApp.tsx
@@ -9,7 +9,6 @@ import {
EmitterSubscription,
AppState,
NativeEventSubscription,
- Platform,
Linking,
SafeAreaView,
} from 'react-native';
@@ -98,7 +97,7 @@ export default function LoadedApp(props: LoadedAppProps) {
const [sendAll, setSendAll] = useState(false);
const [privacy, setPrivacy] = useState(false);
const [mode, setMode] = useState<'basic' | 'advanced'>('basic');
- const [background, setBackground] = useState({ batches: 0, message: '', date: 0 });
+ const [background, setBackground] = useState({ batches: 0, message: '', date: 0, dateEnd: 0 });
const [loading, setLoading] = useState(true);
const file = useMemo(
() => ({
@@ -178,13 +177,10 @@ export default function LoadedApp(props: LoadedAppProps) {
}
// reading background task info
- if (Platform.OS === 'ios') {
- // this file only exists in IOS BS.
- const backgroundJson = await BackgroundFileImpl.readBackground();
- //console.log('background', backgroundJson);
- if (backgroundJson) {
- setBackground(backgroundJson);
- }
+ const backgroundJson = await BackgroundFileImpl.readBackground();
+ //console.log('background', backgroundJson);
+ if (backgroundJson) {
+ setBackground(backgroundJson);
}
setLoading(false);
})();
@@ -298,13 +294,10 @@ export class LoadedAppClass extends Component {
if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
//console.log('App has come to the foreground!');
- // deactivate the interruption sync flag
- await RPC.rpc_setInterruptSyncAfterBatch('false');
+ // deactivate the interruption sync flag. No needed.
+ //await RPC.rpc_setInterruptSyncAfterBatch('false');
// reading background task info
- if (Platform.OS === 'ios') {
- // this file only exists in IOS BS.
- await this.fetchBackgroundSyncing();
- }
+ await this.fetchBackgroundSyncing();
// setting value for background task Android
await AsyncStorage.setItem('@background', 'no');
//console.log('background no in storage');
@@ -317,6 +310,8 @@ export class LoadedAppClass extends Component(false);
const [privacy, setPrivacy] = useState(false);
const [mode, setMode] = useState<'basic' | 'advanced'>('advanced'); // by default advanced
- const [background, setBackground] = useState({ batches: 0, message: '', date: 0 });
+ const [background, setBackground] = useState({ batches: 0, message: '', date: 0, dateEnd: 0 });
const [firstLaunchingMessage, setFirstLaunchingMessage] = useState(false);
const [loading, setLoading] = useState(true);
const file = useMemo(
@@ -168,12 +167,9 @@ export default function LoadingApp(props: LoadingAppProps) {
//await delay(5000);
// reading background task info
- if (Platform.OS === 'ios') {
- // this file only exists in IOS BS.
- const backgroundJson = await BackgroundFileImpl.readBackground();
- if (backgroundJson) {
- setBackground(backgroundJson);
- }
+ const backgroundJson = await BackgroundFileImpl.readBackground();
+ if (backgroundJson) {
+ setBackground(backgroundJson);
}
setLoading(false);
})();
@@ -357,10 +353,7 @@ export class LoadingAppClass extends Component {
- const backgroundJson = await BackgroundFileImpl.readBackground();
+ const backgroundJson: BackgroundType = await BackgroundFileImpl.readBackground();
if (backgroundJson) {
- this.setState({
- background: backgroundJson,
- });
+ this.setState({ background: backgroundJson });
}
};
diff --git a/app/context/contextAppLoaded.tsx b/app/context/contextAppLoaded.tsx
index 08d84dfda..0331e3e40 100644
--- a/app/context/contextAppLoaded.tsx
+++ b/app/context/contextAppLoaded.tsx
@@ -75,7 +75,9 @@ export const defaultAppStateLoaded: AppStateLoaded = {
sendAll: false,
background: {
batches: 0,
+ message: '',
date: 0,
+ dateEnd: 0,
} as BackgroundType,
translate: () => '',
diff --git a/app/context/contextAppLoading.tsx b/app/context/contextAppLoading.tsx
index cd6fcc9e6..f08648374 100644
--- a/app/context/contextAppLoading.tsx
+++ b/app/context/contextAppLoading.tsx
@@ -38,7 +38,9 @@ export const defaultAppStateLoading: AppStateLoading = {
sendAll: false,
background: {
batches: 0,
+ message: '',
date: 0,
+ dateEnd: 0,
} as BackgroundType,
translate: () => '',
diff --git a/app/rpc/RPC.ts b/app/rpc/RPC.ts
index f989c25e0..e9b12cbce 100644
--- a/app/rpc/RPC.ts
+++ b/app/rpc/RPC.ts
@@ -517,8 +517,17 @@ export default class RPC {
return reducedDetailedTxns;
}
- // this is only for the first time when the App is booting.
+ // this is only for the first time when the App is booting, but
+ // there are more cases:
+ // - LoadedApp mounting component.
+ // - App go to Foreground.
+ // - Internet from Not Connected to Connected.
+ // - Cambio de Servidor.
async configure(): Promise {
+ // First things first, I need to stop an existing sync process (if any)
+ // clean start.
+ await this.stopSyncProcess();
+
// every 30 seconds the App try to Sync the new blocks.
if (!this.refreshTimerID) {
this.refreshTimerID = setInterval(() => {
@@ -564,6 +573,40 @@ export default class RPC {
}, 1000);
}
+ sleep = (ms: number) => new Promise(r => setTimeout(r, ms));
+
+ async stopSyncProcess(): Promise {
+ let returnStatus = await this.doSyncStatus();
+ if (returnStatus.toLowerCase().startsWith('error')) {
+ return;
+ }
+ let ss = {} as RPCSyncStatusType;
+ try {
+ ss = await JSON.parse(returnStatus);
+ } catch (e) {
+ return;
+ }
+
+ console.log('stop sync process. in progress', ss.in_progress);
+
+ while (ss.in_progress) {
+ // interrupting sync process
+ await RPC.rpc_setInterruptSyncAfterBatch('true');
+
+ // sleep for half second
+ await this.sleep(500);
+
+ returnStatus = await this.doSyncStatus();
+ ss = await JSON.parse(returnStatus);
+
+ console.log('stop sync process. in progress', ss.in_progress);
+ }
+ console.log('stop sync process. STOPPED');
+
+ // NOT interrupting sync process
+ await RPC.rpc_setInterruptSyncAfterBatch('false');
+ }
+
async clearTimers(): Promise {
if (this.refreshTimerID) {
clearInterval(this.refreshTimerID);
diff --git a/app/translations/en.json b/app/translations/en.json
index 1ee7c99ef..4afda6409 100644
--- a/app/translations/en.json
+++ b/app/translations/en.json
@@ -1,6 +1,6 @@
{
"zingo": "Zingo!",
- "version": "zingo-1.3.4 (137)",
+ "version": "zingo-1.3.4 (145)",
"loading": "loading...",
"connectingserver": "Connecting to the server...",
"wait": "Please wait...",
diff --git a/app/translations/es.json b/app/translations/es.json
index 1b238ee15..71a5c1b21 100644
--- a/app/translations/es.json
+++ b/app/translations/es.json
@@ -1,6 +1,6 @@
{
"zingo": "Zingo!",
- "version": "zingo-1.3.4 (137)",
+ "version": "zingo-1.3.4 (145)",
"loading": "cargando...",
"connectingserver": "Conectando con el servidor...",
"wait": "Por favor espere...",
diff --git a/components/Background/BackgroundFileImpl.ts b/components/Background/BackgroundFileImpl.ts
index 4dcf38b1e..c6e10c952 100644
--- a/components/Background/BackgroundFileImpl.ts
+++ b/components/Background/BackgroundFileImpl.ts
@@ -10,7 +10,7 @@ export default class BackgroundFileImpl {
// Write the server background
static async reset() {
const fileName = await this.getFileName();
- const newBackground: BackgroundType = { batches: 0, message: '', date: 0 };
+ const newBackground: BackgroundType = { batches: 0, message: '', date: 0, dateEnd: 0 };
RNFS.writeFile(fileName, JSON.stringify(newBackground), 'utf8')
.then(() => {
@@ -34,7 +34,7 @@ export default class BackgroundFileImpl {
} catch (err) {
// File probably doesn't exist, so return nothing
console.log('background json Error', err);
- return { batches: 0, date: 0 } as BackgroundType;
+ return { batches: 0, message: '', date: 0, dateEnd: 0 } as BackgroundType;
}
}
}
diff --git a/components/SyncReport/SyncReport.tsx b/components/SyncReport/SyncReport.tsx
index c2fa3ebf5..423e7affb 100644
--- a/components/SyncReport/SyncReport.tsx
+++ b/components/SyncReport/SyncReport.tsx
@@ -219,25 +219,29 @@ const SyncReport: React.FunctionComponent = ({ closeModal }) =>
/>
)}
- {Number(background.date) > 0 && showBackgroundLegend && (
-
-
- {!!background.message && {background.message}}
-
- )}
+ {(Number(background.date) > 0 || Number(background.dateEnd) > 0 || !!background.message) &&
+ showBackgroundLegend && (
+
+ 0
+ ? ' - ' + moment(Number(Number(background.dateEnd).toFixed(0)) * 1000).format('YYYY MMM D h:mm a')
+ : '')
+ }
+ />
+ {!!background.message && {background.message}}
+
+ )}
{maxBlocks && netInfo.isConnected ? (
<>
diff --git a/index.js b/index.js
index 32168fcb8..9b7393291 100644
--- a/index.js
+++ b/index.js
@@ -5,7 +5,5 @@
import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';
-import BackgroundSync from './app/BackgroundSync';
-AppRegistry.registerHeadlessTask('BackgroundSync', () => BackgroundSync);
AppRegistry.registerComponent(appName, () => App);
diff --git a/ios/ZingoMobile.xcodeproj/project.pbxproj b/ios/ZingoMobile.xcodeproj/project.pbxproj
index 4b53f90ed..494835773 100644
--- a/ios/ZingoMobile.xcodeproj/project.pbxproj
+++ b/ios/ZingoMobile.xcodeproj/project.pbxproj
@@ -533,7 +533,7 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = ZingoMobile/ZingoMobile.entitlements;
- CURRENT_PROJECT_VERSION = 137;
+ CURRENT_PROJECT_VERSION = 145;
DEVELOPMENT_TEAM = 788KRST4S8;
ENABLE_BITCODE = NO;
EXCLUDED_ARCHS = "";
@@ -573,7 +573,7 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = ZingoMobile/ZingoMobile.entitlements;
- CURRENT_PROJECT_VERSION = 137;
+ CURRENT_PROJECT_VERSION = 145;
DEVELOPMENT_TEAM = 788KRST4S8;
ENABLE_BITCODE = NO;
EXCLUDED_ARCHS = "";
diff --git a/ios/ZingoMobile/AppDelegate.m b/ios/ZingoMobile/AppDelegate.m
index e6f72f75c..023d4cba0 100644
--- a/ios/ZingoMobile/AppDelegate.m
+++ b/ios/ZingoMobile/AppDelegate.m
@@ -31,11 +31,10 @@ static void InitializeFlipper(UIApplication *application) {
@implementation AppDelegate
-static NSString* syncTask = @"Zingo_Processing_Task_ID";
-static NSString* syncSchedulerTask = @"Zingo_Processing_Scheduler_Task_ID";
-static BOOL isConnectedToWifi = false;
-static BOOL isCharging = false;
-static BGProcessingTask *bgTask = nil;
+NSString* syncTask = @"Zingo_Processing_Task_ID";
+NSString* syncSchedulerTask = @"Zingo_Processing_Scheduler_Task_ID";
+BGProcessingTask *bgTask = nil;
+NSString* timeStampStrStart = nil;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
@@ -57,8 +56,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
[self.window makeKeyAndVisible];
if (@available(iOS 13.0, *)) {
- NSLog(@"BGTask handleBackgroundTask");
- [self handleBackgroundTask];
+ NSLog(@"BGTask registerTasks");
+ [self registerTasks];
}
return YES;
@@ -134,36 +133,36 @@ -(void)stopSyncingProcess:(NSString *)noValue {
@autoreleasepool {
NSLog(@"BGTask stopSyncingProcess");
- char *resp = execute("syncstatus", "");
- NSString* respStr = [NSString stringWithUTF8String:resp];
- rust_free(resp);
- NSLog(@"BGTask stopSyncingProcess - status response %@", respStr);
+ char *status = execute("syncstatus", "");
+ NSString* statusStr = [NSString stringWithUTF8String:status];
+ rust_free(status);
+ NSLog(@"BGTask stopSyncingProcess - status response %@", statusStr);
- if ([respStr hasPrefix:@"Error"]) {
+ if ([statusStr hasPrefix:@"Error"]) {
NSLog(@"BGTask stopSyncingProcess - no lightwalled likely");
return;
}
- NSData *data = [respStr dataUsingEncoding:NSUTF8StringEncoding];
+ NSData *data = [statusStr dataUsingEncoding:NSUTF8StringEncoding];
id jsonResp = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSString *inProgressStr = [jsonResp valueForKey:@"in_progress"];
BOOL inProgress = [inProgressStr boolValue];
while(inProgress) {
- char *resp2 = execute("interrupt_sync_after_batch", "true");
- NSString* respStr2 = [NSString stringWithUTF8String:resp2];
- NSLog(@"BGTask stopSyncingProcess - interrupt syncing %@", respStr2);
+ char *interrupt = execute("interrupt_sync_after_batch", "true");
+ NSString* interruptStr = [NSString stringWithUTF8String:interrupt];
+ NSLog(@"BGTask stopSyncingProcess - interrupt syncing %@", interruptStr);
[NSThread sleepForTimeInterval: 0.5];
- char *resp = execute("syncstatus", "");
- NSString* respStr = [NSString stringWithUTF8String:resp];
- rust_free(resp);
- NSLog(@"BGTask stopSyncingProcess - status response %@", respStr);
+ status = execute("syncstatus", "");
+ statusStr = [NSString stringWithUTF8String:status];
+ rust_free(status);
+ NSLog(@"BGTask stopSyncingProcess - status response %@", statusStr);
- NSData *data = [respStr dataUsingEncoding:NSUTF8StringEncoding];
- id jsonResp = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
- NSString *inProgressStr = [jsonResp valueForKey:@"in_progress"];
+ data = [statusStr dataUsingEncoding:NSUTF8StringEncoding];
+ jsonResp = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
+ inProgressStr = [jsonResp valueForKey:@"in_progress"];
inProgress = [inProgressStr boolValue];
}
@@ -177,16 +176,27 @@ -(void)syncingProcessBackgroundTask:(NSString *)noValue {
//do things with task
@autoreleasepool {
+ RPCModule *rpcmodule = [RPCModule new];
+
+ // save info in background json
+ NSTimeInterval timeStampStart = [[NSDate date] timeIntervalSince1970];
+ // NSTimeInterval is defined as double
+ NSNumber *timeStampObjStart = [NSNumber numberWithDouble: timeStampStart];
+ timeStampStrStart = [timeStampObjStart stringValue];
+ NSString *jsonBackgroudStart = [NSString stringWithFormat: @"%@%@%@%@%@%@%@%@%@", @"{\"batches\": \"", @"0", @"\", \"message\": \"", @"Starting OK.", @"\", \"date\": \"", timeStampStrStart, @"\", \"dateEnd\": \"", @"0", @"\"}"];
+ [rpcmodule saveBackgroundFile:jsonBackgroudStart];
+ NSLog(@"BGTask syncingProcessBackgroundTask - Save background JSON %@", jsonBackgroudStart);
+
NSLog(@"BGTask syncingProcessBackgroundTask");
BOOL exists = [self wallet__exists];
if (exists) {
// check the Server, because the task can run without the App.
- char *bal = execute("balance", "");
- NSString* balStr = [NSString stringWithUTF8String:bal];
- NSLog(@"BGTask syncingProcessBackgroundTask - testing if server is active %@", balStr);
- rust_free(bal);
- if ([balStr hasPrefix:@"Error"]) {
+ char *balance = execute("balance", "");
+ NSString* balanceStr = [NSString stringWithUTF8String:balance];
+ NSLog(@"BGTask syncingProcessBackgroundTask - testing if server is active %@", balanceStr);
+ rust_free(balance);
+ if ([balanceStr hasPrefix:@"Error"]) {
// this means this task is running with the App closed
[self loadWalletFile:nil];
} else {
@@ -196,10 +206,10 @@ -(void)syncingProcessBackgroundTask:(NSString *)noValue {
}
// we need to sync without interruption, I run this just in case
- char *resp = execute("interrupt_sync_after_batch", "false");
- NSString* respStr = [NSString stringWithUTF8String:resp];
- NSLog(@"BGTask syncingProcessBackgroundTask - no interrupt syncing %@", respStr);
- rust_free(resp);
+ char *noInterrupt = execute("interrupt_sync_after_batch", "false");
+ NSString* noInterruptStr = [NSString stringWithUTF8String:noInterrupt];
+ NSLog(@"BGTask syncingProcessBackgroundTask - no interrupt syncing %@", noInterruptStr);
+ rust_free(noInterrupt);
// the task is running here blocking this execution until this process finished:
// 1. finished the syncing.
@@ -207,15 +217,27 @@ -(void)syncingProcessBackgroundTask:(NSString *)noValue {
NSLog(@"BGTask syncingProcessBackgroundTask - sync BEGIN");
- char *resp2 = execute("sync", "");
- NSString* respStr2 = [NSString stringWithUTF8String:resp2];
- rust_free(resp2);
+ char *syncing = execute("sync", "");
+ NSString* syncingStr = [NSString stringWithUTF8String:syncing];
+ rust_free(syncing);
- NSLog(@"BGTask syncingProcessBackgroundTask - sync END %@", respStr2);
+ NSLog(@"BGTask syncingProcessBackgroundTask - sync END %@", syncingStr);
} else {
NSLog(@"BGTask syncingProcessBackgroundTask - No exists wallet file END");
+ // save info in background json
+ NSTimeInterval timeStampError = [[NSDate date] timeIntervalSince1970];
+ // NSTimeInterval is defined as double
+ NSNumber *timeStampObjError = [NSNumber numberWithDouble: timeStampError];
+ NSString *timeStampStrError = [timeStampObjError stringValue];
+ NSString *jsonBackgroudError = [NSString stringWithFormat: @"%@%@%@%@%@%@%@%@%@", @"{\"batches\": \"", @"0", @"\", \"message\": \"", @"No active wallet KO.", @"\", \"date\": \"", timeStampStrStart, @"\", \"dateEnd\": \"", timeStampStrError, @"\"}"];
+ [rpcmodule saveBackgroundFile:jsonBackgroudError];
+ NSLog(@"BGTask syncingProcessBackgroundTask - Save background JSON %@", jsonBackgroudError);
+
+ [bgTask setTaskCompletedWithSuccess:NO];
+ bgTask = nil;
+ return;
}
@@ -225,18 +247,17 @@ -(void)syncingProcessBackgroundTask:(NSString *)noValue {
// I'm gessing NO.
// save the wallet
- RPCModule *rpcmodule = [RPCModule new];
[rpcmodule saveWalletInternal];
NSLog(@"BGTask syncingProcessBackgroundTask - Save Wallet");
// save info in background json
- NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
+ NSTimeInterval timeStampEnd = [[NSDate date] timeIntervalSince1970];
// NSTimeInterval is defined as double
- NSNumber *timeStampObj = [NSNumber numberWithDouble: timeStamp];
- NSString *timeStampStr = [timeStampObj stringValue];
- NSString *jsonBackgroud = [NSString stringWithFormat: @"%@%@%@%@%@%@%@", @"{\"batches\": \"", @"0", @"\", \"message\": \"", @"Finished OK.", @"\", \"date\": \"", timeStampStr, @"\"}"];
- [rpcmodule saveBackgroundFile:jsonBackgroud];
- NSLog(@"BGTask syncingProcessBackgroundTask - Save background JSON");
+ NSNumber *timeStampObjEnd = [NSNumber numberWithDouble: timeStampEnd];
+ NSString *timeStampStrEnd = [timeStampObjEnd stringValue];
+ NSString *jsonBackgroudEnd = [NSString stringWithFormat: @"%@%@%@%@%@%@%@%@%@", @"{\"batches\": \"", @"0", @"\", \"message\": \"", @"Finished OK.", @"\", \"date\": \"", timeStampStrStart, @"\", \"dateEnd\": \"", timeStampStrEnd, @"\"}"];
+ [rpcmodule saveBackgroundFile:jsonBackgroudEnd];
+ NSLog(@"BGTask syncingProcessBackgroundTask - Save background JSON %@", jsonBackgroudEnd);
[bgTask setTaskCompletedWithSuccess:YES];
bgTask = nil;
@@ -289,32 +310,6 @@ -(BOOL)wallet__exists {
// NEW BACKGROUND SCHEDULING TASKS
-- (void)handleBackgroundTask {
- // We require the background task to run when connected to the power and wifi
- Reachability *reachability = [Reachability reachabilityForInternetConnection];
- NetworkStatus networkStatus = [reachability currentReachabilityStatus];
-
- if (networkStatus == ReachableViaWiFi) {
- // the device have Wifi.
- isConnectedToWifi = true;
- } else {
- isConnectedToWifi = false;
- }
-
- UIDeviceBatteryState currentState = [[UIDevice currentDevice] batteryState];
-
- if (currentState == UIDeviceBatteryStateCharging) {
- // The battery is either charging, or connected to a charger.
- isCharging = true;
- } else {
- isCharging = false;
- }
-
- NSLog(@"BGTask isConnectedToWifi %@ isCharging %@", isConnectedToWifi ? @"true" : @"false", isCharging ? @"true" : @"false");
-
- [self registerTasks];
-}
-
- (void)registerTasks {
BOOL bcgSyncTaskResult;
bcgSyncTaskResult = [[BGTaskScheduler sharedScheduler] registerForTaskWithIdentifier:syncTask usingQueue:dispatch_get_main_queue()
@@ -346,42 +341,11 @@ - (void)registerTasks {
- (void)startBackgroundTask:(NSString *)noValue {
NSLog(@"BGTask startBackgroundTask called");
- RPCModule *rpcmodule = [RPCModule new];
// Schedule tasks for the next time
[self scheduleBackgroundTask];
[self scheduleSchedulerBackgroundTask];
- if (!isConnectedToWifi) {
- // save info in background json
- NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
- // NSTimeInterval is defined as double
- NSNumber *timeStampObj = [NSNumber numberWithDouble: timeStamp];
- NSString *timeStampStr = [timeStampObj stringValue];
- NSString *jsonBackgroud = [NSString stringWithFormat: @"%@%@%@%@%@%@%@", @"{\"batches\": \"", @"0", @"\", \"message\": \"", @"No wifi KO.", @"\", \"date\": \"", timeStampStr, @"\"}"];
- [rpcmodule saveBackgroundFile:jsonBackgroud];
-
- NSLog(@"BGTask startBackgroundTask: not connected to the wifi");
- [bgTask setTaskCompletedWithSuccess:NO];
- bgTask = nil;
- return;
- }
-
- if (!isCharging) {
- // save info in background json
- NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
- // NSTimeInterval is defined as double
- NSNumber *timeStampObj = [NSNumber numberWithDouble: timeStamp];
- NSString *timeStampStr = [timeStampObj stringValue];
- NSString *jsonBackgroud = [NSString stringWithFormat: @"%@%@%@%@%@%@%@", @"{\"batches\": \"", @"0", @"\", \"message\": \"", @"No plug-in KO.", @"\", \"date\": \"", timeStampStr, @"\"}"];
- [rpcmodule saveBackgroundFile:jsonBackgroud];
-
- NSLog(@"BGTask startBackgroundTask: not plug in to power");
- [bgTask setTaskCompletedWithSuccess:NO];
- bgTask = nil;
- return;
- }
-
// Start the syncing
NSLog(@"BGTask startBackgroundTask run sync task");
// in order to run only one task
@@ -393,12 +357,13 @@ - (void)startBackgroundTask:(NSString *)noValue {
NSLog(@"BGTask startBackgroundTask - expirationHandler called");
// interrupting the sync process, I can't wait to see if the process is over
// because I have no time enough to run all I need in this task.
- char *resp2 = execute("interrupt_sync_after_batch", "true");
- NSString* respStr2 = [NSString stringWithUTF8String:resp2];
- NSLog(@"BGTask startBackgroundTask - expirationHandler interrupt syncing %@", respStr2);
+ char *interrupt = execute("interrupt_sync_after_batch", "true");
+ NSString* interruptStr = [NSString stringWithUTF8String:interrupt];
+ NSLog(@"BGTask startBackgroundTask - expirationHandler interrupt syncing %@", interruptStr);
+
+ RPCModule *rpcmodule = [RPCModule new];
// save the wallet
- RPCModule *rpcmodule = [RPCModule new];
[rpcmodule saveWalletInternal];
NSLog(@"BGTask startBackgroundTask - expirationHandler Save Wallet");
@@ -407,9 +372,9 @@ - (void)startBackgroundTask:(NSString *)noValue {
// NSTimeInterval is defined as double
NSNumber *timeStampObj = [NSNumber numberWithDouble: timeStamp];
NSString *timeStampStr = [timeStampObj stringValue];
- NSString *jsonBackgroud = [NSString stringWithFormat: @"%@%@%@%@%@%@%@", @"{\"batches\": \"", @"0", @"\", \"message\": \"", @"Expiration fired. Finished OK.", @"\", \"date\": \"", timeStampStr, @"\"}"];
+ NSString *jsonBackgroud = [NSString stringWithFormat: @"%@%@%@%@%@%@%@%@%@", @"{\"batches\": \"", @"0", @"\", \"message\": \"", @"Expiration fired. Finished OK.", @"\", \"date\": \"", timeStampStrStart, @"\", \"dateEnd\": \"", timeStampStr, @"\"}"];
[rpcmodule saveBackgroundFile:jsonBackgroud];
- NSLog(@"BGTask startBackgroundTask - expirationHandler Save background JSON");
+ NSLog(@"BGTask startBackgroundTask - expirationHandler Save background JSON %@", jsonBackgroud);
[bgTask setTaskCompletedWithSuccess:NO];
bgTask = nil;
@@ -432,16 +397,11 @@ - (void)scheduleBackgroundTask {
earlyMorningComponent.hour = 3;
earlyMorningComponent.minute = arc4random_uniform(61);
NSDate *earlyMorning = [[NSCalendar currentCalendar] dateByAddingComponents:earlyMorningComponent toDate:tomorrow options:0];
-
- // DEVELOPMENT
- //NSDate *now = [NSDate date];
-
- //NSDate *twoMinutesLater = [now dateByAddingTimeInterval:120]; // 2 minutes = 120 seconds
NSLog(@"BGTask scheduleBackgroundTask date calculated: %@", earlyMorning);
request.earliestBeginDate = earlyMorning;
- //request.earliestBeginDate = twoMinutesLater;
+ // zancas requeriment, not plug-in, reverted.
request.requiresExternalPower = YES;
request.requiresNetworkConnectivity = YES;
@@ -469,14 +429,8 @@ - (void)scheduleSchedulerBackgroundTask {
afternoonComponent.hour = 14;
afternoonComponent.minute = arc4random_uniform(61);
NSDate *afternoon = [[NSCalendar currentCalendar] dateByAddingComponents:afternoonComponent toDate:tomorrow options:0];
-
- // DEVELOPMENT
- //NSDate *now = [NSDate date];
-
- //NSDate *fiveMinutesLater = [now dateByAddingTimeInterval:300]; // 5 minutes = 300 seconds
request.earliestBeginDate = afternoon;
- //request.earliestBeginDate = fiveMinutesLater;
request.requiresExternalPower = NO;
request.requiresNetworkConnectivity = NO;
diff --git a/package.json b/package.json
index d1004c2da..a064eec1c 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,8 @@
"lint": "eslint . --fix --ext .js,.jsx,.ts,.tsx",
"coverage": "jest --coverage",
"postinstall": "patch-package",
- "build:bundle": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res && rimraf --glob android/app/src/main/res/drawable* && cd android && ./gradlew assembleRelease -PsplitApk=true && cd .."
+ "build:bundle": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res && rimraf --glob android/app/src/main/res/drawable* && cd android && ./gradlew assembleRelease -PsplitApk=true && cd ..",
+ "bundle": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res && rimraf --glob android/app/src/main/res/drawable*"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.2.0",