diff --git a/app/build.gradle b/app/build.gradle index b18450fa..51082968 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,20 +1,24 @@ plugins { id 'com.android.application' id 'kotlin-android' - id 'kotlin-android-extensions' } android { - compileSdkVersion 32 + namespace 'io.horizontalsystems.ethereumkit.sample' + compileSdkVersion 33 defaultConfig { applicationId "io.horizontalsystems.ethereumkit" minSdkVersion 26 - targetSdkVersion 32 + targetSdkVersion 33 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } + buildFeatures { + viewBinding true + } + buildFeatures { compose true } @@ -33,16 +37,16 @@ android { compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = "11" + jvmTarget = "17" } composeOptions { - kotlinCompilerExtensionVersion '1.3.0' + kotlinCompilerExtensionVersion '1.5.8' } } diff --git a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/addresswatch/AddressWatchActivity.kt b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/addresswatch/AddressWatchActivity.kt index 4f4f958c..f94afcf9 100644 --- a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/addresswatch/AddressWatchActivity.kt +++ b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/addresswatch/AddressWatchActivity.kt @@ -2,27 +2,42 @@ package io.horizontalsystems.ethereumkit.sample.modules.addresswatch import android.os.Bundle import android.view.View +import android.widget.Button +import android.widget.EditText +import android.widget.ProgressBar import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import io.horizontalsystems.ethereumkit.sample.R import io.horizontalsystems.ethereumkit.sample.modules.main.ShowTxType import io.horizontalsystems.ethereumkit.sample.modules.main.TransactionsAdapter -import kotlinx.android.synthetic.main.activity_address_watch.* -import kotlinx.android.synthetic.main.activity_address_watch.ethFilter -import kotlinx.android.synthetic.main.activity_address_watch.tokenFilter -import kotlinx.android.synthetic.main.activity_address_watch.transactionsRecyclerView class AddressWatchActivity : AppCompatActivity() { private lateinit var viewModel: AddressWatchViewModel + private lateinit var addressInput: EditText + private lateinit var watchButton: Button + private lateinit var ethFilter: Button + private lateinit var tokenFilter: Button + private lateinit var transactionsRecyclerView: RecyclerView + private lateinit var transactionSyncProgress: ProgressBar + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) viewModel = ViewModelProvider(this).get(AddressWatchViewModel::class.java) + addressInput = findViewById(R.id.addressInput) + watchButton = findViewById(R.id.watchButton) + ethFilter = findViewById(R.id.ethFilter) + tokenFilter = findViewById(R.id.tokenFilter) + transactionsRecyclerView = findViewById(R.id.transactionsRecyclerView) + transactionSyncProgress = findViewById(R.id.transactionSyncProgress) + setContentView(R.layout.activity_address_watch) watchButton.setOnClickListener { diff --git a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/addresswatch/AddressWatchViewModel.kt b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/addresswatch/AddressWatchViewModel.kt index 5bcfce9a..dab774a1 100644 --- a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/addresswatch/AddressWatchViewModel.kt +++ b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/addresswatch/AddressWatchViewModel.kt @@ -129,11 +129,11 @@ class AddressWatchViewModel : ViewModel() { when (Configuration.chain) { Chain.BinanceSmartChain -> { - transactionSource = TransactionSource.etherscanApi(Configuration.etherscanKey.split(",")) + transactionSource = TransactionSource.binance(Configuration.etherscanKey.split(",")) rpcSource = RpcSource.binanceSmartChainHttp() } Chain.Ethereum -> { - transactionSource = TransactionSource.etherscanApi(Configuration.etherscanKey.split(",")) + transactionSource = TransactionSource.ethereum(Configuration.etherscanKey.split(",")) rpcSource = RpcSource.Http(listOf(URI(Configuration.ethereumRpc)), null) } else -> { diff --git a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/BalanceFragment.kt b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/BalanceFragment.kt index 1bf3a717..56e18389 100644 --- a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/BalanceFragment.kt +++ b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/BalanceFragment.kt @@ -8,15 +8,18 @@ import android.view.View import android.view.ViewGroup import androidx.lifecycle.ViewModelProvider import io.horizontalsystems.ethereumkit.core.EthereumKit -import io.horizontalsystems.ethereumkit.sample.R -import kotlinx.android.synthetic.main.fragment_balance.* +import io.horizontalsystems.ethereumkit.sample.databinding.FragmentBalanceBinding class BalanceFragment : Fragment() { private lateinit var viewModel: MainViewModel - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_balance, container, false) + private var _binding: FragmentBalanceBinding? = null // 2. Add binding property + private val binding get() = _binding!! + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + _binding = FragmentBalanceBinding.inflate(inflater, container, false) // 3. Inflate with ViewBinding + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -25,52 +28,52 @@ class BalanceFragment : Fragment() { viewModel = ViewModelProvider(requireActivity()).get(MainViewModel::class.java) viewModel.balance.observe(viewLifecycleOwner, Observer { balance -> - balanceValue.text = (balance ?: 0).toString() + binding.balanceValue.text = (balance ?: 0).toString() }) viewModel.erc20TokenBalance.observe(viewLifecycleOwner, Observer { balance -> - tokenBalanceValue.text = (balance ?: 0).toString() + binding. tokenBalanceValue.text = (balance ?: 0).toString() }) viewModel.lastBlockHeight.observe(viewLifecycleOwner, Observer { lbh -> - lbhValue.text = (lbh ?: 0).toString() + binding.lbhValue.text = (lbh ?: 0).toString() }) viewModel.syncState.observe(viewLifecycleOwner, Observer { state -> val syncStateInfo = getSynStateInfo(state) - syncStateValue.text = syncStateInfo.description + binding.syncStateValue.text = syncStateInfo.description if (syncStateInfo.error == null) { - syncStateError.visibility = View.GONE + binding.syncStateError.visibility = View.GONE } else { - syncStateError.text = syncStateInfo.error.message - syncStateError.visibility = View.VISIBLE + binding.syncStateError.text = syncStateInfo.error.message + binding.syncStateError.visibility = View.VISIBLE } }) viewModel.transactionsSyncState.observe(viewLifecycleOwner, Observer { state -> - txSyncStateValue.text = getSynStateInfo(state).description + binding.txSyncStateValue.text = getSynStateInfo(state).description }) viewModel.erc20SyncState.observe(viewLifecycleOwner, Observer { state -> val syncStateInfo = getSynStateInfo(state) - erc20SyncStateValue.text = syncStateInfo.description + binding.erc20SyncStateValue.text = syncStateInfo.description if (syncStateInfo.error == null) { - erc20SyncStateError.visibility = View.GONE + binding.erc20SyncStateError.visibility = View.GONE } else { - erc20SyncStateError.text = syncStateInfo.error.message - erc20SyncStateError.visibility = View.VISIBLE + binding.erc20SyncStateError.text = syncStateInfo.error.message + binding.erc20SyncStateError.visibility = View.VISIBLE } }) viewModel.erc20TransactionsSyncState.observe(viewLifecycleOwner, Observer { state -> - erc20TxSyncStateValue.text = getSynStateInfo(state).description + binding.erc20TxSyncStateValue.text = getSynStateInfo(state).description }) - buttonRefresh.setOnClickListener { + binding.buttonRefresh.setOnClickListener { viewModel.refresh() } - buttonClear.setOnClickListener { + binding.buttonClear.setOnClickListener { viewModel.clear() } } diff --git a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/MainActivity.kt b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/MainActivity.kt index b101f78b..8e5e208b 100644 --- a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/MainActivity.kt +++ b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/MainActivity.kt @@ -9,12 +9,14 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import com.google.android.material.bottomnavigation.BottomNavigationView import io.horizontalsystems.ethereumkit.sample.R +import io.horizontalsystems.ethereumkit.sample.databinding.ActivityMainBinding import io.horizontalsystems.ethereumkit.sample.modules.addresswatch.AddressWatchActivity import io.horizontalsystems.ethereumkit.sample.modules.uniswapV3.UniswapV3Fragment -import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener { + private lateinit var binding: ActivityMainBinding + private val balanceFragment = BalanceFragment() private val transactionsFragment = TransactionsFragment() private val sendReceiveFragment = SendReceiveFragment() @@ -28,9 +30,10 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + binding = ActivityMainBinding.inflate(layoutInflater) setContentView(R.layout.activity_main) - toolbar.setOnMenuItemClickListener { item -> + binding.toolbar.setOnMenuItemClickListener { item -> when (item.itemId) { R.id.menuAddressWatch -> { val intent = Intent(this, AddressWatchActivity::class.java) diff --git a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/MainViewModel.kt b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/MainViewModel.kt index d764cd7b..a4024627 100644 --- a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/MainViewModel.kt +++ b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/MainViewModel.kt @@ -193,17 +193,17 @@ class MainViewModel : ViewModel() { private fun createKit(): EthereumKit { when (Configuration.chain) { Chain.BinanceSmartChain -> { - transactionSource = TransactionSource.etherscanApi(Configuration.etherscanKey.split(",")) + transactionSource = TransactionSource.binance(Configuration.etherscanKey.split(",")) rpcSource = RpcSource.binanceSmartChainHttp() } Chain.Ethereum -> { - transactionSource = TransactionSource.etherscanApi(Configuration.etherscanKey.split(",")) + transactionSource = TransactionSource.ethereum(Configuration.etherscanKey.split(",")) rpcSource = RpcSource.Http(listOf(URI(Configuration.ethereumRpc)), null) } Chain.ArbitrumOne -> { - transactionSource = TransactionSource.etherscanApi(Configuration.etherscanKey.split(",")) + transactionSource = TransactionSource.arbitrumOne(Configuration.etherscanKey.split(",")) rpcSource = RpcSource.arbitrumOneRpcHttp() } diff --git a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/NftsFragment.kt b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/NftsFragment.kt index 468e9fe0..f61a6f7e 100644 --- a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/NftsFragment.kt +++ b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/NftsFragment.kt @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.appcompat.widget.Toolbar import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.text.selection.SelectionContainer @@ -20,12 +21,13 @@ import androidx.compose.ui.unit.dp import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewmodel.compose.viewModel -import kotlinx.android.synthetic.main.activity_main.* +import io.horizontalsystems.ethereumkit.sample.R class NftsFragment : Fragment() { private lateinit var mainViewModel: MainViewModel override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val toolbar = activity?.findViewById(R.id.toolbar) // <-- FIND THE VIEW toolbar?.title = "Nfts" mainViewModel = activity?.let { ViewModelProvider(it)[MainViewModel::class.java] } ?: return null diff --git a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/SendReceiveFragment.kt b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/SendReceiveFragment.kt index 41a90a9d..4ffd7e06 100644 --- a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/SendReceiveFragment.kt +++ b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/SendReceiveFragment.kt @@ -8,16 +8,22 @@ import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.lifecycle.ViewModelProvider -import io.horizontalsystems.ethereumkit.sample.R -import kotlinx.android.synthetic.main.fragment_send_receive.* +import io.horizontalsystems.ethereumkit.sample.databinding.FragmentSendReceiveBinding import java.math.BigDecimal class SendReceiveFragment : Fragment() { private lateinit var viewModel: MainViewModel - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_send_receive, container, false) + private var _binding: FragmentSendReceiveBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentSendReceiveBinding.inflate(inflater, container, false) + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -26,7 +32,7 @@ class SendReceiveFragment : Fragment() { viewModel = activity?.let { ViewModelProvider(it).get(MainViewModel::class.java) } ?: return viewModel.estimatedGas.observe(viewLifecycleOwner, Observer { estimatedGas -> - estimateGasText.text = estimatedGas + binding.estimateGasText.text = estimatedGas }) viewModel.sendStatus.observe(viewLifecycleOwner, Observer { sendError -> @@ -34,38 +40,38 @@ class SendReceiveFragment : Fragment() { Toast.makeText(context, msg, Toast.LENGTH_LONG).show() }) - receiveAddressButton.setOnClickListener { - receiveAddressText.text = viewModel.receiveAddress() + binding.receiveAddressButton.setOnClickListener { + binding.receiveAddressText.text = viewModel.receiveAddress() } - estimateGasButton.setOnClickListener { + binding.estimateGasButton.setOnClickListener { onTapEstimateGas(false) } - estimateErc20GasButton.setOnClickListener { + binding.estimateErc20GasButton.setOnClickListener { onTapEstimateGas(true) } - sendButton.setOnClickListener { + binding.sendButton.setOnClickListener { when { - sendAddress.text.isEmpty() -> sendAddress.error = "Send address cannot be blank" - sendAmount.text.isEmpty() -> sendAmount.error = "Send amount cannot be blank" - else -> viewModel.send(sendAddress.text.toString(), sendAmount.text.toString().toBigDecimal()) + binding.sendAddress.text.isEmpty() -> binding.sendAddress.error = "Send address cannot be blank" + binding.sendAmount.text.isEmpty() -> binding.sendAmount.error = "Send amount cannot be blank" + else -> viewModel.send(binding.sendAddress.text.toString(), binding.sendAmount.text.toString().toBigDecimal()) } } - sendErc20.setOnClickListener { + binding.sendErc20.setOnClickListener { when { - sendAmount.text.isEmpty() -> sendAmount.error = "Send amount cannot be blank" - else -> viewModel.sendERC20(sendAddress.text.toString(), sendAmount.text.toString().toBigDecimal()) + binding.sendAmount.text.isEmpty() -> binding.sendAmount.error = "Send amount cannot be blank" + else -> viewModel.sendERC20(binding.sendAddress.text.toString(), binding.sendAmount.text.toString().toBigDecimal()) } } } private fun onTapEstimateGas(isErc20: Boolean) { - val toAddress = sendAddress.text.toString() + val toAddress = binding.sendAddress.text.toString() val resolvedToAddress = if (toAddress.isNotBlank()) toAddress else null - val resolvedAmount = sendAmount.text.toString().toBigDecimalOrNull() ?: BigDecimal.ZERO + val resolvedAmount = binding.sendAmount.text.toString().toBigDecimalOrNull() ?: BigDecimal.ZERO viewModel.estimateGas(resolvedToAddress, resolvedAmount, isErc20) } diff --git a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/SwapFragment.kt b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/SwapFragment.kt index 35a36c5c..2a68e9f9 100644 --- a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/SwapFragment.kt +++ b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/SwapFragment.kt @@ -11,15 +11,17 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import io.horizontalsystems.ethereumkit.sample.Configuration -import io.horizontalsystems.ethereumkit.sample.R +import io.horizontalsystems.ethereumkit.sample.databinding.FragmentSwapBinding import io.horizontalsystems.uniswapkit.models.Token import io.horizontalsystems.uniswapkit.models.TradeType -import kotlinx.android.synthetic.main.fragment_swap.* import java.math.BigDecimal class SwapFragment : Fragment() { private lateinit var viewModel: MainViewModel + private var _binding: FragmentSwapBinding? = null + private val binding get() = _binding!! + private val fromAmountListener = object : TextWatcher { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { @@ -48,7 +50,9 @@ class SwapFragment : Fragment() { } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_swap, container, false) + _binding = FragmentSwapBinding.inflate(inflater, container, false) + val view = binding.root + return view } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -62,71 +66,71 @@ class SwapFragment : Fragment() { }) viewModel.swapData.observe(viewLifecycleOwner, Observer { swapData -> - fromAmount.isEnabled = swapData != null - toAmount.isEnabled = swapData != null + binding.fromAmount.isEnabled = swapData != null + binding.toAmount.isEnabled = swapData != null }) viewModel.tradeData.observe(viewLifecycleOwner, Observer { tradeData -> if (tradeData == null) { - minMax.text = null - executionPrice.text = null - midPrice.text = null - priceImpact.text = null + binding.minMax.text = null + binding.executionPrice.text = null + binding.midPrice.text = null + binding.priceImpact.text = null } else { when (tradeData.type) { TradeType.ExactIn -> { setToAmount(tradeData.amountOut) - minMax.text = "Minimum Received: ${tradeData.amountOutMin?.let { "${it.stripTrailingZeros().toPlainString()} $toTokenCode" } ?: ""}" + binding.minMax.text = "Minimum Received: ${tradeData.amountOutMin?.let { "${it.stripTrailingZeros().toPlainString()} $toTokenCode" } ?: ""}" } TradeType.ExactOut -> { setFromAmount(tradeData.amountIn) - minMax.text = "Maximum Sold: ${tradeData.amountInMax?.let { "${it.stripTrailingZeros().toPlainString()} $fromTokenCode" } ?: ""}" + binding.minMax.text = "Maximum Sold: ${tradeData.amountInMax?.let { "${it.stripTrailingZeros().toPlainString()} $fromTokenCode" } ?: ""}" } } val executionPriceStr = tradeData.executionPrice?.let { "${it.toPlainString()} $toTokenCode / $fromTokenCode " } - executionPrice.text = "Execution Price: " + (executionPriceStr ?: "") + binding.executionPrice.text = "Execution Price: " + (executionPriceStr ?: "") val midPriceStr = tradeData.midPrice?.let { "${it.toPlainString()} $toTokenCode / $fromTokenCode " } - midPrice.text = "Mid Price: " + (midPriceStr ?: "") + binding.midPrice.text = "Mid Price: " + (midPriceStr ?: "") - priceImpact.text = "Price Impact: ${tradeData.priceImpact?.toPlainString() ?: ""}%" + binding.priceImpact.text = "Price Impact: ${tradeData.priceImpact?.toPlainString() ?: ""}%" - providerFee.text = "Provider Fee: ${tradeData.providerFee?.toPlainString() ?: ""}" + binding.providerFee.text = "Provider Fee: ${tradeData.providerFee?.toPlainString() ?: ""}" - path.text = "Path: ${pathDescription(tradeData.path)}" + binding.path.text = "Path: ${pathDescription(tradeData.path)}" updateLabels(tradeData.type) } }) - buttonSyncSwapData.setOnClickListener { + binding.buttonSyncSwapData.setOnClickListener { syncSwapData() } - buttonSwap.setOnClickListener { + binding.buttonSwap.setOnClickListener { viewModel.swap() } - buttonSyncAllowance.setOnClickListener { + binding.buttonSyncAllowance.setOnClickListener { viewModel.syncAllowance() } - buttonApprove.setOnClickListener { - fromAmount.text?.let { + binding.buttonApprove.setOnClickListener { + binding.fromAmount.text?.let { if (it.isNotBlank()) { viewModel.approve(BigDecimal(it.toString())) } } } - fromAmount.addTextChangedListener(fromAmountListener) - toAmount.addTextChangedListener(toAmountListener) + binding.fromAmount.addTextChangedListener(fromAmountListener) + binding.toAmount.addTextChangedListener(toAmountListener) updateLabels(TradeType.ExactIn) } @@ -146,22 +150,22 @@ class SwapFragment : Fragment() { get() = viewModel.toToken?.code ?: "ETH" private fun syncSwapData() { - fromAmount.isEnabled = false - toAmount.isEnabled = false + binding.fromAmount.isEnabled = false + binding.toAmount.isEnabled = false viewModel.syncSwapData() } private fun setFromAmount(amount: BigDecimal?) { - fromAmount.removeTextChangedListener(fromAmountListener) - fromAmount.setText(amount?.stripTrailingZeros()?.toPlainString()) - fromAmount.addTextChangedListener(fromAmountListener) + binding.fromAmount.removeTextChangedListener(fromAmountListener) + binding.fromAmount.setText(amount?.stripTrailingZeros()?.toPlainString()) + binding.fromAmount.addTextChangedListener(fromAmountListener) } private fun setToAmount(amount: BigDecimal?) { - toAmount.removeTextChangedListener(toAmountListener) - toAmount.setText(amount?.stripTrailingZeros()?.toPlainString()) - toAmount.addTextChangedListener(toAmountListener) + binding.toAmount.removeTextChangedListener(toAmountListener) + binding.toAmount.setText(amount?.stripTrailingZeros()?.toPlainString()) + binding.toAmount.addTextChangedListener(toAmountListener) } private fun updateLabels(tradeType: TradeType) { @@ -174,10 +178,10 @@ class SwapFragment : Fragment() { fromLabel += " (estimated)" } - fromAmount.hint = fromLabel - fromAmountLayout.hint = fromLabel - toAmount.hint = toLabel - toAmountLayout.hint = toLabel + binding.fromAmount.hint = fromLabel + binding.fromAmountLayout.hint = fromLabel + binding.toAmount.hint = toLabel + binding.toAmountLayout.hint = toLabel } } diff --git a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/TransactionsFragment.kt b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/TransactionsFragment.kt index 6031d151..63f4709c 100644 --- a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/TransactionsFragment.kt +++ b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/main/TransactionsFragment.kt @@ -13,7 +13,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import io.horizontalsystems.ethereumkit.sample.R import io.horizontalsystems.ethereumkit.sample.core.TransactionRecord -import kotlinx.android.synthetic.main.fragment_transactions.* +import io.horizontalsystems.ethereumkit.sample.databinding.FragmentTransactionsBinding import java.math.BigDecimal import java.math.BigInteger import java.math.RoundingMode @@ -25,16 +25,20 @@ class TransactionsFragment : Fragment() { private lateinit var viewModel: MainViewModel private val transactionsAdapter = TransactionsAdapter() + private var _binding: FragmentTransactionsBinding? = null + private val binding get() = _binding!! - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_transactions, container, false) + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + _binding = FragmentTransactionsBinding.inflate(inflater, container, false) + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - transactionsRecyclerView.adapter = transactionsAdapter - transactionsRecyclerView.layoutManager = LinearLayoutManager(context) + binding.transactionsRecyclerView.adapter = transactionsAdapter + binding.transactionsRecyclerView.layoutManager = LinearLayoutManager(context) viewModel = activity?.let { ViewModelProvider(it).get(MainViewModel::class.java) } ?: return @@ -55,12 +59,12 @@ class TransactionsFragment : Fragment() { context?.let { ctx -> when (showTxType) { ShowTxType.Eth -> { - ethFilter.setBackgroundColor(ctx.getColor(R.color.colorSelected)) - tokenFilter.setBackgroundColor(Color.WHITE) + binding.ethFilter.setBackgroundColor(ctx.getColor(R.color.colorSelected)) + binding.tokenFilter.setBackgroundColor(Color.WHITE) } ShowTxType.Erc20 -> { - tokenFilter.setBackgroundColor(ctx.getColor(R.color.colorSelected)) - ethFilter.setBackgroundColor(Color.WHITE) + binding.tokenFilter.setBackgroundColor(ctx.getColor(R.color.colorSelected)) + binding.ethFilter.setBackgroundColor(Color.WHITE) } else -> { } @@ -69,11 +73,11 @@ class TransactionsFragment : Fragment() { } - ethFilter.setOnClickListener { + binding.ethFilter.setOnClickListener { viewModel.filterTransactions(true) } - tokenFilter.setOnClickListener { + binding.tokenFilter.setOnClickListener { viewModel.filterTransactions(false) } } diff --git a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/uniswapV3/UniswapV3Fragment.kt b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/uniswapV3/UniswapV3Fragment.kt index 882acbb3..83cbe0fc 100644 --- a/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/uniswapV3/UniswapV3Fragment.kt +++ b/app/src/main/java/io/horizontalsystems/ethereumkit/sample/modules/uniswapV3/UniswapV3Fragment.kt @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -28,14 +29,12 @@ import io.horizontalsystems.ethereumkit.sample.core.Erc20Adapter import io.horizontalsystems.ethereumkit.sample.core.EthereumAdapter import io.horizontalsystems.ethereumkit.sample.modules.main.GasPriceHelper import io.horizontalsystems.ethereumkit.sample.modules.main.MainViewModel -import io.horizontalsystems.uniswapkit.models.TradeType -import kotlinx.android.synthetic.main.activity_main.* import java.math.BigDecimal class UniswapV3Fragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - toolbar?.title = "Uniswap V3" + (activity as? AppCompatActivity)?.supportActionBar?.title = "Uniswap V3" val mainViewModel = activity?.let { ViewModelProvider(it)[MainViewModel::class.java] } ?: return null diff --git a/build.gradle b/build.gradle index 91b79e63..34b8bebb 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.7.10' + ext.kotlin_version = '1.9.22' ext.room_version = '2.4.3' ext.coroutines_version = '1.6.4' repositories { @@ -9,7 +9,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' + classpath 'com.android.tools.build:gradle:8.11.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/erc20kit/build.gradle b/erc20kit/build.gradle index 5bb26b5a..6786f106 100644 --- a/erc20kit/build.gradle +++ b/erc20kit/build.gradle @@ -16,11 +16,12 @@ afterEvaluate { } android { - compileSdkVersion 32 + namespace 'io.horizontalsystems.erc20kit' + compileSdkVersion 33 defaultConfig { minSdkVersion 26 - targetSdkVersion 32 + targetSdkVersion 33 kapt { arguments { @@ -38,8 +39,13 @@ android { } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { - jvmTarget = "11" + jvmTarget = "17" } } diff --git a/ethereumkit/build.gradle b/ethereumkit/build.gradle index 9517342d..be19db3b 100644 --- a/ethereumkit/build.gradle +++ b/ethereumkit/build.gradle @@ -16,11 +16,12 @@ afterEvaluate { } android { - compileSdkVersion 32 + namespace 'io.horizontalsystems.ethereumkit' + compileSdkVersion 33 defaultConfig { minSdkVersion 26 - targetSdkVersion 32 + targetSdkVersion 33 kapt { arguments { @@ -40,12 +41,12 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '11' + jvmTarget = '17' } diff --git a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/ApiRpcSyncer.kt b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/ApiRpcSyncer.kt index 1bea70a1..f092deba 100644 --- a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/ApiRpcSyncer.kt +++ b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/ApiRpcSyncer.kt @@ -52,7 +52,7 @@ class ApiRpcSyncer( stopTimer() } - override fun single(rpc: JsonRpc): Single = + override fun single(rpc: JsonRpc): Single = rpcApiProvider.single(rpc) //endregion diff --git a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/Interfaces.kt b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/Interfaces.kt index b6222bf9..fba99fde 100644 --- a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/Interfaces.kt +++ b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/Interfaces.kt @@ -47,7 +47,7 @@ sealed class WebSocketState { interface IRpcApiProvider { val source: String - fun single(rpc: JsonRpc): Single + fun single(rpc: JsonRpc): Single } interface IRpcSyncer { @@ -58,7 +58,7 @@ interface IRpcSyncer { fun start() fun stop() - fun single(rpc: JsonRpc): Single + fun single(rpc: JsonRpc): Single } interface IRpcSyncerListener { diff --git a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/NodeApiProvider.kt b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/NodeApiProvider.kt index d08f990a..3b273451 100644 --- a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/NodeApiProvider.kt +++ b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/NodeApiProvider.kt @@ -58,7 +58,7 @@ class NodeApiProvider( override val source: String = uris.first().host - override fun single(rpc: JsonRpc): Single { + override fun single(rpc: JsonRpc): Single { rpc.id = currentRpcId.addAndGet(1) return Single.create { emitter -> diff --git a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/RpcBlockchain.kt b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/RpcBlockchain.kt index f5279790..dad3cc26 100644 --- a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/RpcBlockchain.kt +++ b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/RpcBlockchain.kt @@ -224,7 +224,7 @@ class RpcBlockchain( return syncer.single(callRpc(contractAddress, data, defaultBlockParameter)) } - override fun rpcSingle(rpc: JsonRpc): Single { + override fun rpcSingle(rpc: JsonRpc): Single { return syncer.single(rpc) } diff --git a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/WebSocketRpcSyncer.kt b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/WebSocketRpcSyncer.kt index 2f5d44b0..5d8ec1d7 100644 --- a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/WebSocketRpcSyncer.kt +++ b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/api/core/WebSocketRpcSyncer.kt @@ -46,7 +46,7 @@ class WebSocketRpcSyncer( rpcSocket.stop() } - override fun single(rpc: JsonRpc): Single { + override fun single(rpc: JsonRpc): Single { return Single.create { emitter -> send( rpc = rpc, diff --git a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/core/EthereumKit.kt b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/core/EthereumKit.kt index afac9a08..a5a58ca4 100644 --- a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/core/EthereumKit.kt +++ b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/core/EthereumKit.kt @@ -332,7 +332,7 @@ class EthereumKit( decorationManager.addTransactionDecorator(decorator) } - internal fun rpcSingle(rpc: JsonRpc): Single { + internal fun rpcSingle(rpc: JsonRpc): Single { return blockchain.rpcSingle(rpc) } diff --git a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/core/Interfaces.kt b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/core/Interfaces.kt index 7ceb74e2..04718d1c 100644 --- a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/core/Interfaces.kt +++ b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/core/Interfaces.kt @@ -70,7 +70,7 @@ interface IBlockchain { fun getStorageAt(contractAddress: Address, position: ByteArray, defaultBlockParameter: DefaultBlockParameter): Single fun call(contractAddress: Address, data: ByteArray, defaultBlockParameter: DefaultBlockParameter): Single - fun rpcSingle(rpc: JsonRpc): Single + fun rpcSingle(rpc: JsonRpc): Single } interface IBlockchainListener { diff --git a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/models/TransactionSource.kt b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/models/TransactionSource.kt index a5da0c5c..29124596 100644 --- a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/models/TransactionSource.kt +++ b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/models/TransactionSource.kt @@ -12,15 +12,46 @@ class TransactionSource(val name: String, val type: SourceType) { } companion object { - private fun etherscan(apiSubdomain: String, txSubdomain: String?, apiKeys: List): TransactionSource { + private fun etherscan(name: String, explorerUrl: String, apiKeys: List): TransactionSource { return TransactionSource( - "etherscan.io", - SourceType.Etherscan("https://$apiSubdomain.etherscan.io/v2/", "https://${txSubdomain?.let { "$it." } ?: ""}etherscan.io", apiKeys) + name, SourceType.Etherscan("https://api.etherscan.io/v2/", explorerUrl, apiKeys) ) } - fun etherscanApi(apiKeys: List): TransactionSource { - return etherscan("api", null, apiKeys) + fun ethereum(apiKeys: List): TransactionSource { + return etherscan("etherscan.io", "https://etherscan.io", apiKeys) + } + + fun binance(apiKeys: List): TransactionSource { + return etherscan("bscscan.com", "https://bscscan.com", apiKeys) + } + + fun polygon(apiKeys: List): TransactionSource { + return etherscan("polygonscan.com", "https://polygonscan.com", apiKeys) + } + + fun optimism(apiKeys: List): TransactionSource { + return etherscan("optimistic.etherscan.io", "https://optimistic.etherscan.io", apiKeys) + } + + fun arbitrumOne(apiKeys: List): TransactionSource { + return etherscan("arbiscan.io", "https://arbiscan.io", apiKeys) + } + + fun avalanche(apiKeys: List): TransactionSource { + return etherscan("snowtrace.io", "https://snowtrace.io", apiKeys) + } + + fun gnosis(apiKeys: List): TransactionSource { + return etherscan("gnosisscan.io", "https://gnosisscan.io", apiKeys) + } + + fun base(apiKeys: List): TransactionSource { + return etherscan("basescan.org", "https://basescan.org", apiKeys) + } + + fun zkSync(apiKeys: List): TransactionSource { + return etherscan("era.zksync.network", "https://era.zksync.network", apiKeys) } } diff --git a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/network/GsonTypeAdapters.kt b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/network/GsonTypeAdapters.kt index 8fa2ac7b..08e0c391 100644 --- a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/network/GsonTypeAdapters.kt +++ b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/network/GsonTypeAdapters.kt @@ -130,7 +130,7 @@ class DefaultBlockParameterTypeAdapter : TypeAdapter() { } } -class OptionalTypeAdapter( +class OptionalTypeAdapter( private val type: Type ) : TypeAdapter>() { diff --git a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/spv/core/SpvBlockchain.kt b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/spv/core/SpvBlockchain.kt index 2fd4410c..4a539516 100644 --- a/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/spv/core/SpvBlockchain.kt +++ b/ethereumkit/src/main/java/io/horizontalsystems/ethereumkit/spv/core/SpvBlockchain.kt @@ -122,7 +122,7 @@ class SpvBlockchain( TODO("not implemented") } - override fun rpcSingle(rpc: JsonRpc): Single { + override fun rpcSingle(rpc: JsonRpc): Single { TODO("not implemented") } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 214d0119..083897d1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Apr 19 11:44:39 KGT 2022 +#Fri Nov 14 11:19:08 KGT 2025 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/jitpack.yml b/jitpack.yml index 46c85291..1e41e00b 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,2 +1,2 @@ jdk: - - openjdk11 \ No newline at end of file + - openjdk17 \ No newline at end of file diff --git a/merkleiokit/build.gradle b/merkleiokit/build.gradle index 2a776832..0caa12de 100644 --- a/merkleiokit/build.gradle +++ b/merkleiokit/build.gradle @@ -2,7 +2,6 @@ plugins { id 'com.android.library' id 'kotlin-android' id 'kotlin-kapt' - id 'kotlin-android-extensions' id 'maven-publish' } @@ -17,11 +16,12 @@ afterEvaluate { } android { - compileSdkVersion 32 + namespace 'io.horizontalsystems.merkleiokit' + compileSdkVersion 33 defaultConfig { minSdkVersion 26 - targetSdkVersion 32 + targetSdkVersion 33 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -34,8 +34,13 @@ android { } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { - jvmTarget = '11' + jvmTarget = '17' } } diff --git a/nftkit/build.gradle b/nftkit/build.gradle index 4af97400..7b4b8efa 100644 --- a/nftkit/build.gradle +++ b/nftkit/build.gradle @@ -16,6 +16,7 @@ afterEvaluate { } android { + namespace 'io.horizontalsystems.nftkit' compileSdk 32 defaultConfig { @@ -40,8 +41,13 @@ android { } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { - jvmTarget = '11' + jvmTarget = '17' } } diff --git a/oneinchkit/build.gradle b/oneinchkit/build.gradle index c6d81010..518e3358 100644 --- a/oneinchkit/build.gradle +++ b/oneinchkit/build.gradle @@ -2,7 +2,6 @@ plugins { id 'com.android.library' id 'kotlin-android' id 'kotlin-kapt' - id 'kotlin-android-extensions' id 'maven-publish' } @@ -17,11 +16,12 @@ afterEvaluate { } android { - compileSdkVersion 32 + namespace 'io.horizontalsystems.oneinchkit' + compileSdkVersion 33 defaultConfig { minSdkVersion 26 - targetSdkVersion 32 + targetSdkVersion 33 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -34,8 +34,13 @@ android { } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { - jvmTarget = "11" + jvmTarget = "17" } } diff --git a/uniswapkit/build.gradle b/uniswapkit/build.gradle index ebdf9580..b7906c44 100644 --- a/uniswapkit/build.gradle +++ b/uniswapkit/build.gradle @@ -2,7 +2,6 @@ plugins { id 'com.android.library' id 'kotlin-android' id 'kotlin-kapt' - id 'kotlin-android-extensions' id 'maven-publish' } @@ -17,11 +16,12 @@ afterEvaluate { } android { - compileSdkVersion 32 + namespace 'io.horizontalsystems.uniswapkit' + compileSdkVersion 33 defaultConfig { minSdkVersion 26 - targetSdkVersion 32 + targetSdkVersion 33 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles 'consumer-rules.pro' @@ -34,8 +34,13 @@ android { } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { - jvmTarget = "11" + jvmTarget = "17" } }