- Update the MaterialDialogs library version.
- Add the functionality to the Settings BrainKey's View & Show button. It first fetches the brainkey from the authorities db table and then shows it in a custom MaterialDialog so that the user can view and copy it.
This commit is contained in:
parent
f45d9055c3
commit
8f0026c205
8 changed files with 112 additions and 4 deletions
|
@ -59,7 +59,7 @@ dependencies {
|
||||||
implementation 'com.moldedbits.r2d2:r2d2:1.0.1'
|
implementation 'com.moldedbits.r2d2:r2d2:1.0.1'
|
||||||
implementation 'com.google.zxing:core:3.3.1'
|
implementation 'com.google.zxing:core:3.3.1'
|
||||||
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
||||||
implementation 'com.afollestad.material-dialogs:core:2.0.0-rc1'
|
implementation 'com.afollestad.material-dialogs:core:2.0.0-rc3'
|
||||||
|
|
||||||
// Android Debug Database
|
// Android Debug Database
|
||||||
debugImplementation 'com.amitshekhar.android:debug-db:1.0.4'
|
debugImplementation 'com.amitshekhar.android:debug-db:1.0.4'
|
||||||
|
|
|
@ -39,14 +39,19 @@ class MainActivity : ConnectedActivity() {
|
||||||
val host: NavHostFragment = supportFragmentManager
|
val host: NavHostFragment = supportFragmentManager
|
||||||
.findFragmentById(R.id.navHostFragment) as NavHostFragment? ?: return
|
.findFragmentById(R.id.navHostFragment) as NavHostFragment? ?: return
|
||||||
|
|
||||||
// Set up Action Bar
|
// Set up Action Bar with Navigation's controller
|
||||||
val navController = host.navController
|
val navController = host.navController
|
||||||
|
|
||||||
appBarConfiguration = AppBarConfiguration(navController.graph)
|
appBarConfiguration = AppBarConfiguration(navController.graph)
|
||||||
|
|
||||||
|
// Sets up the ActionBar with the navigation controller so that it automatically responds to clicks on toolbar
|
||||||
|
// menu items and shows the up navigation button on all fragments except home (Balances)
|
||||||
setupActionBarWithNavController(navController, appBarConfiguration)
|
setupActionBarWithNavController(navController, appBarConfiguration)
|
||||||
|
|
||||||
mHandler = Handler()
|
mHandler = Handler()
|
||||||
|
|
||||||
|
// When this runnable finishes it first verifies if the auto close feature is enabled and if it is then it
|
||||||
|
// closes the app, if not then it just restarts the Handler (timer)
|
||||||
mRunnable = Runnable {
|
mRunnable = Runnable {
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(this)
|
if (PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
.getBoolean(Constants.KEY_AUTO_CLOSE_ACTIVATED, false))
|
.getBoolean(Constants.KEY_AUTO_CLOSE_ACTIVATED, false))
|
||||||
|
@ -57,11 +62,17 @@ class MainActivity : ConnectedActivity() {
|
||||||
startHandler()
|
startHandler()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restarts the Handler (timer) each time there is user's interaction
|
||||||
|
*/
|
||||||
override fun onUserInteraction() {
|
override fun onUserInteraction() {
|
||||||
super.onUserInteraction()
|
super.onUserInteraction()
|
||||||
restartHandler()
|
restartHandler()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops and then restarts the Handler
|
||||||
|
*/
|
||||||
private fun restartHandler() {
|
private fun restartHandler() {
|
||||||
stopHandler()
|
stopHandler()
|
||||||
startHandler()
|
startHandler()
|
||||||
|
|
|
@ -12,6 +12,9 @@ interface AuthorityDao {
|
||||||
@Insert
|
@Insert
|
||||||
fun insert(authority: Authority)
|
fun insert(authority: Authority)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM authorities WHERE user_id=:userId LIMIT 1")
|
||||||
|
fun get(userId: String): Single<Authority>
|
||||||
|
|
||||||
@Query("SELECT * FROM authorities")
|
@Query("SELECT * FROM authorities")
|
||||||
fun getAll(): LiveData<List<Authority>>
|
fun getAll(): LiveData<List<Authority>>
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,31 @@
|
||||||
package cy.agorise.bitsybitshareswallet.fragments
|
package cy.agorise.bitsybitshareswallet.fragments
|
||||||
|
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context.CLIPBOARD_SERVICE
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.preference.PreferenceManager
|
import android.preference.PreferenceManager
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import com.afollestad.materialdialogs.customview.customView
|
||||||
import cy.agorise.bitsybitshareswallet.R
|
import cy.agorise.bitsybitshareswallet.R
|
||||||
|
import cy.agorise.bitsybitshareswallet.repositories.AuthorityRepository
|
||||||
import cy.agorise.bitsybitshareswallet.utils.Constants
|
import cy.agorise.bitsybitshareswallet.utils.Constants
|
||||||
|
import cy.agorise.bitsybitshareswallet.utils.CryptoUtils
|
||||||
|
import cy.agorise.graphenej.BrainKey
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
import kotlinx.android.synthetic.main.fragment_settings.*
|
import kotlinx.android.synthetic.main.fragment_settings.*
|
||||||
|
|
||||||
class SettingsFragment : Fragment() {
|
class SettingsFragment : Fragment() {
|
||||||
|
private val TAG = this.javaClass.simpleName
|
||||||
|
|
||||||
|
private var mDisposables = CompositeDisposable()
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
@ -28,8 +42,14 @@ class SettingsFragment : Fragment() {
|
||||||
initAutoCloseSwitch()
|
initAutoCloseSwitch()
|
||||||
|
|
||||||
initNightModeSwitch()
|
initNightModeSwitch()
|
||||||
|
|
||||||
|
btnViewBrainKey.setOnClickListener { getBrainkey(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the relevant preference from the SharedPreferences and configures the corresponding switch accordingly,
|
||||||
|
* and adds a listener to the said switch to store the preference in case the user changes it.
|
||||||
|
*/
|
||||||
private fun initAutoCloseSwitch() {
|
private fun initAutoCloseSwitch() {
|
||||||
val autoCloseOn = PreferenceManager.getDefaultSharedPreferences(context)
|
val autoCloseOn = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
.getBoolean(Constants.KEY_AUTO_CLOSE_ACTIVATED, false)
|
.getBoolean(Constants.KEY_AUTO_CLOSE_ACTIVATED, false)
|
||||||
|
@ -42,6 +62,11 @@ class SettingsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the relevant preference from the SharedPreferences and configures the corresponding switch accordingly,
|
||||||
|
* and adds a listener to the said switch to store the preference in case the user changes it. Also makes a call to
|
||||||
|
* recreate the activity and apply the selected theme.
|
||||||
|
*/
|
||||||
private fun initNightModeSwitch() {
|
private fun initNightModeSwitch() {
|
||||||
val nightModeOn = PreferenceManager.getDefaultSharedPreferences(context)
|
val nightModeOn = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
.getBoolean(Constants.KEY_NIGHT_MODE_ACTIVATED, false)
|
.getBoolean(Constants.KEY_NIGHT_MODE_ACTIVATED, false)
|
||||||
|
@ -57,5 +82,55 @@ class SettingsFragment : Fragment() {
|
||||||
activity?.recreate()
|
activity?.recreate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the brainKey from the authorities db table for the current user account and if it is not null it passes
|
||||||
|
* the brainKey to a method to show it in a nice MaterialDialog
|
||||||
|
*/
|
||||||
|
private fun getBrainkey(view: View) {
|
||||||
|
val userId = PreferenceManager.getDefaultSharedPreferences(view.context)
|
||||||
|
.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "") ?: ""
|
||||||
|
|
||||||
|
val authorityRepository = AuthorityRepository(view.context)
|
||||||
|
|
||||||
|
mDisposables.add(authorityRepository.get(userId)
|
||||||
|
.subscribeOn(Schedulers.computation())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe { authority ->
|
||||||
|
if (authority != null) {
|
||||||
|
val plainBrainKey = CryptoUtils.decrypt(view.context, authority.encryptedBrainKey)
|
||||||
|
val plainSequenceNumber = CryptoUtils.decrypt(view.context, authority.encryptedSequenceNumber)
|
||||||
|
val sequenceNumber = Integer.parseInt(plainSequenceNumber)
|
||||||
|
val brainKey = BrainKey(plainBrainKey, sequenceNumber)
|
||||||
|
showBrainKeyDialog(view, brainKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the plain brainkey in a dialog so that the user can view and Copy it.
|
||||||
|
*/
|
||||||
|
private fun showBrainKeyDialog(view: View, brainKey: BrainKey) {
|
||||||
|
MaterialDialog(view.context).show {
|
||||||
|
title(text = "BrainKey")
|
||||||
|
message(text = brainKey.brainKey)
|
||||||
|
customView(R.layout.dialog_copy_brainkey)
|
||||||
|
cancelable(false)
|
||||||
|
positiveButton(android.R.string.copy) {
|
||||||
|
Toast.makeText(it.context, "Copied to clipboard", Toast.LENGTH_SHORT).show()
|
||||||
|
val clipboard = it.context.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
|
val clip = ClipData.newPlainText("label", brainKey.brainKey)
|
||||||
|
clipboard.primaryClip = clip
|
||||||
|
it.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
|
||||||
|
if (!mDisposables.isDisposed) mDisposables.dispose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,8 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
|
||||||
Log.e(TAG, "AEADBadTagException. Class: " + e.javaClass + ", Msg: " + e.message)
|
Log.e(TAG, "AEADBadTagException. Class: " + e.javaClass + ", Msg: " + e.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
}
|
||||||
|
)
|
||||||
mDisposables.add(RxBus.getBusInstance()
|
mDisposables.add(RxBus.getBusInstance()
|
||||||
.asFlowable()
|
.asFlowable()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
@ -145,7 +146,8 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
|
||||||
responseMap.clear()
|
responseMap.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
// If there is no current user, we should not do anything
|
// If there is no current user, we should not do anything
|
||||||
mState = State.CANCELLED
|
mState = State.CANCELLED
|
||||||
|
|
|
@ -20,6 +20,10 @@ class AuthorityRepository internal constructor(context: Context) {
|
||||||
insertAsyncTask(mAuthorityDao).execute(authority)
|
insertAsyncTask(mAuthorityDao).execute(authority)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun get(userId: String): Single<Authority> {
|
||||||
|
return mAuthorityDao.get(userId)
|
||||||
|
}
|
||||||
|
|
||||||
fun getWIF(userId: String, authorityType: Int): Single<String> {
|
fun getWIF(userId: String, authorityType: Int): Single<String> {
|
||||||
return mAuthorityDao.getWIF(userId, authorityType)
|
return mAuthorityDao.getWIF(userId, authorityType)
|
||||||
}
|
}
|
||||||
|
|
11
app/src/main/res/layout/dialog_copy_brainkey.xml
Normal file
11
app/src/main/res/layout/dialog_copy_brainkey.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/msg__brainkey_info"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingStart="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingEnd="@dimen/activity_horizontal_margin"/>
|
|
@ -66,6 +66,8 @@
|
||||||
<string name="msg__brainkey_description">BrainKey. Account recovery words that can be captured or copied, but not
|
<string name="msg__brainkey_description">BrainKey. Account recovery words that can be captured or copied, but not
|
||||||
edited.
|
edited.
|
||||||
</string>
|
</string>
|
||||||
|
<string name="msg__brainkey_info">Print this out, or write it down. Anyone with access to your recovery key will
|
||||||
|
have access to funds within this wallet.</string>
|
||||||
<string name="btn__view_and_copy"><![CDATA[View & Copy]]></string>
|
<string name="btn__view_and_copy"><![CDATA[View & Copy]]></string>
|
||||||
<string name="title__bugs_or_ideas">Bugs or Ideas?</string>
|
<string name="title__bugs_or_ideas">Bugs or Ideas?</string>
|
||||||
<string name="msg__bugs_or_ideas">Telegram chat: http://t.me/Agorise\nEmail: Agorise@protonmail.ch\nOpen Source:
|
<string name="msg__bugs_or_ideas">Telegram chat: http://t.me/Agorise\nEmail: Agorise@protonmail.ch\nOpen Source:
|
||||||
|
|
Loading…
Reference in a new issue