// 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.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 androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.text.HtmlCompat import com.beust.klaxon.Klaxon import com.google.android.material.snackbar.Snackbar 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 org.myhush.silentdragon.ui.AboutActivity import org.myhush.silentdragon.ui.SettingsActivity 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?) { 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" }