diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 29fb061..97989d1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -21,14 +21,15 @@
+
+
+
+
-
-
-
\ No newline at end of file
diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/ConnectedActivity.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/ConnectedActivity.kt
index 5df194e..76f3564 100644
--- a/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/ConnectedActivity.kt
+++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/ConnectedActivity.kt
@@ -72,13 +72,13 @@ abstract class ConnectedActivity : AppCompatActivity(), ServiceConnection {
Toast.LENGTH_LONG
).show()
}
-// } else if (message is ConnectionStatusUpdate) {
-// handleConnectionStatusUpdate(message)
-// if (message.updateCode == ConnectionStatusUpdate.DISCONNECTED) {
+ } else if (message is ConnectionStatusUpdate) {
+ handleConnectionStatusUpdate(message)
+ if (message.updateCode == ConnectionStatusUpdate.DISCONNECTED) {
// recurrentAccountUpdateId = -1
// accountOpRequestId = -1
// isProcessingTx = false
-// }
+ }
}
}
}
diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/DatabaseLoadActivity.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/DatabaseLoadActivity.kt
new file mode 100644
index 0000000..47328c5
--- /dev/null
+++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/DatabaseLoadActivity.kt
@@ -0,0 +1,181 @@
+package cy.agorise.bitsybitshareswallet.activities
+
+import android.content.ComponentName
+import android.content.Intent
+import android.os.Bundle
+import android.os.CountDownTimer
+import android.os.Handler
+import android.os.IBinder
+import android.preference.PreferenceManager
+import android.util.Log
+import android.view.View
+import cy.agorise.bitsybitshareswallet.R
+import cy.agorise.bitsybitshareswallet.repositories.AssetRepository
+import cy.agorise.bitsybitshareswallet.utils.Constants
+import cy.agorise.graphenej.Asset
+import cy.agorise.graphenej.api.ApiAccess
+import cy.agorise.graphenej.api.ConnectionStatusUpdate
+import cy.agorise.graphenej.api.calls.ListAssets
+import cy.agorise.graphenej.models.JsonRpcResponse
+import kotlinx.android.synthetic.main.activity_database_load.*
+
+class DatabaseLoadActivity: ConnectedActivity() {
+ private val TAG = "DatabaseLoadActivity"
+
+ /** Time in milliseconds to wait before re-trying to access the full node */
+ private val NETWORK_RETRY_PERIOD: Long = 1000
+
+ /** Handler instance used to schedule tasks back to the main thread */
+ private var mHandler: Handler? = null
+
+ /** Timer used to avoid multiple instances of the following activity */
+ private var countDownTimer: CountDownTimer? = null
+
+ /** Repository used as the single point of truth for Assets */
+ private var mAssetRepository: AssetRepository? = null
+
+ // Variable used to keep track of the last lower bound used int asset batch loading
+ private var lastLowerBound: String? = null
+
+ // Variable used to keep track of the possession state of the database api id
+ private var hasDatabaseApiId: Boolean = false
+
+ // Variable used to count the number of assets already loaded
+ private var loadedAssetsCounter: Int = 0
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_database_load)
+
+ mHandler = Handler()
+
+ mAssetRepository = AssetRepository(application)
+
+ btnNext.setOnClickListener { onNext() }
+ }
+ override fun handleJsonRpcResponse(response: JsonRpcResponse<*>) {
+ if (response.result is List<*> &&
+ (response.result as List<*>).size > 0 &&
+ (response.result as List<*>)[0] is Asset) {
+ handlePlatformAssetBatch(response.result as List)
+ }
+ }
+
+ override fun handleConnectionStatusUpdate(connectionStatusUpdate: ConnectionStatusUpdate) {
+ if (connectionStatusUpdate.updateCode == ConnectionStatusUpdate.API_UPDATE &&
+ connectionStatusUpdate.api and ApiAccess.API_DATABASE == ApiAccess.API_DATABASE) {
+ hasDatabaseApiId = true
+ this.lastLowerBound = ""
+ sendAssetBatchRequest()
+ }
+ }
+
+ /**
+ * Method that issues a request for the next 100 known assets, starting from the last known
+ * lower bound for the asset symbol.
+ */
+ private fun sendAssetBatchRequest() {
+ if (mNetworkService != null && mNetworkService!!.isConnected) {
+ mNetworkService!!.sendMessage(ListAssets(lastLowerBound, ListAssets.LIST_ALL), ListAssets.REQUIRED_API)
+ } else {
+ Handler().postDelayed({ sendAssetBatchRequest() }, NETWORK_RETRY_PERIOD)
+ }
+ }
+
+ /**
+ * Method that loads a new batch of platform assets into the database and decides whether to finish
+ * the procedure or to keep requesting for more assets.
+ *
+ * @param assetList The list of assets obtained in the last 'list_assets' API call.
+ */
+ private fun handlePlatformAssetBatch(assetList: List) {
+ val assets = mutableListOf()
+
+ // TODO find if there is a better way to convert to Bitsy Asset instances
+ for (_asset in assetList) {
+ val asset = cy.agorise.bitsybitshareswallet.models.Asset(
+ _asset.objectId,
+ _asset.symbol,
+ _asset.precision,
+ _asset.description ?: "",
+ _asset.bitassetId ?: ""
+ )
+
+ assets.add(asset)
+ }
+
+ mAssetRepository!!.insertAll(assets)
+
+ loadedAssetsCounter += assetList.size
+
+ tvLoadMessage.text = getString(R.string.text__loading_assets, loadedAssetsCounter)
+
+ if (assetList.size < ListAssets.MAX_BATCH_SIZE) {
+ // We might have reached the end of the asset list
+ Log.d(TAG, "We might have reached the end!")
+
+ // Storing the last asset update time and setting the database as loaded
+ PreferenceManager.getDefaultSharedPreferences(applicationContext)
+ .edit()
+ .putLong(Constants.KEY_LAST_ASSET_LIST_UPDATE, System.currentTimeMillis())
+ .apply()
+
+ onAssetsReady()
+ } else {
+ // Using the last asset symbol in the list as the new lower bound.
+ lastLowerBound = assetList[assetList.size - 1].symbol
+ sendAssetBatchRequest()
+ }
+ }
+
+ private fun onAssetsReady() {
+ // Storing the last asset update time and setting the database as loaded
+ PreferenceManager.getDefaultSharedPreferences(applicationContext)
+ .edit()
+ .putBoolean(Constants.KEY_DATABASE_LOADED, true)
+ .apply()
+
+
+ mHandler!!.post {
+ progressBar.visibility = View.INVISIBLE
+ btnNext.isEnabled = true
+ tvLoadTitle.setText(R.string.title__assets_loaded)
+ tvLoadMessage.setText(R.string.text__assets_loaded)
+
+ // Timer to automatically take user to the next activity
+ countDownTimer = object : CountDownTimer(5000, 1000) {
+
+ override fun onTick(millisUntilFinished: Long) {}
+
+ override fun onFinish() {
+ onNext()
+ }
+ }.start()
+ }
+ }
+
+ /**
+ * Called whenever the user clicks on the 'next' button_light. This button_light will only be visible when
+ * the database loading procedure is done, OR if there was an error in it.
+ */
+ fun onNext() {
+ // Cancel timer to avoid starting InitialSetupActivity twice
+ countDownTimer!!.cancel()
+
+ val intent = Intent(applicationContext, ImportBrainkeyActivity::class.java)
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ startActivity(intent)
+// overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left)
+ finish()
+ }
+
+ override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
+ super.onServiceConnected(name, service)
+
+ hasDatabaseApiId = mNetworkService!!.hasApiId(ApiAccess.API_DATABASE)
+ if (hasDatabaseApiId) {
+ this.lastLowerBound = ""
+ sendAssetBatchRequest()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/LicenseActivity.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/LicenseActivity.kt
index 71807fa..e47d03e 100644
--- a/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/LicenseActivity.kt
+++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/LicenseActivity.kt
@@ -32,7 +32,8 @@ class LicenseActivity : AppCompatActivity() {
/**
* This function stores the version of the current accepted license version into the Shared Preferences and
- * sends the user to either import/create account if there is no active account or to the MainActivity otherwise
+ * sends the user to load the assets database if they have not been loaded, import/create account if there is no
+ * active account or to the MainActivity otherwise.
*/
private fun agree() {
PreferenceManager.getDefaultSharedPreferences(this).edit()
@@ -40,13 +41,19 @@ class LicenseActivity : AppCompatActivity() {
val intent : Intent?
+ val isDatabaseLoaded = PreferenceManager.getDefaultSharedPreferences(this)
+ .getBoolean(Constants.KEY_DATABASE_LOADED, false)
+
val initialSetupDone = PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(Constants.KEY_INITIAL_SETUP_DONE, false)
- intent = if (initialSetupDone)
- Intent(this, MainActivity::class.java)
- else
+ intent = if (!isDatabaseLoaded)
+ Intent(this, DatabaseLoadActivity::class.java)
+ else if (!initialSetupDone)
Intent(this, ImportBrainkeyActivity::class.java)
+ else
+ Intent(this, MainActivity::class.java)
+
startActivity(intent)
finish()
diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/daos/AssetDao.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/daos/AssetDao.kt
index 5083f19..2a343a3 100644
--- a/app/src/main/java/cy/agorise/bitsybitshareswallet/daos/AssetDao.kt
+++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/daos/AssetDao.kt
@@ -3,6 +3,7 @@ package cy.agorise.bitsybitshareswallet.daos
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
+import androidx.room.OnConflictStrategy
import androidx.room.Query
import cy.agorise.bitsybitshareswallet.models.Asset
@@ -11,6 +12,9 @@ interface AssetDao {
@Insert
fun insert(asset: Asset)
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ fun insertAll(assets: List)
+
@Query("SELECT * FROM assets")
fun getAllAssets(): LiveData>
}
diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/AssetRepository.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/AssetRepository.kt
new file mode 100644
index 0000000..9830f2a
--- /dev/null
+++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/AssetRepository.kt
@@ -0,0 +1,30 @@
+package cy.agorise.bitsybitshareswallet.repositories
+
+import android.app.Application
+import android.os.AsyncTask
+import cy.agorise.bitsybitshareswallet.daos.AssetDao
+import cy.agorise.bitsybitshareswallet.daos.BitsyDatabase
+import cy.agorise.bitsybitshareswallet.models.Asset
+
+class AssetRepository internal constructor(application: Application) {
+
+ private val mAssetDao: AssetDao
+
+ init {
+ val db = BitsyDatabase.getDatabase(application)
+ mAssetDao = db!!.assetDao()
+ }
+
+ fun insertAll(assets: List) {
+ insertAllAsyncTask(mAssetDao).execute(assets)
+ }
+
+ private class insertAllAsyncTask internal constructor(private val mAsyncTaskDao: AssetDao) :
+ AsyncTask, Void, Void>() {
+
+ override fun doInBackground(vararg assets: List): Void? {
+ mAsyncTaskDao.insertAll(assets[0])
+ return null
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/Constants.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/Constants.kt
index 36fd11a..3bc277b 100644
--- a/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/Constants.kt
+++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/Constants.kt
@@ -9,6 +9,18 @@ object Constants {
/** Version of the currently used license */
const val CURRENT_LICENSE_VERSION = 1
+ /** Key used to store if the assets database has been loaded or not */
+ const val KEY_DATABASE_LOADED = "key_database_loaded"
+
+ /**
+ * Key used to store a preference value used to keep track of the last time the assets in
+ * database were updated.
+ */
+ const val KEY_LAST_ASSET_LIST_UPDATE = "key_last_assets_update"
+
+ /** Key used to store if the initial setup is already done or not */
+ const val KEY_INITIAL_SETUP_DONE = "key_initial_setup_done"
+
/** Key used to store the id value of the currently active account in the shared preferences */
const val KEY_CURRENT_ACCOUNT_ID = "key_current_account_id"
@@ -24,9 +36,6 @@ object Constants {
*/
const val LIFETIME_EXPIRATION_DATE = "1969-12-31T23:59:59"
- /** Key used to store if the initial setup is already done or not */
- const val KEY_INITIAL_SETUP_DONE = "key_initial_setup_done"
-
/** Key used to store the night mode setting into the shared preferences */
const val KEY_NIGHT_MODE_ACTIVATED = "key_night_mode_activated"
}
diff --git a/app/src/main/res/layout/activity_database_load.xml b/app/src/main/res/layout/activity_database_load.xml
new file mode 100644
index 0000000..a9bc4f2
--- /dev/null
+++ b/app/src/main/res/layout/activity_database_load.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 808684c..934cc19 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -12,4 +12,7 @@
24dp
40dp
+
+ 180dp
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3c5c341..18cbd24 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -7,6 +7,14 @@
Agree
Disagree
+
+ Loading Assets…
+ Performing a series of requests in order to get the complete list of all existing assets
+ Loaded %1$d assets into the database
+ Assets Loaded
+ Next, please setup your account…
+ Next
+
6+ digits PIN
PIN too short
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index e883885..dcc2016 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -42,6 +42,7 @@
+