You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

401 lines
15 KiB

// Copyright 2019-2020 The Hush developers
// Released under the GPLv3
package org.myhush.silentdragon
import android.annotation.SuppressLint
import android.app.Activity
import android.app.AlertDialog
import android.content.*
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.StrictMode
import androidx.constraintlayout.widget.ConstraintLayout
import com.google.android.material.snackbar.Snackbar
import androidx.core.text.HtmlCompat
import androidx.appcompat.app.AppCompatActivity
import android.text.Html
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.Button
import android.widget.ScrollView
import android.widget.TextView
import android.widget.Toast
import com.beust.klaxon.Klaxon
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.content_main.*
import org.myhush.silentdragon.DataModel.ConnectionStatus
import org.myhush.silentdragon.DataModel.connStatus
import java.text.DecimalFormat
class MainActivity : AppCompatActivity(),
TransactionItemFragment.OnFragmentInteractionListener,
UnconfirmedTxItemFragment.OnFragmentInteractionListener {
override fun onFragmentInteraction(uri: Uri) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onCreate(savedInstanceState: Bundle?) {
//StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()) // TESTING
super.onCreate(savedInstanceState)
title = getString(R.string.app_name)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
// When creating, clear all the data first
setMainStatus("")
DataModel.init()
btnConnect.setOnClickListener {
val intent = Intent(this, QrReaderActivity::class.java)
intent.putExtra("REQUEST_CODE",
QrReaderActivity.REQUEST_CONNDATA
)
startActivityForResult(intent,
QrReaderActivity.REQUEST_CONNDATA
)
}
btnReconnect.setOnClickListener {
ConnectionManager.refreshAllData()
}
btnHelp.setOnClickListener {
val dialogBuilder = AlertDialog.Builder(this)
dialogBuilder.setMessage(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) Html.fromHtml(resources.getString(R.string.help_text), HtmlCompat.FROM_HTML_MODE_LEGACY) else Html.fromHtml(resources.getString(R.string.help_text)))
.setNegativeButton(resources.getString(R.string.ok), DialogInterface.OnClickListener {
dialog, id -> dialog.cancel()
})
val alert = dialogBuilder.create()
alert.setTitle(resources.getString(R.string.help))
alert.show()
}
swiperefresh.setOnRefreshListener {
ConnectionManager.refreshAllData()
}
txtMainBalanceUSD.setOnClickListener {
if(DataModel.selectedCurrency == "BTC")
Toast.makeText(applicationContext, "1 HUSH = ${DataModel.currencySymbols[DataModel.selectedCurrency]}${DecimalFormat(" #,##0.00000000")
.format(DataModel.currencyValues[DataModel.selectedCurrency])}", Toast.LENGTH_LONG).show()
else(
Toast.makeText(applicationContext, "1 HUSH = ${DataModel.currencySymbols[DataModel.selectedCurrency]}${DecimalFormat("#,##0.00")
.format(DataModel.currencyValues[DataModel.selectedCurrency])}", Toast.LENGTH_LONG).show()
)
}
bottomNav.setOnNavigationItemSelectedListener {
when(it.itemId) {
R.id.action_send -> {
val intent = Intent(this, SendActivity::class.java)
startActivity(intent)
return@setOnNavigationItemSelectedListener true
}
R.id.action_bal -> true
R.id.action_recieve -> {
val intent = Intent(this, ReceiveActivity::class.java)
startActivity(intent)
return@setOnNavigationItemSelectedListener true
}
else -> {
return@setOnNavigationItemSelectedListener false
}
}
}
loadSharedPref()
updateUI(false)
}
private fun loadSharedPref() {
var ref: SharedPreferences = getSharedPreferences("MainFile", 0)
DataModel.selectedCurrency = ref.getString("currency", "BTC").toString()
}
private fun setMainStatus(status: String) {
lblBalance.text = ""
txtMainBalanceUSD.text = ""
txtMainBalance.text = status
}
@SuppressLint("SetTextI18n")
private fun updateUI(updateTxns: Boolean) {
runOnUiThread {
Log.i(TAG, "Updating UI $updateTxns")
bottomNav.itemIconTintList = null
bottomNav.menu.findItem(R.id.action_bal)?.isChecked = true
when (connStatus) {
ConnectionStatus.DISCONNECTED -> {
setMainStatus(resources.getString(R.string.no_connection))
scrollViewTxns.visibility = ScrollView.GONE
layoutConnect.visibility = ConstraintLayout.VISIBLE
swiperefresh.isRefreshing = false
// Hide the reconnect button if there is no connection string
if (DataModel.getConnString(SilentDragonApp.appContext!!).isNullOrBlank() ||
DataModel.getSecret() == null) {
btnHelp.visibility = Button.VISIBLE
btnReconnect.visibility = Button.GONE
lblConnectionOr.visibility = TextView.GONE
} else {
btnHelp.visibility = Button.GONE
btnReconnect.visibility = Button.VISIBLE
lblConnectionOr.visibility = TextView.VISIBLE
}
// Disable the send and recieve buttons
bottomNav.menu.findItem(R.id.action_recieve).isEnabled = false
bottomNav.menu.findItem(R.id.action_send).isEnabled = false
if (updateTxns) {
Handler().post {
run {
addPastTransactions(DataModel.transactions)
}
}
}
}
ConnectionStatus.CONNECTING -> {
setMainStatus(resources.getString(R.string.connecting))
scrollViewTxns.visibility = ScrollView.GONE
layoutConnect.visibility = ConstraintLayout.GONE
swiperefresh.isRefreshing = true
// Disable the send and recieve buttons
bottomNav.menu.findItem(R.id.action_recieve).isEnabled = false
bottomNav.menu.findItem(R.id.action_send).isEnabled = false
}
ConnectionStatus.CONNECTED -> {
scrollViewTxns.visibility = ScrollView.VISIBLE
layoutConnect.visibility = ConstraintLayout.GONE
ConnectionManager.initCurrencies()
if (DataModel.mainResponseData == null) {
setMainStatus(resources.getString(R.string.loading))
} else {
val cur = DataModel.selectedCurrency
val price = DataModel.currencyValues[cur]?: 0.0
val bal = DataModel.mainResponseData?.balance ?: 0.0
val balText = DecimalFormat("#0.00000000").format(bal)
lblBalance.text = resources.getString(R.string.balance)
txtMainBalance.text = balText + " ${DataModel.mainResponseData?.tokenName} "
if(cur == "BTC")
txtMainBalanceUSD.text = "${DataModel.currencySymbols[cur]} " + DecimalFormat("0.00000000").format(bal * price)
else
txtMainBalanceUSD.text = "${DataModel.currencySymbols[cur]} " + DecimalFormat("#,##0.00").format(bal * price)
// Enable the send and recieve buttons
bottomNav.menu.findItem(R.id.action_recieve).isEnabled = true
bottomNav.menu.findItem(R.id.action_send).isEnabled = true
}
if (updateTxns) {
Handler().post {
run {
addPastTransactions(DataModel.transactions)
}
}
} else {
swiperefresh.isRefreshing = false
}
}
}
}
}
private fun addPastTransactions(txns: List<DataModel.TransactionItem>?) {
runOnUiThread {
val fragTx = supportFragmentManager.beginTransaction()
for (fr in supportFragmentManager.fragments) {
fragTx.remove(fr)
}
// If there are no transactions, make sure to commit the Tx, so existing items are removed, and just return
if (txns.isNullOrEmpty()) {
fragTx.commitAllowingStateLoss()
swiperefresh.isRefreshing = false
return@runOnUiThread
}
// Split all the transactions into confirmations = 0 and confirmations > 0
// Unconfirmed first
val unconfirmed = txns.filter { t -> t.confirmations == 0L }
if (unconfirmed.isNotEmpty()) {
for (tx in unconfirmed) {
fragTx.add(
txList.id ,
UnconfirmedTxItemFragment.newInstance(
Klaxon().toJsonString(tx),
""
),
"tag1"
)
}
}
// Add all confirmed transactions
val confirmed = txns.filter { t -> t.confirmations > 0L }
if (confirmed.isNotEmpty()) {
var oddeven = "odd"
for (tx in confirmed) {
fragTx.add(
txList.id,
TransactionItemFragment.newInstance(
Klaxon().toJsonString(tx),
oddeven
),
"tag1"
)
oddeven = if (oddeven == "odd") "even" else "odd"
}
}
fragTx.commitAllowingStateLoss()
swiperefresh.isRefreshing = false
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_settings -> {
val intent = Intent(this, SettingsActivity::class.java)
startActivity(intent)
return true
}
R.id.action_about -> {
val intent = Intent(this, AboutActivity::class.java)
startActivity(intent)
return true
}
R.id.action_refresh -> {
swiperefresh.isRefreshing = true
ConnectionManager.refreshAllData()
return true
}
else -> super.onOptionsItemSelected(item)
}
}
var mReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// We've received a signal
when(intent.getStringExtra("action")) {
"refresh" -> {
swiperefresh.isRefreshing = !intent.getBooleanExtra("finished", true)
}
"newdata" -> {
val updateTxns = intent.getBooleanExtra("updateTxns", false)
updateUI(updateTxns)
}
"error" -> {
val msg = intent.getStringExtra("msg")
if (!msg.isNullOrEmpty()) {
Snackbar.make(layoutConnect, msg, Snackbar.LENGTH_LONG).show()
}
// Also check if we need to disconnect
if (intent.getBooleanExtra("doDisconnect", false)) {
disconnected()
}
}
}
}
}
override fun onResume() {
super.onResume()
registerReceiver(mReceiver, IntentFilter(ConnectionManager.DATA_SIGNAL))
// On resuming, refresh all data
ConnectionManager.refreshAllData()
}
override fun onDestroy() {
unregisterReceiver(mReceiver)
super.onDestroy()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when(requestCode) {
QrReaderActivity.REQUEST_CONNDATA -> {
if (resultCode == Activity.RESULT_OK) {
Log.i(TAG, "Main Activity got result for QrCode: ${data?.dataString}")
// Check to make sure that the result is an actual address
if (!(data?.dataString ?: "").startsWith("ws")) {
Toast.makeText(applicationContext,
getString(R.string.is_not_a_valid_connection_string, data?.dataString), Toast.LENGTH_SHORT).show()
return
}
val conComponents = data?.dataString?.split(",")
if (conComponents?.size ?: 0 < 2 || conComponents?.size ?: 0 > 3) {
Toast.makeText(applicationContext,
getString(R.string.is_not_a_valid_connection_string, data?.dataString), Toast.LENGTH_SHORT).show()
return
}
val conString = conComponents!![0]
val secretHex = conComponents[1]
val allowInternetConnections = if (conComponents.size == 3) conComponents[2] == "1" else false
DataModel.setSecretHex(secretHex)
DataModel.setConnString(
conString,
applicationContext
)
DataModel.setAllowInternet(
allowInternetConnections
)
ConnectionManager.refreshAllData()
}
}
}
}
private fun disconnected() {
Log.i(TAG, "Disconnected")
connStatus = ConnectionStatus.DISCONNECTED
println("Connstatus = Disconnected")
DataModel.clear()
swiperefresh.isRefreshing = false
updateUI(true)
}
private val TAG = "MainActivity"
}