Verified Commit 2aaa20a8 authored by Sarath's avatar Sarath
Browse files

Add transaction broadcast dialog

parent f4dd3dea
......@@ -80,7 +80,6 @@ dependencies {
def topl_android_version = "2.1.0"
def room_version = "2.2.6"
def paging_version = "2.1.2"
def lottieVersion = "3.4.0"
implementation ('io.samourai.code.wallet:ExtLibJ:0.0.16-aes') {
exclude group: 'com.google.code.findbugs', module: 'jsr305'
......@@ -96,7 +95,6 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'org.apache.commons:commons-lang3:3.4'
implementation 'org.bouncycastle:bcprov-jdk15on:1.56'
implementation "com.airbnb.android:lottie:$lottieVersion"
implementation 'com.google.guava:guava:24.1-jre'
implementation 'com.google.code.gson:gson:2.8.6'
......
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.samourai.sentinel" >
package="com.samourai.sentinel">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
......@@ -76,7 +76,7 @@
android:theme="@style/AppThemeV3" />
<activity
android:name=".ui.MainActivity"
android:theme="@style/AppTheme.Splash" >
android:theme="@style/AppTheme.Splash">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
......@@ -101,11 +101,6 @@
android:label="Network"
android:theme="@style/AppThemeV3" />
<service
android:name=".tor.service.TorService"
android:enabled="true"
android:stopWithTask="true" />
<provider
android:name=".util.GenericFileProvider"
android:authorities="${applicationId}.provider"
......
package com.samourai.sentinel.ui.broadcast
import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.viewModels
import androidx.lifecycle.*
import com.samourai.sentinel.R
import com.samourai.sentinel.api.ApiService
import com.samourai.sentinel.core.SentinelState
import com.samourai.sentinel.ui.utils.AndroidUtil
import com.samourai.sentinel.ui.views.GenericBottomSheet
import com.samourai.sentinel.ui.views.codeScanner.CameraFragmentBottomSheet
import kotlinx.android.synthetic.main.layout_broadcast_bottom_sheet.*
import kotlinx.coroutines.*
import org.bitcoinj.core.Transaction
import org.bouncycastle.util.encoders.Hex
import org.koin.java.KoinJavaComponent.inject
class BroadcastTx : GenericBottomSheet() {
class BroadcastVm : ViewModel() {
private val _hex = MutableLiveData("")
val hex: LiveData<String> get() = _hex
private val apiService: ApiService by inject(ApiService::class.java);
fun broadCast(): Job {
return viewModelScope.launch(Dispatchers.IO) {
hex.value?.let {
try {
apiService.broadcast(it)
} catch (e: Exception) {
throw CancellationException(e.message)
}
}
};
}
fun setHex(hex: String) {
_hex.postValue(hex)
}
}
private var onBroadcastSuccess: ((hash: String) -> Unit)? = null
private val model: BroadcastVm by viewModels()
private var hash = "";
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.layout_broadcast_bottom_sheet, container);
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
disableBtn(broadCastTransactionBtn, false)
pasteHex.setOnClickListener { _ ->
val string = AndroidUtil.getClipBoardString(requireContext())
string?.let {
model.viewModelScope.launch(Dispatchers.Default) {
validate(it)
}
}
}
hexTextView.movementMethod = ScrollingMovementMethod()
model.hex.observe(viewLifecycleOwner, Observer {
hexTextView.text = it
})
pasteHex.setOnClickListener {
val clipboardData = AndroidUtil.getClipBoardString(requireContext());
clipboardData?.takeIf { it.isNotEmpty() }?.let { string ->
model.viewModelScope.launch(Dispatchers.Default) {
validate(string)
}
}
}
scanHex.setOnClickListener {
val camera = CameraFragmentBottomSheet()
camera.show(requireActivity().supportFragmentManager, camera.tag)
camera.setQrCodeScanLisenter {
model.viewModelScope.launch(Dispatchers.Default) {
validate(it)
}
}
}
broadCastTransactionBtn.setOnClickListener {
showLoading(true)
model.broadCast().invokeOnCompletion {
model.viewModelScope.launch(Dispatchers.Main) {
showLoading(false)
if (it == null) {
onBroadcastSuccess?.invoke(hash)
dismiss()
} else {
Toast.makeText(
requireContext(),
"Unable to broadcast ${it.message}",
Toast.LENGTH_LONG
).show()
}
}
}
}
}
private suspend fun validate(hex: String) {
try {
val transaction = Transaction(SentinelState.getNetworkParam(), Hex.decode(hex))
hash = transaction.hashAsString;
withContext(Dispatchers.Main) {
disableAllButtons(true)
model.setHex(hex)
}
} catch (ex: Exception) {
withContext(Dispatchers.Main) {
disableAllButtons(false)
}
}
}
private fun showLoading(show: Boolean) {
broadcastProgress.visibility = if (show) View.VISIBLE else View.GONE
broadCastTransactionBtn?.text = if (show) " " else getString(R.string.broadcast_transaction)
disableAllButtons(!show)
}
fun setOnBroadcastSuccess(listener: (hash: String) -> Unit) {
this.onBroadcastSuccess = listener;
}
private fun disableAllButtons(enable: Boolean) {
disableBtn(hexTextView, enable)
disableBtn(scanHex, enable)
disableBtn(pasteHex, enable)
disableBtn(broadCastTransactionBtn, enable)
}
private fun disableBtn(button: View, enable: Boolean) {
button.isEnabled = enable
button.alpha = if (enable) 1F else 0.5f
}
}
\ No newline at end of file
<vector android:height="24dp" android:viewportHeight="128"
android:viewportWidth="128" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#ffff" android:pathData="M79,45.745A15,15 0,1 0,58.25 59.6v66.652A1.749,1.749 0,0 0,60 128h8a1.749,1.749 0,0 0,1.75 -1.75V59.6A15.019,15.019 0,0 0,79 45.745ZM66.25,124.5h-4.5V60.558a13.63,13.63 0,0 0,4.5 0ZM64,57.245a11.5,11.5 0,1 1,11.5 -11.5A11.513,11.513 0,0 1,64 57.245Z"/>
<path android:fillColor="#ffff" android:pathData="M86.03,21.713a1.748,1.748 0,0 0,-2.474 0L77.9,27.369a1.751,1.751 0,0 0,0 2.475,22.457 22.457,0 0,1 0,31.8 1.75,1.75 0,0 0,0 2.474l5.659,5.656a1.748,1.748 0,0 0,2.474 0,33.955 33.955,0 0,0 0,-48.064ZM84.759,66.03 L81.57,62.843a25.955,25.955 0,0 0,0 -34.2l3.188,-3.187a30.454,30.454 0,0 1,0 40.57Z"/>
<path android:fillColor="#ffff" android:pathData="M97.632,11.111a1.751,1.751 0,0 0,-2.475 0L89.5,16.768a1.748,1.748 0,0 0,0 2.474,37.432 37.432,0 0,1 0,53.005 1.749,1.749 0,0 0,0 2.475l5.656,5.656a1.749,1.749 0,0 0,2.475 0,48.929 48.929,0 0,0 0,-69.267ZM96.372,76.643 L93.188,73.459a40.928,40.928 0,0 0,0 -55.429l3.184,-3.183a45.424,45.424 0,0 1,0 61.8Z"/>
<path android:fillColor="#ffff" android:pathData="M109.235,0.51a1.748,1.748 0,0 0,-2.474 0L101.1,6.166a1.751,1.751 0,0 0,0 2.475,52.409 52.409,0 0,1 0,74.209 1.75,1.75 0,0 0,0 2.474l5.657,5.656a1.748,1.748 0,0 0,2.474 0,63.9 63.9,0 0,0 0,-90.47ZM107.98,87.251 L104.8,84.068a55.906,55.906 0,0 0,0 -76.646l3.182,-3.183a60.4,60.4 0,0 1,0 83.012Z"/>
<path android:fillColor="#ffff" android:pathData="M43.5,45.745a22.348,22.348 0,0 1,6.6 -15.9,1.751 1.751,0 0,0 0,-2.475l-5.657,-5.656a1.748,1.748 0,0 0,-2.474 0,33.955 33.955,0 0,0 0,48.064 1.748,1.748 0,0 0,2.474 0L50.1,64.121a1.75,1.75 0,0 0,0 -2.474A22.349,22.349 0,0 1,43.5 45.745ZM43.241,66.03a30.454,30.454 0,0 1,0 -40.57l3.188,3.187a25.955,25.955 0,0 0,0 34.2Z"/>
<path android:fillColor="#ffff" android:pathData="M27.5,45.745a37.251,37.251 0,0 1,11 -26.5,1.748 1.748,0 0,0 0,-2.474l-5.656,-5.657a1.8,1.8 0,0 0,-2.475 0,48.93 48.93,0 0,0 0,69.267 1.749,1.749 0,0 0,2.475 0L38.5,74.722a1.749,1.749 0,0 0,0 -2.475A37.247,37.247 0,0 1,27.5 45.745ZM31.627,76.645a45.426,45.426 0,0 1,0 -61.8l3.183,3.183a40.932,40.932 0,0 0,0 55.429Z"/>
<path android:fillColor="#ffff" android:pathData="M11.5,45.745a52.148,52.148 0,0 1,15.4 -37.1,1.749 1.749,0 0,0 0,-2.475L21.239,0.51a1.748,1.748 0,0 0,-2.474 0,63.9 63.9,0 0,0 0,90.47 1.748,1.748 0,0 0,2.474 0L26.9,85.324a1.748,1.748 0,0 0,0 -2.474A52.148,52.148 0,0 1,11.5 45.745ZM20.019,87.251a60.4,60.4 0,0 1,0 -83.012L23.2,7.422a55.906,55.906 0,0 0,0 76.646Z"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:hint="Singed Transaction HEX"
android:outlineProvider="bounds"
app:boxStrokeColor="@color/white"
app:endIconMode="custom"
android:focusable="true"
app:hintTextColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:id="@+id/hexEditText"
android:layout_height="match_parent"
android:focusable="true"
android:lines="6" />
</com.google.android.material.textfield.TextInputLayout>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/scanHexBtn"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:src="@drawable/ic_baseline_qr_code_scanner_24"
app:layout_constraintBottom_toBottomOf="@+id/scanHexBtn2"
app:layout_constraintEnd_toEndOf="@+id/textInputLayout"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/scanHexBtn2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/scanHexBtn2" />
<com.google.android.material.button.MaterialButton
android:id="@+id/scanHexBtn2"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:backgroundTint="@android:color/transparent"
app:icon="@drawable/ic_content_paste_24px"
app:iconGravity="textEnd"
app:iconPadding="0dp"
app:iconTint="@color/white"
app:layout_constraintEnd_toStartOf="@+id/scanHexBtn"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="@+id/textInputLayout"
app:layout_constraintTop_toBottomOf="@+id/textInputLayout" />
<com.google.android.material.button.MaterialButton
android:id="@+id/broadCastTransactionBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="11dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="11dp"
android:layout_marginBottom="8dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="Broadcast Transaction"
android:textColor="@color/white"
app:backgroundTint="?attr/colorAccent"
app:cornerRadius="8dp"
app:icon="@drawable/ic_baseline_cloud_queue_24"
app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.8"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/scanHexBtn"
app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/motionItem"
android:layout_width="match_parent"
android:layout_height="420dp"
android:minHeight="420dp"
>
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/materialToolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@android:color/transparent"
android:elevation="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:title="Broadcast transaction"
app:titleCentered="true" />
<com.google.android.material.button.MaterialButton
android:id="@+id/pasteHex"
android:layout_width="0dp"
android:layout_height="@dimen/spacing_xxlarge"
android:layout_marginStart="24dp"
android:layout_marginEnd="16dp"
android:text="paste"
android:textColor="@color/white"
app:backgroundTint="@color/grey_accent"
app:cornerRadius="6dp"
app:icon="@drawable/ic_content_paste_24px"
app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="@+id/scanHex"
app:layout_constraintEnd_toStartOf="@+id/guideline5"
app:layout_constraintHorizontal_bias="0.80"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/scanHex" />
<com.google.android.material.button.MaterialButton
android:id="@+id/scanHex"
android:layout_width="0dp"
android:layout_height="@dimen/spacing_xxlarge"
android:layout_marginStart="16dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="16dp"
android:text="Scan"
android:textColor="@color/white"
app:backgroundTint="@color/grey_accent"
app:cornerRadius="6dp"
app:icon="@drawable/ic_baseline_qr_code_24"
app:iconTint="@color/white"
app:layout_constraintBottom_toTopOf="@+id/broadCastTransactionBtn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.20"
app:layout_constraintStart_toStartOf="@+id/guideline5" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.50121653" />
<androidx.cardview.widget.CardView
android:id="@+id/cardView4"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="24dp"
app:cardBackgroundColor="@color/v3_background_light"
app:cardCornerRadius="8dp"
app:layout_constraintBottom_toTopOf="@+id/scanHex"
app:layout_constraintEnd_toEndOf="@+id/scanHex"
app:layout_constraintStart_toStartOf="@+id/pasteHex"
app:layout_constraintTop_toBottomOf="@+id/materialToolbar">
<TextView
android:id="@+id/hexTextView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="start"
android:nestedScrollingEnabled="true"
android:padding="@dimen/spacing_medium"
android:scrollbars="vertical"
tools:text="0100000010\n1\n101410" />
</androidx.cardview.widget.CardView>
<com.google.android.material.button.MaterialButton
android:id="@+id/broadCastTransactionBtn"
android:layout_width="0dp"
android:layout_height="58dp"
android:layout_marginBottom="8dp"
android:text="@string/broadcast_transaction"
android:textColor="@color/white"
app:backgroundTint="@color/md_green_400"
app:cornerRadius="28dp"
app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/scanHex"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@+id/pasteHex" />
<com.google.android.material.progressindicator.CircularProgressIndicator
style="@style/Widget.MaterialComponents.CircularProgressIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
android:id="@+id/broadcastProgress"
android:elevation="2dp"
app:indicatorSize="24dp"
app:dotWidth="2dp"
android:visibility="gone"
app:indicatorColor="@color/white"
app:layout_constraintBottom_toBottomOf="@+id/broadCastTransactionBtn"
app:layout_constraintEnd_toEndOf="@+id/broadCastTransactionBtn"
app:layout_constraintStart_toStartOf="@+id/broadCastTransactionBtn"
app:layout_constraintTop_toTopOf="@+id/broadCastTransactionBtn" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_scan"
android:title="Scan"
app:icon="@drawable/ic_baseline_qr_code_scanner_24" />
<item
android:id="@+id/menu_paste"
android:title="Paste"
app:icon="@drawable/ic_content_paste_24px" />
</menu>
\ No newline at end of file
......@@ -2,6 +2,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/home_options_broadcast"
android:title="Broadcast transaction" />
<item
android:id="@+id/home_options_settings"
android:title="Settings" />
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment