diff --git a/app/build.gradle b/app/build.gradle index a455070..1ecd250 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'com.android.application' +apply plugin: "androidx.navigation.safeargs" android { compileSdkVersion 31 diff --git a/app/src/main/java/com/m2049r/xmrwallet/fragment/home/HomeFragment.java b/app/src/main/java/com/m2049r/xmrwallet/fragment/home/HomeFragment.java index 50654f1..ff13ca1 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/fragment/home/HomeFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/fragment/home/HomeFragment.java @@ -1,7 +1,5 @@ package com.m2049r.xmrwallet.fragment.home; -import android.content.Intent; -import android.net.Uri; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -18,6 +16,7 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.lifecycle.ViewModelProvider; +import androidx.navigation.NavDirections; import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -33,7 +32,6 @@ import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.service.BalanceService; import com.m2049r.xmrwallet.service.BlockchainService; import com.m2049r.xmrwallet.service.HistoryService; -import com.m2049r.xmrwallet.util.UriData; import java.util.Collections; @@ -68,7 +66,7 @@ public class HomeFragment extends Fragment implements TransactionInfoAdapter.TxI Button receiveButton = view.findViewById(R.id.receive_button); settingsImageView.setOnClickListener(view12 -> { - navigate(R.id.settings_fragment); + navigate(HomeFragmentDirections.navToSettings()); }); sendButton.setOnClickListener(view1 -> { @@ -152,10 +150,11 @@ public class HomeFragment extends Fragment implements TransactionInfoAdapter.TxI @Override public void onClickTransaction(TransactionInfo txInfo) { - System.out.println(txInfo.hash); + NavDirections directions = HomeFragmentDirections.navToTransaction(txInfo); + navigate(directions); } - private void navigate(int destination) { + private void navigate(NavDirections destination) { FragmentActivity activity = getActivity(); if (activity != null) { FragmentManager fm = activity.getSupportFragmentManager(); diff --git a/app/src/main/java/com/m2049r/xmrwallet/fragment/transaction/TransactionFragment.java b/app/src/main/java/com/m2049r/xmrwallet/fragment/transaction/TransactionFragment.java new file mode 100644 index 0000000..1ec536f --- /dev/null +++ b/app/src/main/java/com/m2049r/xmrwallet/fragment/transaction/TransactionFragment.java @@ -0,0 +1,115 @@ +package com.m2049r.xmrwallet.fragment.transaction; + +import static com.m2049r.xmrwallet.util.DateHelper.DATETIME_FORMATTER; + +import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; +import androidx.navigation.fragment.NavHostFragment; + +import com.m2049r.xmrwallet.MainActivity; +import com.m2049r.xmrwallet.R; +import com.m2049r.xmrwallet.model.TransactionInfo; +import com.m2049r.xmrwallet.model.Wallet; +import com.m2049r.xmrwallet.model.WalletManager; +import com.m2049r.xmrwallet.service.PrefService; +import com.m2049r.xmrwallet.util.Constants; +import com.m2049r.xmrwallet.util.Helper; + +import java.io.File; +import java.util.Calendar; +import java.util.Date; +import java.util.Objects; +import java.util.TimeZone; + +public class TransactionFragment extends Fragment { + + private TransactionViewModel mViewModel; + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_transaction, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + Calendar cal = Calendar.getInstance(); + TimeZone tz = cal.getTimeZone(); //get the local time zone. + DATETIME_FORMATTER.setTimeZone(tz); + + mViewModel = new ViewModelProvider(this).get(TransactionViewModel.class); + Bundle args = getArguments(); + if(args != null) { + TransactionInfo txInfo = getArguments().getParcelable(Constants.NAV_ARG_TXINFO); + mViewModel.init(txInfo); + } + + bindObservers(view); + bindListeners(view); + } + + private void bindListeners(View view) { + ImageButton copyTxHashImageButton = view.findViewById(R.id.copy_txhash_imagebutton); + copyTxHashImageButton.setOnClickListener(view1 -> { + TransactionInfo txInfo = mViewModel.transaction.getValue(); + if(txInfo != null) { + Helper.clipBoardCopy(getContext(), "transaction_hash", txInfo.hash); + } + }); + + ImageButton copyTxAddressImageButton = view.findViewById(R.id.copy_txaddress_imagebutton); + copyTxAddressImageButton.setOnClickListener(view1 -> { + TransactionInfo txInfo = mViewModel.transaction.getValue(); + if(txInfo != null) { + String destination = mViewModel.destination.getValue(); + if(destination != null) { + Helper.clipBoardCopy(getContext(), "transaction_address", destination); + } + } + }); + } + + private void bindObservers(View view) { + TextView txHashTextView = view.findViewById(R.id.transaction_hash_textview); + TextView txConfTextView = view.findViewById(R.id.transaction_conf_textview); + TextView txAddressTextView = view.findViewById(R.id.transaction_address_textview); + ImageButton copyTxAddressImageButton = view.findViewById(R.id.copy_txaddress_imagebutton); + TextView txDateTextView = view.findViewById(R.id.transaction_date_textview); + + mViewModel.transaction.observe(getViewLifecycleOwner(), transactionInfo -> { + txHashTextView.setText(transactionInfo.hash); + txConfTextView.setText(""+transactionInfo.confirmations); + txDateTextView.setText(getDateTime(transactionInfo.timestamp)); + }); + + mViewModel.destination.observe(getViewLifecycleOwner(), s -> { + txAddressTextView.setText(Objects.requireNonNullElse(s, "-")); + if(s == null) { + copyTxAddressImageButton.setVisibility(View.INVISIBLE); + } + }); + } + + private String getDateTime(long time) { + return DATETIME_FORMATTER.format(new Date(time * 1000)); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/m2049r/xmrwallet/fragment/transaction/TransactionViewModel.java b/app/src/main/java/com/m2049r/xmrwallet/fragment/transaction/TransactionViewModel.java new file mode 100644 index 0000000..38342f0 --- /dev/null +++ b/app/src/main/java/com/m2049r/xmrwallet/fragment/transaction/TransactionViewModel.java @@ -0,0 +1,35 @@ +package com.m2049r.xmrwallet.fragment.transaction; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +import com.m2049r.xmrwallet.model.TransactionInfo; +import com.m2049r.xmrwallet.model.Transfer; +import com.m2049r.xmrwallet.model.Wallet; +import com.m2049r.xmrwallet.model.WalletManager; +import com.m2049r.xmrwallet.service.HistoryService; + +public class TransactionViewModel extends ViewModel { + private final MutableLiveData _transaction = new MutableLiveData<>(null); + public LiveData transaction = _transaction; + private final MutableLiveData _destination = new MutableLiveData<>(null); + public LiveData destination = _destination; + + public void init(TransactionInfo info) { + Wallet wallet = WalletManager.getInstance().getWallet(); + if(info.txKey == null) { + info.txKey = wallet.getTxKey(info.hash); + } + if(info.address == null && info.direction == TransactionInfo.Direction.Direction_In) { + _destination.setValue(wallet.getSubaddress(info.accountIndex, info.addressIndex)); + } else if(info.address != null && info.direction == TransactionInfo.Direction.Direction_In) { + _destination.setValue(info.address); + } else if(info.transfers != null && info.direction == TransactionInfo.Direction.Direction_Out) { + if(info.transfers.size() == 1) { + _destination.setValue(info.transfers.get(0).address); + } + } + this._transaction.setValue(info); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/Constants.java b/app/src/main/java/com/m2049r/xmrwallet/util/Constants.java index 7295ad9..11d66e0 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/util/Constants.java +++ b/app/src/main/java/com/m2049r/xmrwallet/util/Constants.java @@ -12,4 +12,5 @@ public class Constants { public static final String URI_PREFIX = "monero:"; public static final String URI_ARG_AMOUNT = "tx_amount"; + public static final String NAV_ARG_TXINFO = "nav_arg_txinfo"; } diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/DateHelper.java b/app/src/main/java/com/m2049r/xmrwallet/util/DateHelper.java index e791cea..3b83f45 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/util/DateHelper.java +++ b/app/src/main/java/com/m2049r/xmrwallet/util/DateHelper.java @@ -21,7 +21,7 @@ import java.text.SimpleDateFormat; import java.util.Date; public class DateHelper { - public static final SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + public static final SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static Date parse(String dateString) throws ParseException { return DATETIME_FORMATTER.parse(dateString.replaceAll("Z$", "+0000")); diff --git a/app/src/main/res/layout/fragment_transaction.xml b/app/src/main/res/layout/fragment_transaction.xml new file mode 100644 index 0000000..847592f --- /dev/null +++ b/app/src/main/res/layout/fragment_transaction.xml @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/main_nav.xml b/app/src/main/res/navigation/main_nav.xml index 4fe4770..859354a 100644 --- a/app/src/main/res/navigation/main_nav.xml +++ b/app/src/main/res/navigation/main_nav.xml @@ -12,26 +12,33 @@ - + + + android:name="nav_arg_txinfo" + app:argType="com.m2049r.xmrwallet.model.TransactionInfo" + app:nullable="true"/> + tools:layout="@layout/fragment_settings" /> + tools:layout="@layout/fragment_settings" /> + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c0e3ebd..e43af4d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -80,6 +80,7 @@ Nodes My Monero Node 127.0.0.1:18081 + Transaction 127.0.0.1 9050 @@ -89,4 +90,8 @@ Connected Disconnected Version mismatch + Transaction Hash + Destination + Confirmations + Date diff --git a/build.gradle b/build.gradle index 175257d..26dab65 100644 --- a/build.gradle +++ b/build.gradle @@ -6,6 +6,8 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:7.2.0' + classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.5.2" + } }