diff --git a/app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java b/app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java index 2c0276a3..f533a0c2 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java @@ -16,6 +16,7 @@ package com.m2049r.xmrwallet; +import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; @@ -43,6 +44,7 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.ShareActionProvider; import androidx.core.content.FileProvider; @@ -50,13 +52,13 @@ import androidx.core.view.MenuItemCompat; import androidx.fragment.app.Fragment; import com.google.android.material.textfield.TextInputLayout; +import com.google.android.material.transition.MaterialContainerTransform; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.WriterException; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.QRCodeWriter; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; -import com.m2049r.xmrwallet.BuildConfig; import com.m2049r.xmrwallet.data.BarcodeData; import com.m2049r.xmrwallet.data.Crypto; import com.m2049r.xmrwallet.ledger.LedgerProgressDialog; @@ -64,6 +66,7 @@ import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor; +import com.m2049r.xmrwallet.util.ThemeHelper; import com.m2049r.xmrwallet.widget.ExchangeView; import com.m2049r.xmrwallet.widget.Toolbar; @@ -72,6 +75,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import timber.log.Timber; @@ -84,7 +88,6 @@ public class ReceiveFragment extends Fragment { private ExchangeView evAmount; private TextView tvQrCode; private ImageView ivQrCode; - private View cvQrCode; private ImageView ivQrCodeFull; private EditText etDummy; private ImageButton bCopyAddress; @@ -112,7 +115,6 @@ public class ReceiveFragment extends Fragment { tvAddress = view.findViewById(R.id.tvAddress); etNotes = view.findViewById(R.id.etNotes); evAmount = view.findViewById(R.id.evAmount); - cvQrCode = view.findViewById(R.id.cvQrCode); ivQrCode = view.findViewById(R.id.qrCode); tvQrCode = view.findViewById(R.id.tvQrCode); ivQrCodeFull = view.findViewById(R.id.qrCodeFull); @@ -126,40 +128,31 @@ public class ReceiveFragment extends Fragment { enableCopyAddress(false); enableSubaddressButton(false); - evAmount.setOnNewAmountListener(new ExchangeView.OnNewAmountListener() { - @Override - public void onNewAmount(String xmr) { - Timber.d("new amount = %s", xmr); - generateQr(); - } + evAmount.setOnNewAmountListener(xmr -> { + Timber.d("new amount = %s", xmr); + generateQr(); }); - evAmount.setOnFailedExchangeListener(new ExchangeView.OnFailedExchangeListener() { - @Override - public void onFailedExchange() { - if (isAdded()) { - clearQR(); - Toast.makeText(getActivity(), getString(R.string.message_exchange_failed), Toast.LENGTH_LONG).show(); - } + evAmount.setOnFailedExchangeListener(() -> { + if (isAdded()) { + clearQR(); + Toast.makeText(getActivity(), getString(R.string.message_exchange_failed), Toast.LENGTH_LONG).show(); } }); final EditText notesEdit = etNotes.getEditText(); notesEdit.setRawInputType(InputType.TYPE_CLASS_TEXT); - notesEdit.setOnEditorActionListener(new TextView.OnEditorActionListener() { - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) - || (actionId == EditorInfo.IME_ACTION_DONE)) { - generateQr(); - return true; - } - return false; + notesEdit.setOnEditorActionListener((v, actionId, event) -> { + if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) + || (actionId == EditorInfo.IME_ACTION_DONE)) { + generateQr(); + return true; } + return false; }); notesEdit.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } @Override @@ -169,47 +162,33 @@ public class ReceiveFragment extends Fragment { @Override public void afterTextChanged(Editable s) { - } }); - bSubaddress.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - enableSubaddressButton(false); - enableCopyAddress(false); + bSubaddress.setOnClickListener(v -> { + enableSubaddressButton(false); + enableCopyAddress(false); - final Runnable newAddress = new Runnable() { - public void run() { - getNewSubaddress(); - } - }; + final Runnable newAddress = this::getNewSubaddress; - tvAddress.animate().alpha(0).setDuration(250) - .withEndAction(newAddress).start(); + tvAddress.animate().alpha(0).setDuration(250) + .withEndAction(newAddress).start(); + }); + + view.findViewById(R.id.cvQrCode).setOnClickListener(v -> { + Helper.hideKeyboard(getActivity()); + etDummy.requestFocus(); + if (qrValid) { + ivQrCodeFull.setImageBitmap(((BitmapDrawable) ivQrCode.getDrawable()).getBitmap()); + ivQrCodeFull.setVisibility(View.VISIBLE); + } else { + evAmount.doExchange(); } }); - cvQrCode.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Helper.hideKeyboard(getActivity()); - etDummy.requestFocus(); - if (qrValid) { - ivQrCodeFull.setImageBitmap(((BitmapDrawable) ivQrCode.getDrawable()).getBitmap()); - ivQrCodeFull.setVisibility(View.VISIBLE); - } else { - evAmount.doExchange(); - } - } - }); - - ivQrCodeFull.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - ivQrCodeFull.setImageBitmap(null); - ivQrCodeFull.setVisibility(View.GONE); - } + ivQrCodeFull.setOnClickListener(v -> { + ivQrCodeFull.setImageBitmap(null); + ivQrCodeFull.setVisibility(View.GONE); }); showProgress(); @@ -244,12 +223,17 @@ public class ReceiveFragment extends Fragment { public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); + final MaterialContainerTransform transform = new MaterialContainerTransform(); + transform.setDrawingViewId(R.id.fragment_container); + transform.setDuration(getResources().getInteger(R.integer.tx_item_transition_duration)); + transform.setAllContainerColors(ThemeHelper.getThemedColor(Objects.requireNonNull(getContext()), R.attr.colorSurface)); + setSharedElementEnterTransition(transform); } private ShareActionProvider shareActionProvider; @Override - public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) { + public void onCreateOptionsMenu(@NonNull Menu menu, final MenuInflater inflater) { inflater.inflate(R.menu.receive_menu, menu); super.onCreateOptionsMenu(menu, inflater); @@ -320,7 +304,7 @@ public class ReceiveFragment extends Fragment { } void copyAddress() { - Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_address), tvAddress.getText().toString()); + Helper.clipBoardCopy(Objects.requireNonNull(getActivity()), getString(R.string.label_copy_address), tvAddress.getText().toString()); Toast.makeText(getActivity(), getString(R.string.message_copy_address), Toast.LENGTH_SHORT).show(); } @@ -381,6 +365,7 @@ public class ReceiveFragment extends Fragment { GenerateReviewFragment.ProgressListener progressCallback = null; + @SuppressLint("StaticFieldLeak") private class AsyncShow extends AsyncTask { final private String walletPath; final private String password; @@ -434,8 +419,8 @@ public class ReceiveFragment extends Fragment { new AsyncStore().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR); } + @SuppressLint("StaticFieldLeak") private class AsyncStore extends AsyncTask { - @Override protected Boolean doInBackground(String... params) { if (params.length != 0) return false; @@ -520,12 +505,12 @@ public class ReceiveFragment extends Fragment { canvas.save(); // figure out how to scale the logo float scaleSize = 1.0f; - while ((logoWidth / scaleSize) > (qrWidth / 5) || (logoHeight / scaleSize) > (qrHeight / 5)) { + while ((logoWidth / scaleSize) > (qrWidth / 5.) || (logoHeight / scaleSize) > (qrHeight / 5.)) { scaleSize *= 2; } float sx = 1.0f / scaleSize; - canvas.scale(sx, sx, qrWidth / 2, qrHeight / 2); - canvas.drawBitmap(logo, (qrWidth - logoWidth) / 2, (qrHeight - logoHeight) / 2, null); + canvas.scale(sx, sx, qrWidth / 2f, qrHeight / 2f); + canvas.drawBitmap(logo, (qrWidth - logoWidth) / 2f, (qrHeight - logoHeight) / 2f, null); canvas.restore(); return logoBitmap; } @@ -550,7 +535,7 @@ public class ReceiveFragment extends Fragment { Listener listenerCallback = null; @Override - public void onAttach(Context context) { + public void onAttach(@NonNull Context context) { super.onAttach(context); if (context instanceof Listener) { this.listenerCallback = (Listener) context; @@ -585,6 +570,7 @@ public class ReceiveFragment extends Fragment { new AsyncSubaddress().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR); } + @SuppressLint("StaticFieldLeak") private class AsyncSubaddress extends AsyncTask { private String newSubaddress; @@ -619,11 +605,7 @@ public class ReceiveFragment extends Fragment { wallet.getNumSubaddresses() - 1)); generateQr(); enableCopyAddress(true); - final Runnable resetSize = new Runnable() { - public void run() { - tvAddress.animate().setDuration(125).scaleX(1).scaleY(1).start(); - } - }; + final Runnable resetSize = () -> tvAddress.animate().setDuration(125).scaleX(1).scaleY(1).start(); tvAddress.animate().alpha(1).setDuration(125) .scaleX(1.2f).scaleY(1.2f) .withEndAction(resetSize).start(); diff --git a/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java b/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java index 9973f54c..2e862e1f 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java +++ b/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java @@ -16,6 +16,7 @@ package com.m2049r.xmrwallet; +import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; @@ -43,7 +44,6 @@ import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.navigation.NavigationView; @@ -60,9 +60,9 @@ import com.m2049r.xmrwallet.model.TransactionInfo; import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.service.WalletService; -import com.m2049r.xmrwallet.util.ThemeHelper; import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor; +import com.m2049r.xmrwallet.util.ThemeHelper; import com.m2049r.xmrwallet.widget.Toolbar; import java.util.ArrayList; @@ -206,7 +206,6 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste connectWalletService(walletId, password); } else { finish(); - //throw new IllegalStateException("No extras passed! Panic!"); } } @@ -271,47 +270,36 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.action_rescan: - onWalletRescan(); - return true; - case R.id.action_info: - onWalletDetails(); - return true; - case R.id.action_credits: - CreditsFragment.display(getSupportFragmentManager()); - return true; - case R.id.action_share: - onShareTxInfo(); - return true; - case R.id.action_help_tx_info: - HelpFragment.display(getSupportFragmentManager(), R.string.help_tx_details); - return true; - case R.id.action_help_wallet: - HelpFragment.display(getSupportFragmentManager(), R.string.help_wallet); - return true; - case R.id.action_details_help: - HelpFragment.display(getSupportFragmentManager(), R.string.help_details); - return true; - case R.id.action_details_changepw: - onWalletChangePassword(); - return true; - case R.id.action_help_send: - HelpFragment.display(getSupportFragmentManager(), R.string.help_send); - return true; - case R.id.action_rename: - onAccountRename(); - return true; - case R.id.action_streetmode: - if (isStreetMode()) { // disable streetmode - onDisableStreetMode(); - } else { - onEnableStreetMode(); - } - return true; - default: - return super.onOptionsItemSelected(item); - } + final int itemId = item.getItemId(); + if (itemId == R.id.action_rescan) { + onWalletRescan(); + } else if (itemId == R.id.action_info) { + onWalletDetails(); + } else if (itemId == R.id.action_credits) { + CreditsFragment.display(getSupportFragmentManager()); + } else if (itemId == R.id.action_share) { + onShareTxInfo(); + } else if (itemId == R.id.action_help_tx_info) { + HelpFragment.display(getSupportFragmentManager(), R.string.help_tx_details); + } else if (itemId == R.id.action_help_wallet) { + HelpFragment.display(getSupportFragmentManager(), R.string.help_wallet); + } else if (itemId == R.id.action_details_help) { + HelpFragment.display(getSupportFragmentManager(), R.string.help_details); + } else if (itemId == R.id.action_details_changepw) { + onWalletChangePassword(); + } else if (itemId == R.id.action_help_send) { + HelpFragment.display(getSupportFragmentManager(), R.string.help_send); + } else if (itemId == R.id.action_rename) { + onAccountRename(); + } else if (itemId == R.id.action_streetmode) { + if (isStreetMode()) { // disable streetmode + onDisableStreetMode(); + } else { + onEnableStreetMode(); + } + } else + return super.onOptionsItemSelected(item); + return true; } private void updateStreetMode() { @@ -327,12 +315,9 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste Helper.promptPassword(WalletActivity.this, getWallet().getName(), false, new Helper.PasswordAction() { @Override public void act(String walletName, String password, boolean fingerprintUsed) { - runOnUiThread(new Runnable() { - @Override - public void run() { - enableStreetMode(false); - updateStreetMode(); - } + runOnUiThread(() -> { + enableStreetMode(false); + updateStreetMode(); }); } @@ -423,10 +408,8 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste case NetworkType_Mainnet: toolbar.setBackgroundResource(R.drawable.backgound_toolbar_mainnet); break; - case NetworkType_Testnet: - toolbar.setBackgroundResource(ThemeHelper.getThemedResourceId(this, R.attr.colorPrimaryDark)); - break; case NetworkType_Stagenet: + case NetworkType_Testnet: toolbar.setBackgroundResource(ThemeHelper.getThemedResourceId(this, R.attr.colorPrimaryDark)); break; default: @@ -443,7 +426,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste private WalletService mBoundService = null; private boolean mIsBound = false; - private ServiceConnection mConnection = new ServiceConnection() { + private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the service object we can use to @@ -542,8 +525,8 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste } @Override - public void onSendRequest() { - replaceFragment(SendFragment.newInstance(uri), null, null); + public void onSendRequest(View view) { + replaceFragmentWithTransition(view, SendFragment.newInstance(uri), null, null); uri = null; // only use uri once } @@ -591,18 +574,10 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste onProgress(-1); saveWallet(); // save on first sync synced = true; - runOnUiThread(new Runnable() { - public void run() { - walletFragment.onSynced(); - } - }); + runOnUiThread(walletFragment::onSynced); } } - runOnUiThread(new Runnable() { - public void run() { - walletFragment.onRefreshed(wallet, full); - } - }); + runOnUiThread(() -> walletFragment.onRefreshed(wallet, full)); return true; } catch (ClassCastException ex) { // not in wallet fragment (probably send monero) @@ -614,13 +589,11 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste @Override public void onWalletStored(final boolean success) { - runOnUiThread(new Runnable() { - public void run() { - if (success) { - Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_unloaded), Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_unload_failed), Toast.LENGTH_LONG).show(); - } + runOnUiThread(() -> { + if (success) { + Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_unloaded), Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_unload_failed), Toast.LENGTH_LONG).show(); } }); } @@ -629,30 +602,23 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste @Override public void onWalletOpen(final Wallet.Device device) { - switch (device) { - case Device_Ledger: - runOnUiThread(new Runnable() { - public void run() { - showLedgerProgressDialog(LedgerProgressDialog.TYPE_RESTORE); - } - }); + if (device == Wallet.Device.Device_Ledger) { + runOnUiThread(() -> showLedgerProgressDialog(LedgerProgressDialog.TYPE_RESTORE)); } } @Override public void onWalletStarted(final Wallet.Status walletStatus) { - runOnUiThread(new Runnable() { - public void run() { - dismissProgressDialog(); - if (walletStatus == null) { - // guess what went wrong - Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_failed), Toast.LENGTH_LONG).show(); - } else { - if (Wallet.ConnectionStatus.ConnectionStatus_WrongVersion == walletStatus.getConnectionStatus()) - Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_wrongversion), Toast.LENGTH_LONG).show(); - else if (!walletStatus.isOk()) - Toast.makeText(WalletActivity.this, walletStatus.getErrorString(), Toast.LENGTH_LONG).show(); - } + runOnUiThread(() -> { + dismissProgressDialog(); + if (walletStatus == null) { + // guess what went wrong + Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_failed), Toast.LENGTH_LONG).show(); + } else { + if (Wallet.ConnectionStatus.ConnectionStatus_WrongVersion == walletStatus.getConnectionStatus()) + Toast.makeText(WalletActivity.this, getString(R.string.status_wallet_connect_wrongversion), Toast.LENGTH_LONG).show(); + else if (!walletStatus.isOk()) + Toast.makeText(WalletActivity.this, walletStatus.getErrorString(), Toast.LENGTH_LONG).show(); } }); if ((walletStatus == null) || (Wallet.ConnectionStatus.ConnectionStatus_Connected != walletStatus.getConnectionStatus())) { @@ -665,12 +631,10 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste final WalletFragment walletFragment = (WalletFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_container); - runOnUiThread(new Runnable() { - public void run() { - updateAccountsHeader(); - if (walletFragment != null) { - walletFragment.onLoaded(); - } + runOnUiThread(() -> { + updateAccountsHeader(); + if (walletFragment != null) { + walletFragment.onLoaded(); } }); } @@ -681,17 +645,15 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste try { final SendFragment sendFragment = (SendFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_container); - runOnUiThread(new Runnable() { - public void run() { - dismissProgressDialog(); - PendingTransaction.Status status = pendingTransaction.getStatus(); - if (status != PendingTransaction.Status.Status_Ok) { - String errorText = pendingTransaction.getErrorString(); - getWallet().disposePendingTransaction(); - sendFragment.onCreateTransactionFailed(errorText); - } else { - sendFragment.onTransactionCreated(txTag, pendingTransaction); - } + runOnUiThread(() -> { + dismissProgressDialog(); + PendingTransaction.Status status = pendingTransaction.getStatus(); + if (status != PendingTransaction.Status.Status_Ok) { + String errorText = pendingTransaction.getErrorString(); + getWallet().disposePendingTransaction(); + sendFragment.onCreateTransactionFailed(errorText); + } else { + sendFragment.onTransactionCreated(txTag, pendingTransaction); } }); } catch (ClassCastException ex) { @@ -707,11 +669,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste try { final SendFragment sendFragment = (SendFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_container); - runOnUiThread(new Runnable() { - public void run() { - sendFragment.onSendTransactionFailed(error); - } - }); + runOnUiThread(() -> sendFragment.onSendTransactionFailed(error)); } catch (ClassCastException ex) { // not in spend fragment Timber.d(ex.getLocalizedMessage()); @@ -723,11 +681,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste try { final SendFragment sendFragment = (SendFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_container); - runOnUiThread(new Runnable() { - public void run() { - sendFragment.onTransactionSent(txId); - } - }); + runOnUiThread(() -> sendFragment.onTransactionSent(txId)); } catch (ClassCastException ex) { // not in spend fragment Timber.d(ex.getLocalizedMessage()); @@ -753,18 +707,16 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste @Override public void onProgress(final int n) { - runOnUiThread(new Runnable() { - public void run() { - try { - WalletFragment walletFragment = (WalletFragment) - getSupportFragmentManager().findFragmentByTag(WalletFragment.class.getName()); - if (walletFragment != null) - walletFragment.setProgress(n); - } catch (ClassCastException ex) { - // not in wallet fragment (probably send monero) - Timber.d(ex.getLocalizedMessage()); - // keep calm and carry on - } + runOnUiThread(() -> { + try { + WalletFragment walletFragment = (WalletFragment) + getSupportFragmentManager().findFragmentByTag(WalletFragment.class.getName()); + if (walletFragment != null) + walletFragment.setProgress(n); + } catch (ClassCastException ex) { + // not in wallet fragment (probably send monero) + Timber.d(ex.getLocalizedMessage()); + // keep calm and carry on } }); } @@ -832,8 +784,18 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste if (extras != null) { newFragment.setArguments(extras); } + int transition; + if (newFragment instanceof TxFragment) + transition = R.string.tx_details_transition_name; + else if (newFragment instanceof ReceiveFragment) + transition = R.string.receive_transition_name; + else if (newFragment instanceof SendFragment) + transition = R.string.send_transition_name; + else + throw new IllegalStateException("expecting known transition"); + getSupportFragmentManager().beginTransaction() - .addSharedElement(view, getString(R.string.tx_details_transition_name)) + .addSharedElement(view, getString(transition)) .replace(R.id.fragment_container, newFragment) .addToBackStack(stackName) .commit(); @@ -843,10 +805,11 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste if (extras != null) { newFragment.setArguments(extras); } - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - transaction.replace(R.id.fragment_container, newFragment); - transaction.addToBackStack(stackName); - transaction.commit(); + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.fragment_container, newFragment) + .addToBackStack(stackName) + .commit(); } private void onWalletDetails() { @@ -963,40 +926,28 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste } @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], - @NonNull int[] grantResults) { + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { Timber.d("onRequestPermissionsResult()"); - switch (requestCode) { - case Helper.PERMISSIONS_REQUEST_CAMERA: - // If request is cancelled, the result arrays are empty. - if (grantResults.length > 0 - && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - startScanFragment = true; - } else { - String msg = getString(R.string.message_camera_not_permitted); - Timber.e(msg); - Toast.makeText(this, msg, Toast.LENGTH_LONG).show(); - } - break; - default: + if (requestCode == Helper.PERMISSIONS_REQUEST_CAMERA) { // If request is cancelled, the result arrays are empty. + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + startScanFragment = true; + } else { + String msg = getString(R.string.message_camera_not_permitted); + Timber.e(msg); + Toast.makeText(this, msg, Toast.LENGTH_LONG).show(); + } } } @Override - public void onWalletReceive() { - startReceive(getWallet().getAddress()); - } - - void startReceive(String address) { + public void onWalletReceive(View view) { + final String address = getWallet().getAddress(); Timber.d("startReceive()"); Bundle b = new Bundle(); b.putString("address", address); b.putString("name", getWalletName()); - startReceiveFragment(b); - } - - void startReceiveFragment(Bundle extras) { - replaceFragment(new ReceiveFragment(), null, extras); + replaceFragmentWithTransition(view, new ReceiveFragment(), null, b); Timber.d("ReceiveFragment placed"); } @@ -1031,7 +982,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste return getPreferences(Context.MODE_PRIVATE); } - private List accountIds = new ArrayList<>(); + private final List accountIds = new ArrayList<>(); // generate and cache unique ids for use in accounts list private int getAccountId(int accountIndex) { @@ -1112,39 +1063,33 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste alertDialogBuilder .setCancelable(false) .setPositiveButton(getString(R.string.label_ok), - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - Helper.hideKeyboardAlways(WalletActivity.this); - String newName = etRename.getText().toString(); - wallet.setAccountLabel(newName); - updateAccountName(); - } + (dialog, id) -> { + Helper.hideKeyboardAlways(WalletActivity.this); + String newName = etRename.getText().toString(); + wallet.setAccountLabel(newName); + updateAccountName(); }) .setNegativeButton(getString(R.string.label_cancel), - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - Helper.hideKeyboardAlways(WalletActivity.this); - dialog.cancel(); - } + (dialog, id) -> { + Helper.hideKeyboardAlways(WalletActivity.this); + dialog.cancel(); }); final AlertDialog dialog = alertDialogBuilder.create(); Helper.showKeyboard(dialog); // accept keyboard "ok" - etRename.setOnEditorActionListener(new TextView.OnEditorActionListener() { - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) - || (actionId == EditorInfo.IME_ACTION_DONE)) { - Helper.hideKeyboardAlways(WalletActivity.this); - String newName = etRename.getText().toString(); - dialog.cancel(); - wallet.setAccountLabel(newName); - updateAccountName(); - return false; - } + etRename.setOnEditorActionListener((v, actionId, event) -> { + if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) + || (actionId == EditorInfo.IME_ACTION_DONE)) { + Helper.hideKeyboardAlways(WalletActivity.this); + String newName = etRename.getText().toString(); + dialog.cancel(); + wallet.setAccountLabel(newName); + updateAccountName(); return false; } + return false; }); dialog.show(); @@ -1153,19 +1098,17 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste @Override public boolean onNavigationItemSelected(MenuItem item) { final int id = item.getItemId(); - switch (id) { - case R.id.account_new: - addAccount(); - break; - default: - Timber.d("NavigationDrawer ID=%d", id); - int accountIdx = accountIds.indexOf(id); - if (accountIdx >= 0) { - Timber.d("found @%d", accountIdx); - getWallet().setAccountIndex(accountIdx); - } - forceUpdate(); - drawer.closeDrawer(GravityCompat.START); + if (id == R.id.account_new) { + addAccount(); + } else { + Timber.d("NavigationDrawer ID=%d", id); + int accountIdx = accountIds.indexOf(id); + if (accountIdx >= 0) { + Timber.d("found @%d", accountIdx); + getWallet().setAccountIndex(accountIdx); + } + forceUpdate(); + drawer.closeDrawer(GravityCompat.START); } return true; } @@ -1174,6 +1117,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste new AsyncAddAccount().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR); } + @SuppressLint("StaticFieldLeak") private class AsyncAddAccount extends AsyncTask { boolean dialogOpened = false; diff --git a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java index eee13d92..60e0f46d 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java @@ -36,6 +36,7 @@ import android.widget.ProgressBar; import android.widget.Spinner; import android.widget.TextView; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; @@ -57,13 +58,14 @@ import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import timber.log.Timber; public class WalletFragment extends Fragment implements TransactionInfoAdapter.OnInteractionListener { private TransactionInfoAdapter adapter; - private NumberFormat formatter = NumberFormat.getInstance(); + private final NumberFormat formatter = NumberFormat.getInstance(); private TextView tvStreetView; private LinearLayout llBalance; @@ -80,7 +82,7 @@ public class WalletFragment extends Fragment private Spinner sCurrency; - private List dismissedTransactions = new ArrayList<>(); + private final List dismissedTransactions = new ArrayList<>(); public void resetDismissedTransactions() { dismissedTransactions.clear(); @@ -93,7 +95,7 @@ public class WalletFragment extends Fragment } @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { if (activityCallback.hasWallet()) inflater.inflate(R.menu.wallet_menu, menu); super.onCreateOptionsMenu(menu, inflater); @@ -104,6 +106,13 @@ public class WalletFragment extends Fragment Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_wallet, container, false); + final MaterialElevationScale exitTransition = new MaterialElevationScale(false); + exitTransition.setDuration(getResources().getInteger(R.integer.tx_item_transition_duration)); + setExitTransition(exitTransition); + final MaterialElevationScale reenterTransition = new MaterialElevationScale(true); + reenterTransition.setDuration(getResources().getInteger(R.integer.tx_item_transition_duration)); + setReenterTransition(reenterTransition); + ivStreetGunther = view.findViewById(R.id.ivStreetGunther); tvStreetView = view.findViewById(R.id.tvStreetView); llBalance = view.findViewById(R.id.llBalance); @@ -124,7 +133,7 @@ public class WalletFragment extends Fragment List currencies = new ArrayList<>(); currencies.add(Helper.BASE_CRYPTO); currencies.addAll(Arrays.asList(getResources().getStringArray(R.array.currency))); - ArrayAdapter spinnerAdapter = new ArrayAdapter<>(getContext(), R.layout.item_spinner_balance, currencies); + ArrayAdapter spinnerAdapter = new ArrayAdapter<>(Objects.requireNonNull(getContext()), R.layout.item_spinner_balance, currencies); spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); sCurrency.setAdapter(spinnerAdapter); @@ -169,18 +178,8 @@ public class WalletFragment extends Fragment recyclerView.addOnItemTouchListener(swipeTouchListener); - bSend.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - activityCallback.onSendRequest(); - } - }); - bReceive.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - activityCallback.onWalletReceive(); - } - }); + bSend.setOnClickListener(v -> activityCallback.onSendRequest(v)); + bReceive.setOnClickListener(v -> activityCallback.onWalletReceive(v)); sCurrency.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override @@ -203,6 +202,16 @@ public class WalletFragment extends Fragment return view; } + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + postponeEnterTransition(); + view.getViewTreeObserver().addOnPreDrawListener(() -> { + startPostponedEnterTransition(); + return true; + }); + } + void showBalance(String balance) { tvBalance.setText(balance); final boolean streetMode = activityCallback.isStreetMode(); @@ -260,24 +269,14 @@ public class WalletFragment extends Fragment @Override public void onSuccess(final ExchangeRate exchangeRate) { if (isAdded()) - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - exchange(exchangeRate); - } - }); + new Handler(Looper.getMainLooper()).post(() -> exchange(exchangeRate)); } @Override public void onError(final Exception e) { Timber.e(e.getLocalizedMessage()); if (isAdded()) - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - exchangeFailed(); - } - }); + new Handler(Looper.getMainLooper()).post(() -> exchangeFailed()); } }); } else { @@ -418,7 +417,6 @@ public class WalletFragment extends Fragment void setActivityTitle(Wallet wallet) { if (wallet == null) return; walletTitle = wallet.getName(); - String watchOnly = (wallet.isWatchOnly() ? getString(R.string.label_watchonly) : ""); walletSubtitle = wallet.getAccountLabel(); activityCallback.setTitle(walletTitle, walletSubtitle); Timber.d("wallet title is %s", walletTitle); @@ -442,7 +440,7 @@ public class WalletFragment extends Fragment balance = wallet.getBalance(); unlockedBalance = wallet.getUnlockedBalance(); refreshBalance(); - String sync = ""; + String sync; if (!activityCallback.hasBoundService()) throw new IllegalStateException("WalletService not bound."); Wallet.ConnectionStatus daemonConnected = activityCallback.getConnectionStatus(); @@ -483,7 +481,7 @@ public class WalletFragment extends Fragment long getDaemonHeight(); //mBoundService.getDaemonHeight(); - void onSendRequest(); + void onSendRequest(View view); void onTxDetailsRequest(View view, TransactionInfo info); @@ -497,7 +495,7 @@ public class WalletFragment extends Fragment String getTxKey(String txId); - void onWalletReceive(); + void onWalletReceive(View view); boolean hasWallet(); @@ -511,7 +509,7 @@ public class WalletFragment extends Fragment } @Override - public void onAttach(Context context) { + public void onAttach(@NonNull Context context) { super.onAttach(context); if (context instanceof Listener) { this.activityCallback = (Listener) context; @@ -554,7 +552,7 @@ public class WalletFragment extends Fragment //TODO figure out why gunther disappears on return from send although he is still set if (enable) { if (streetGunther == null) - streetGunther = ContextCompat.getDrawable(getContext(), R.drawable.ic_gunther_streetmode); + streetGunther = ContextCompat.getDrawable(Objects.requireNonNull(getContext()), R.drawable.ic_gunther_streetmode); ivStreetGunther.setImageDrawable(streetGunther); } else ivStreetGunther.setImageDrawable(null); diff --git a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendFragment.java b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendFragment.java index 903aff0f..d480cc74 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/fragment/send/SendFragment.java @@ -36,6 +36,7 @@ import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.viewpager.widget.ViewPager; +import com.google.android.material.transition.MaterialContainerTransform; import com.m2049r.xmrwallet.OnBackPressedListener; import com.m2049r.xmrwallet.OnUriScannedListener; import com.m2049r.xmrwallet.R; @@ -49,10 +50,12 @@ import com.m2049r.xmrwallet.layout.SpendViewPager; import com.m2049r.xmrwallet.model.PendingTransaction; import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Notice; +import com.m2049r.xmrwallet.util.ThemeHelper; import com.m2049r.xmrwallet.widget.DotBar; import com.m2049r.xmrwallet.widget.Toolbar; import java.lang.ref.WeakReference; +import java.util.Objects; import timber.log.Timber; @@ -309,7 +312,7 @@ public class SendFragment extends Fragment SparseArray> myFragments = new SparseArray<>(); public SpendPagerAdapter(FragmentManager fm) { - super(fm); + super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); } public void addSuccess() { @@ -538,14 +541,18 @@ public class SendFragment extends Fragment enableNavigation(); } - @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); + final MaterialContainerTransform transform = new MaterialContainerTransform(); + transform.setDrawingViewId(R.id.fragment_container); + transform.setDuration(getResources().getInteger(R.integer.tx_item_transition_duration)); + transform.setAllContainerColors(ThemeHelper.getThemedColor(Objects.requireNonNull(getContext()), R.attr.colorSurface)); + setSharedElementEnterTransition(transform); } @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.send_menu, menu); super.onCreateOptionsMenu(menu, inflater); } diff --git a/app/src/main/res/layout/fragment_receive.xml b/app/src/main/res/layout/fragment_receive.xml index 69e52d2e..f3cee81a 100644 --- a/app/src/main/res/layout/fragment_receive.xml +++ b/app/src/main/res/layout/fragment_receive.xml @@ -3,7 +3,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:transitionName="@string/receive_transition_name"> + android:orientation="vertical" + android:transitionName="@string/send_transition_name">