zircles-android/app/src/main/java/cash/z/ecc/android/ui/MainActivity.kt

226 lines
7.4 KiB
Kotlin

package cash.z.ecc.android.ui
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.graphics.Color
import android.media.MediaPlayer
import android.os.Bundle
import android.os.Vibrator
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.getSystemService
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController
import androidx.navigation.findNavController
import cash.z.ecc.android.R
import cash.z.ecc.android.ZcashWalletApp
import cash.z.ecc.android.di.component.MainActivitySubcomponent
import cash.z.ecc.android.di.viewmodel.viewModel
import cash.z.ecc.android.feedback.*
import cash.z.ecc.android.feedback.Report.NonUserAction.FEEDBACK_STOPPED
import cash.z.ecc.android.feedback.Report.NonUserAction.SYNC_START
import cash.z.ecc.android.ui.send.SendViewModel
import cash.z.wallet.sdk.Initializer
import cash.z.wallet.sdk.Synchronizer
import cash.z.wallet.sdk.ext.twig
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.launch
import javax.inject.Inject
class MainActivity : AppCompatActivity() {
private var syncInit: (() -> Unit)? = null
@Inject
lateinit var feedback: Feedback
@Inject
lateinit var feedbackCoordinator: FeedbackCoordinator
@Inject
lateinit var clipboard: ClipboardManager
val sendViewModel: SendViewModel by viewModel()
private val mediaPlayer: MediaPlayer = MediaPlayer()
private var snackbar: Snackbar? = null
lateinit var navController: NavController
lateinit var synchronizer: Synchronizer
lateinit var component: MainActivitySubcomponent
override fun onCreate(savedInstanceState: Bundle?) {
component = ZcashWalletApp.component.mainActivityComponent().create(this).also {
it.inject(this)
}
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
initNavigation()
window.statusBarColor = Color.TRANSPARENT
window.navigationBarColor = Color.TRANSPARENT
window.setFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
)
setWindowFlag(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, false)
setWindowFlag(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, false)
lifecycleScope.launch {
feedback.start()
}
}
override fun onResume() {
super.onResume()
// keep track of app launch metrics
// (how long does it take the app to open when it is not already in the foreground)
ZcashWalletApp.instance.let { app ->
if (!app.creationMeasured) {
app.creationMeasured = true
feedback.report(LaunchMetric())
}
}
}
override fun onDestroy() {
lifecycleScope.launch {
feedback.report(FEEDBACK_STOPPED)
feedback.stop()
}
super.onDestroy()
}
private fun setWindowFlag(bits: Int, on: Boolean) {
val win = window
val winParams = win.attributes
if (on) {
winParams.flags = winParams.flags or bits
} else {
winParams.flags = winParams.flags and bits.inv()
}
win.attributes = winParams
}
private fun initNavigation() {
navController = findNavController(R.id.nav_host_fragment)
navController.addOnDestinationChangedListener { _, _, _ ->
// hide the keyboard anytime we change destinations
getSystemService<InputMethodManager>()?.hideSoftInputFromWindow(
this@MainActivity.window.decorView.rootView.windowToken,
InputMethodManager.HIDE_NOT_ALWAYS
)
}
}
fun initSync() {
twig("Initializing synchronizer")
if (!::synchronizer.isInitialized) {
twig("Synchronizer didn't exist yet (this means we're opening an existing wallet). Creating it now.")
val initializer = Initializer(ZcashWalletApp.instance, "lightd-main.zecwallet.co", 443).also { it.open() }
synchronizer = Synchronizer(ZcashWalletApp.instance, initializer)
}
feedback.report(SYNC_START)
synchronizer.start(lifecycleScope)
if (syncInit != null) {
syncInit!!()
syncInit = null
}
}
fun initializeAccount(seed: ByteArray, birthday: Initializer.WalletBirthday? = null) {
twig("Initializing accounts")
feedback.measure(Report.MetricType.ACCOUNT_CREATED) {
synchronizer =
Synchronizer(ZcashWalletApp.instance, "lightd-main.zecwallet.co", 443, seed, birthday)
}
}
fun playSound(fileName: String) {
mediaPlayer.apply {
if (isPlaying) stop()
try {
reset()
assets.openFd(fileName).let { afd ->
setDataSource(afd.fileDescriptor, afd.startOffset, afd.length)
}
prepare()
start()
} catch (t: Throwable) {
Log.e("SDK_ERROR", "ERROR: unable to play sound due to $t")
}
}
}
// TODO: spruce this up with API 26 stuff
fun vibrateSuccess() {
val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
if (vibrator.hasVibrator()) {
vibrator.vibrate(longArrayOf(0, 200, 200, 100, 100, 800), -1)
}
}
fun copyAddress(view: View) {
lifecycleScope.launch {
clipboard.setPrimaryClip(
ClipData.newPlainText(
"Z-Address",
synchronizer.getAddress()
)
)
showMessage("Address copied!", "Sweet")
}
}
private fun showMessage(message: String, action: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
fun showSnackbar(message: String, action: String = "OK"): Snackbar {
return if (snackbar == null) {
val view = findViewById<View>(R.id.main_activity_container)
val snacks = Snackbar
.make(view, "$message", Snackbar.LENGTH_INDEFINITE)
.setAction(action) { /*auto-close*/ }
val snackBarView = snacks.view as ViewGroup
val navigationBarHeight = resources.getDimensionPixelSize(resources.getIdentifier("navigation_bar_height", "dimen", "android"))
val params = snackBarView.getChildAt(0).layoutParams as ViewGroup.MarginLayoutParams
params.setMargins(
params.leftMargin,
params.topMargin,
params.rightMargin,
navigationBarHeight
)
snackBarView.getChildAt(0).setLayoutParams(params)
snacks
} else {
snackbar!!.setText(message).setAction(action) {/*auto-close*/}
}.also {
if (!it.isShownOrQueued) it.show()
}
}
// TODO: refactor initialization and remove the need for this
fun onSyncInit(initBlock: () -> Unit) {
if (::synchronizer.isInitialized) {
initBlock()
} else {
syncInit = initBlock
}
}
}