mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-17 19:10:51 +02:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2fbd152fb3 | ||
![]() |
a7b178e024 | ||
![]() |
c5a035437b | ||
![]() |
75c550fd19 | ||
![]() |
1b680344b1 | ||
![]() |
3329636d32 | ||
![]() |
77e9bf7c43 | ||
![]() |
40f5c9365e | ||
![]() |
850ba7efef | ||
![]() |
548369ca0b | ||
![]() |
afc0d5b7bc |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,3 +15,4 @@
|
|||||||
/app/alphaStagenet
|
/app/alphaStagenet
|
||||||
/app/prodStagenet
|
/app/prodStagenet
|
||||||
/app/.cxx
|
/app/.cxx
|
||||||
|
/monerujo.id
|
||||||
|
@@ -7,8 +7,8 @@ android {
|
|||||||
applicationId "com.m2049r.xmrwallet"
|
applicationId "com.m2049r.xmrwallet"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 708
|
versionCode 710
|
||||||
versionName "1.17.8 'Druk'"
|
versionName "1.17.10 'Druk'"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
|
@@ -59,7 +59,7 @@ import com.m2049r.xmrwallet.model.NetworkType;
|
|||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
import com.m2049r.xmrwallet.service.WalletService;
|
import com.m2049r.xmrwallet.service.WalletService;
|
||||||
import com.m2049r.xmrwallet.util.ColorHelper;
|
import com.m2049r.xmrwallet.util.ThemeHelper;
|
||||||
import com.m2049r.xmrwallet.util.DayNightMode;
|
import com.m2049r.xmrwallet.util.DayNightMode;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
import com.m2049r.xmrwallet.util.KeyStoreHelper;
|
||||||
@@ -78,7 +78,6 @@ import java.util.Arrays;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -376,7 +375,7 @@ public class LoginActivity extends BaseActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fail(String walletName1, String password, boolean fingerprintUsed) {
|
public void fail(String walletName) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else { // this cannot really happen as we prefilter choices
|
} else { // this cannot really happen as we prefilter choices
|
||||||
@@ -412,7 +411,7 @@ public class LoginActivity extends BaseActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fail(String walletName, String password, boolean fingerprintUsed) {
|
public void fail(String walletName) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else { // this cannot really happen as we prefilter choices
|
} else { // this cannot really happen as we prefilter choices
|
||||||
@@ -707,11 +706,11 @@ public class LoginActivity extends BaseActivity
|
|||||||
break;
|
break;
|
||||||
case NetworkType_Testnet:
|
case NetworkType_Testnet:
|
||||||
toolbar.setSubtitle(getString(R.string.connect_testnet));
|
toolbar.setSubtitle(getString(R.string.connect_testnet));
|
||||||
toolbar.setBackgroundResource(ColorHelper.getThemedResourceId(this, R.attr.colorPrimaryDark));
|
toolbar.setBackgroundResource(ThemeHelper.getThemedResourceId(this, R.attr.colorPrimaryDark));
|
||||||
break;
|
break;
|
||||||
case NetworkType_Stagenet:
|
case NetworkType_Stagenet:
|
||||||
toolbar.setSubtitle(getString(R.string.connect_stagenet));
|
toolbar.setSubtitle(getString(R.string.connect_stagenet));
|
||||||
toolbar.setBackgroundResource(ColorHelper.getThemedResourceId(this, R.attr.colorPrimaryDark));
|
toolbar.setBackgroundResource(ThemeHelper.getThemedResourceId(this, R.attr.colorPrimaryDark));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("NetworkType unknown: " + net);
|
throw new IllegalStateException("NetworkType unknown: " + net);
|
||||||
@@ -1400,7 +1399,7 @@ public class LoginActivity extends BaseActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fail(String walletName, String password, boolean fingerprintUsed) {
|
public void fail(String walletName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@@ -258,7 +258,6 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
|||||||
walletList.addAll(walletInfos);
|
walletList.addAll(walletInfos);
|
||||||
filterList();
|
filterList();
|
||||||
adapter.setInfos(displayedList);
|
adapter.setInfos(displayedList);
|
||||||
adapter.notifyDataSetChanged();
|
|
||||||
|
|
||||||
// deal with Gunther & FAB animation
|
// deal with Gunther & FAB animation
|
||||||
if (displayedList.isEmpty()) {
|
if (displayedList.isEmpty()) {
|
||||||
|
@@ -524,7 +524,7 @@ public class NodeFragment extends Fragment
|
|||||||
.setNegativeButton(getString(R.string.label_cancel),
|
.setNegativeButton(getString(R.string.label_cancel),
|
||||||
(dialog, id) -> {
|
(dialog, id) -> {
|
||||||
closeDialog();
|
closeDialog();
|
||||||
nodesAdapter.dataSetChanged(); // to refresh test results
|
nodesAdapter.setNodes(); // to refresh test results
|
||||||
});
|
});
|
||||||
|
|
||||||
editDialog = alertDialogBuilder.create();
|
editDialog = alertDialogBuilder.create();
|
||||||
@@ -588,7 +588,7 @@ public class NodeFragment extends Fragment
|
|||||||
if (nodeBackup == null) {
|
if (nodeBackup == null) {
|
||||||
nodesAdapter.addNode(nodeInfo);
|
nodesAdapter.addNode(nodeInfo);
|
||||||
} else {
|
} else {
|
||||||
nodesAdapter.dataSetChanged();
|
nodesAdapter.setNodes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,10 +36,12 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import com.google.android.material.transition.MaterialContainerTransform;
|
||||||
import com.m2049r.xmrwallet.data.UserNotes;
|
import com.m2049r.xmrwallet.data.UserNotes;
|
||||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||||
import com.m2049r.xmrwallet.model.Transfer;
|
import com.m2049r.xmrwallet.model.Transfer;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
|
import com.m2049r.xmrwallet.util.ThemeHelper;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
|
|
||||||
@@ -300,7 +302,7 @@ public class TxFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
tvTxXmrToKey.setText(key);
|
tvTxXmrToKey.setText(key);
|
||||||
tvDestinationBtc.setText(userNotes.xmrtoDestination);
|
tvDestinationBtc.setText(userNotes.xmrtoDestination);
|
||||||
tvTxAmountBtc.setText(userNotes.xmrtoAmount + " "+ userNotes.xmrtoCurrency);
|
tvTxAmountBtc.setText(userNotes.xmrtoAmount + " " + userNotes.xmrtoCurrency);
|
||||||
switch (userNotes.xmrtoTag) {
|
switch (userNotes.xmrtoTag) {
|
||||||
case "xmrto":
|
case "xmrto":
|
||||||
tvXmrToSupport.setVisibility(View.GONE);
|
tvXmrToSupport.setVisibility(View.GONE);
|
||||||
@@ -329,6 +331,11 @@ public class TxFragment extends Fragment {
|
|||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setHasOptionsMenu(true);
|
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(getContext(), R.attr.colorSurface));
|
||||||
|
setSharedElementEnterTransition(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -60,7 +60,7 @@ import com.m2049r.xmrwallet.model.TransactionInfo;
|
|||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
import com.m2049r.xmrwallet.service.WalletService;
|
import com.m2049r.xmrwallet.service.WalletService;
|
||||||
import com.m2049r.xmrwallet.util.ColorHelper;
|
import com.m2049r.xmrwallet.util.ThemeHelper;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
import com.m2049r.xmrwallet.util.MoneroThreadPoolExecutor;
|
||||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||||
@@ -337,7 +337,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fail(String walletName, String password, boolean fingerprintUsed) {
|
public void fail(String walletName) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -424,10 +424,10 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
toolbar.setBackgroundResource(R.drawable.backgound_toolbar_mainnet);
|
toolbar.setBackgroundResource(R.drawable.backgound_toolbar_mainnet);
|
||||||
break;
|
break;
|
||||||
case NetworkType_Testnet:
|
case NetworkType_Testnet:
|
||||||
toolbar.setBackgroundResource(ColorHelper.getThemedResourceId(this, R.attr.colorPrimaryDark));
|
toolbar.setBackgroundResource(ThemeHelper.getThemedResourceId(this, R.attr.colorPrimaryDark));
|
||||||
break;
|
break;
|
||||||
case NetworkType_Stagenet:
|
case NetworkType_Stagenet:
|
||||||
toolbar.setBackgroundResource(ColorHelper.getThemedResourceId(this, R.attr.colorPrimaryDark));
|
toolbar.setBackgroundResource(ThemeHelper.getThemedResourceId(this, R.attr.colorPrimaryDark));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unsupported Network: " + WalletManager.getInstance().getNetworkType());
|
throw new IllegalStateException("Unsupported Network: " + WalletManager.getInstance().getNetworkType());
|
||||||
@@ -548,10 +548,10 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTxDetailsRequest(TransactionInfo info) {
|
public void onTxDetailsRequest(View view, TransactionInfo info) {
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putParcelable(TxFragment.ARG_INFO, info);
|
args.putParcelable(TxFragment.ARG_INFO, info);
|
||||||
replaceFragment(new TxFragment(), null, args);
|
replaceFragmentWithTransition(view, new TxFragment(), null, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -828,6 +828,17 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void replaceFragmentWithTransition(View view, Fragment newFragment, String stackName, Bundle extras) {
|
||||||
|
if (extras != null) {
|
||||||
|
newFragment.setArguments(extras);
|
||||||
|
}
|
||||||
|
getSupportFragmentManager().beginTransaction()
|
||||||
|
.addSharedElement(view, getString(R.string.tx_details_transition_name))
|
||||||
|
.replace(R.id.fragment_container, newFragment)
|
||||||
|
.addToBackStack(stackName)
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
void replaceFragment(Fragment newFragment, String stackName, Bundle extras) {
|
void replaceFragment(Fragment newFragment, String stackName, Bundle extras) {
|
||||||
if (extras != null) {
|
if (extras != null) {
|
||||||
newFragment.setArguments(extras);
|
newFragment.setArguments(extras);
|
||||||
@@ -854,7 +865,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fail(String walletName, String password, boolean fingerprintUsed) {
|
public void fail(String walletName) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -42,6 +42,7 @@ import androidx.fragment.app.Fragment;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.github.brnunes.swipeablerecyclerview.SwipeableRecyclerViewTouchListener;
|
import com.github.brnunes.swipeablerecyclerview.SwipeableRecyclerViewTouchListener;
|
||||||
|
import com.google.android.material.transition.MaterialElevationScale;
|
||||||
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
import com.m2049r.xmrwallet.layout.TransactionInfoAdapter;
|
||||||
import com.m2049r.xmrwallet.model.TransactionInfo;
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
@@ -154,7 +155,6 @@ public class WalletFragment extends Fragment
|
|||||||
dismissedTransactions.add(adapter.getItem(position).hash);
|
dismissedTransactions.add(adapter.getItem(position).hash);
|
||||||
adapter.removeItem(position);
|
adapter.removeItem(position);
|
||||||
}
|
}
|
||||||
adapter.notifyDataSetChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -163,7 +163,6 @@ public class WalletFragment extends Fragment
|
|||||||
dismissedTransactions.add(adapter.getItem(position).hash);
|
dismissedTransactions.add(adapter.getItem(position).hash);
|
||||||
adapter.removeItem(position);
|
adapter.removeItem(position);
|
||||||
}
|
}
|
||||||
adapter.notifyDataSetChanged();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -334,7 +333,13 @@ public class WalletFragment extends Fragment
|
|||||||
// Callbacks from TransactionInfoAdapter
|
// Callbacks from TransactionInfoAdapter
|
||||||
@Override
|
@Override
|
||||||
public void onInteraction(final View view, final TransactionInfo infoItem) {
|
public void onInteraction(final View view, final TransactionInfo infoItem) {
|
||||||
activityCallback.onTxDetailsRequest(infoItem);
|
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);
|
||||||
|
activityCallback.onTxDetailsRequest(view, infoItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from activity
|
// called from activity
|
||||||
@@ -352,7 +357,6 @@ public class WalletFragment extends Fragment
|
|||||||
list.add(info);
|
list.add(info);
|
||||||
}
|
}
|
||||||
adapter.setInfos(list);
|
adapter.setInfos(list);
|
||||||
adapter.notifyDataSetChanged();
|
|
||||||
}
|
}
|
||||||
updateStatus(wallet);
|
updateStatus(wallet);
|
||||||
}
|
}
|
||||||
@@ -481,7 +485,7 @@ public class WalletFragment extends Fragment
|
|||||||
|
|
||||||
void onSendRequest();
|
void onSendRequest();
|
||||||
|
|
||||||
void onTxDetailsRequest(TransactionInfo info);
|
void onTxDetailsRequest(View view, TransactionInfo info);
|
||||||
|
|
||||||
boolean isSynced();
|
boolean isSynced();
|
||||||
|
|
||||||
|
@@ -64,12 +64,14 @@ public class Node {
|
|||||||
return hostAddress.hashCode();
|
return hostAddress.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nodes are equal if they are the same host address & are on the same network
|
// Nodes are equal if they are the same host address:port & are on the same network
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (!(other instanceof Node)) return false;
|
if (!(other instanceof Node)) return false;
|
||||||
final Node anotherNode = (Node) other;
|
final Node anotherNode = (Node) other;
|
||||||
return (hostAddress.equals(anotherNode.hostAddress) && (networkType == anotherNode.networkType));
|
return (hostAddress.equals(anotherNode.hostAddress)
|
||||||
|
&& (rpcPort == anotherNode.rpcPort)
|
||||||
|
&& (networkType == anotherNode.networkType));
|
||||||
}
|
}
|
||||||
|
|
||||||
static public Node fromString(String nodeString) {
|
static public Node fromString(String nodeString) {
|
||||||
|
@@ -227,8 +227,7 @@ public class NodeInfo extends Node {
|
|||||||
if (response.isSuccessful()) {
|
if (response.isSuccessful()) {
|
||||||
ResponseBody respBody = response.body(); // closed through Response object
|
ResponseBody respBody = response.body(); // closed through Response object
|
||||||
if ((respBody != null) && (respBody.contentLength() < 2000)) { // sanity check
|
if ((respBody != null) && (respBody.contentLength() < 2000)) { // sanity check
|
||||||
final JSONObject json = new JSONObject(
|
final JSONObject json = new JSONObject(respBody.string());
|
||||||
respBody.string());
|
|
||||||
String rpcVersion = json.getString("jsonrpc");
|
String rpcVersion = json.getString("jsonrpc");
|
||||||
if (!RPC_VERSION.equals(rpcVersion))
|
if (!RPC_VERSION.equals(rpcVersion))
|
||||||
return false;
|
return false;
|
||||||
|
@@ -332,7 +332,7 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
|
|||||||
send();
|
send();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fail(String walletName, String password, boolean fingerprintUsed) {
|
public void fail(String walletName) {
|
||||||
getActivity().runOnUiThread(() -> {
|
getActivity().runOnUiThread(() -> {
|
||||||
bSend.setEnabled(sendCountdown > 0); // allow to try again
|
bSend.setEnabled(sendCountdown > 0); // allow to try again
|
||||||
});
|
});
|
||||||
|
@@ -227,7 +227,7 @@ public class SendConfirmWizardFragment extends SendWizardFragment implements Sen
|
|||||||
send();
|
send();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fail(String walletName, String password, boolean fingerprintUsed) {
|
public void fail(String walletName) {
|
||||||
getActivity().runOnUiThread(() -> {
|
getActivity().runOnUiThread(() -> {
|
||||||
bSend.setEnabled(true); // allow to try again
|
bSend.setEnabled(true); // allow to try again
|
||||||
});
|
});
|
||||||
|
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 yorha-0x
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.m2049r.xmrwallet.layout;
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DiffUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class DiffCallback<T> extends DiffUtil.Callback {
|
||||||
|
|
||||||
|
protected final List<T> mOldList;
|
||||||
|
protected final List<T> mNewList;
|
||||||
|
|
||||||
|
public DiffCallback(List<T> oldList, List<T> newList) {
|
||||||
|
this.mOldList = oldList;
|
||||||
|
this.mNewList = newList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOldListSize() {
|
||||||
|
return mOldList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNewListSize() {
|
||||||
|
return mNewList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean areItemsTheSame(int oldItemPosition, int newItemPosition);
|
||||||
|
|
||||||
|
public abstract boolean areContentsTheSame(int oldItemPosition, int newItemPosition);
|
||||||
|
}
|
@@ -25,11 +25,12 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.DiffUtil;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.data.NodeInfo;
|
import com.m2049r.xmrwallet.data.NodeInfo;
|
||||||
import com.m2049r.xmrwallet.util.ColorHelper;
|
import com.m2049r.xmrwallet.util.ThemeHelper;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
|
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
@@ -53,7 +54,7 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
|
|||||||
private final List<NodeInfo> nodeItems = new ArrayList<>();
|
private final List<NodeInfo> nodeItems = new ArrayList<>();
|
||||||
private final OnInteractionListener listener;
|
private final OnInteractionListener listener;
|
||||||
|
|
||||||
private Context context;
|
private final Context context;
|
||||||
|
|
||||||
public NodeInfoAdapter(Context context, OnInteractionListener listener) {
|
public NodeInfoAdapter(Context context, OnInteractionListener listener) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@@ -63,11 +64,34 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
|
|||||||
TS_FORMATTER.setTimeZone(tz);
|
TS_FORMATTER.setTimeZone(tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class NodeDiff extends DiffCallback<NodeInfo> {
|
||||||
|
|
||||||
|
public NodeDiff(List<NodeInfo> oldList, List<NodeInfo> newList) {
|
||||||
|
super(oldList, newList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
|
||||||
|
return mOldList.get(oldItemPosition).equals(mNewList.get(newItemPosition));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
|
||||||
|
final NodeInfo oldItem = mOldList.get(oldItemPosition);
|
||||||
|
final NodeInfo newItem = mNewList.get(newItemPosition);
|
||||||
|
return (oldItem.getTimestamp() == newItem.getTimestamp())
|
||||||
|
&& (oldItem.isTested() == newItem.isTested())
|
||||||
|
&& (oldItem.isValid() == newItem.isValid())
|
||||||
|
&& (oldItem.getResponseTime() == newItem.getResponseTime())
|
||||||
|
&& (oldItem.isSelected() == newItem.isSelected())
|
||||||
|
&& (oldItem.getName().equals(newItem.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull
|
public @NonNull
|
||||||
ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
View view = LayoutInflater.from(parent.getContext())
|
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_node, parent, false);
|
||||||
.inflate(R.layout.item_node, parent, false);
|
|
||||||
return new ViewHolder(view);
|
return new ViewHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,25 +106,29 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addNode(NodeInfo node) {
|
public void addNode(NodeInfo node) {
|
||||||
|
List<NodeInfo> newItems = new ArrayList<>(nodeItems);
|
||||||
if (!nodeItems.contains(node))
|
if (!nodeItems.contains(node))
|
||||||
nodeItems.add(node);
|
newItems.add(node);
|
||||||
dataSetChanged(); // in case the nodeinfo has changed
|
setNodes(newItems); // in case the nodeinfo has changed
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dataSetChanged() {
|
public void setNodes(Collection<NodeInfo> newItemsCollection) {
|
||||||
Collections.sort(nodeItems, NodeInfo.BestNodeComparator);
|
List<NodeInfo> newItems;
|
||||||
notifyDataSetChanged();
|
if (newItemsCollection != null) {
|
||||||
|
newItems = new ArrayList<>(newItemsCollection);
|
||||||
|
Collections.sort(newItems, NodeInfo.BestNodeComparator);
|
||||||
|
} else {
|
||||||
|
newItems = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
final NodeInfoAdapter.NodeDiff diffCallback = new NodeInfoAdapter.NodeDiff(nodeItems, newItems);
|
||||||
public void setNodes(Collection<NodeInfo> data) {
|
final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
|
||||||
nodeItems.clear();
|
nodeItems.clear();
|
||||||
if (data != null) {
|
nodeItems.addAll(newItems);
|
||||||
for (NodeInfo node : data) {
|
diffResult.dispatchUpdatesTo(this);
|
||||||
if (!nodeItems.contains(node))
|
|
||||||
nodeItems.add(node);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
dataSetChanged();
|
public void setNodes() {
|
||||||
|
setNodes(nodeItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean itemsClickable = true;
|
private boolean itemsClickable = true;
|
||||||
@@ -130,7 +158,7 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
|
|||||||
showStar();
|
showStar();
|
||||||
if (!nodeItem.isFavourite()) {
|
if (!nodeItem.isFavourite()) {
|
||||||
nodeItem.setSelected(false);
|
nodeItem.setSelected(false);
|
||||||
notifyDataSetChanged();
|
setNodes(nodeItems);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
itemView.setOnClickListener(this);
|
itemView.setOnClickListener(this);
|
||||||
@@ -154,7 +182,7 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
|
|||||||
Helper.showTimeDifference(tvIp, nodeItem.getTimestamp());
|
Helper.showTimeDifference(tvIp, nodeItem.getTimestamp());
|
||||||
} else {
|
} else {
|
||||||
tvIp.setText(getResponseErrorText(context, nodeItem.getResponseCode()));
|
tvIp.setText(getResponseErrorText(context, nodeItem.getResponseCode()));
|
||||||
tvIp.setTextColor(ColorHelper.getThemedColor(tvIp.getContext(), R.attr.colorError));
|
tvIp.setTextColor(ThemeHelper.getThemedColor(context, R.attr.colorError));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tvIp.setText(context.getResources().getString(R.string.node_testing, nodeItem.getHostAddress()));
|
tvIp.setText(context.getResources().getString(R.string.node_testing, nodeItem.getHostAddress()));
|
||||||
|
@@ -23,7 +23,9 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.recyclerview.widget.DiffUtil;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
@@ -38,6 +40,7 @@ import java.util.Calendar;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
@@ -46,10 +49,10 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
|
|
||||||
private final SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
private final SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||||
|
|
||||||
private int outboundColour;
|
private final int outboundColour;
|
||||||
private int inboundColour;
|
private final int inboundColour;
|
||||||
private int pendingColour;
|
private final int pendingColour;
|
||||||
private int failedColour;
|
private final int failedColour;
|
||||||
|
|
||||||
public interface OnInteractionListener {
|
public interface OnInteractionListener {
|
||||||
void onInteraction(View view, TransactionInfo item);
|
void onInteraction(View view, TransactionInfo item);
|
||||||
@@ -58,7 +61,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
private final List<TransactionInfo> infoItems;
|
private final List<TransactionInfo> infoItems;
|
||||||
private final OnInteractionListener listener;
|
private final OnInteractionListener listener;
|
||||||
|
|
||||||
private Context context;
|
private final Context context;
|
||||||
|
|
||||||
public TransactionInfoAdapter(Context context, OnInteractionListener listener) {
|
public TransactionInfoAdapter(Context context, OnInteractionListener listener) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@@ -73,10 +76,32 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
DATETIME_FORMATTER.setTimeZone(tz);
|
DATETIME_FORMATTER.setTimeZone(tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TransactionInfoDiff extends DiffCallback<TransactionInfo> {
|
||||||
|
|
||||||
|
public TransactionInfoDiff(List<TransactionInfo> oldList, List<TransactionInfo> newList) {
|
||||||
|
super(oldList, newList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
|
||||||
|
return mOldList.get(oldItemPosition).hash.equals(mNewList.get(newItemPosition).hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
|
||||||
|
final TransactionInfo oldItem = mOldList.get(oldItemPosition);
|
||||||
|
final TransactionInfo newItem = mNewList.get(newItemPosition);
|
||||||
|
return (oldItem.direction == newItem.direction)
|
||||||
|
&& (oldItem.isPending == newItem.isPending)
|
||||||
|
&& (oldItem.isFailed == newItem.isFailed)
|
||||||
|
&& (Objects.equals(oldItem.notes, newItem.notes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
View view = LayoutInflater.from(parent.getContext())
|
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_transaction, parent, false);
|
||||||
.inflate(R.layout.item_transaction, parent, false);
|
|
||||||
return new ViewHolder(view);
|
return new ViewHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,23 +115,26 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
return infoItems.size();
|
return infoItems.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInfos(List<TransactionInfo> data) {
|
public void setInfos(List<TransactionInfo> newItems) {
|
||||||
// TODO do stuff with data so we can really recycle elements (i.e. add only new tx)
|
if (newItems == null) {
|
||||||
// as the TransactionInfo items are always recreated, we cannot recycle
|
newItems = new ArrayList<>();
|
||||||
infoItems.clear();
|
|
||||||
if (data != null) {
|
|
||||||
Timber.d("setInfos %s", data.size());
|
|
||||||
infoItems.addAll(data);
|
|
||||||
Collections.sort(infoItems);
|
|
||||||
} else {
|
|
||||||
Timber.d("setInfos null");
|
Timber.d("setInfos null");
|
||||||
|
} else {
|
||||||
|
Timber.d("setInfos %s", newItems.size());
|
||||||
}
|
}
|
||||||
notifyDataSetChanged();
|
Collections.sort(newItems);
|
||||||
|
final DiffCallback<TransactionInfo> diffCallback = new TransactionInfoAdapter.TransactionInfoDiff(infoItems, newItems);
|
||||||
|
final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
|
||||||
|
infoItems.clear();
|
||||||
|
infoItems.addAll(newItems);
|
||||||
|
diffResult.dispatchUpdatesTo(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeItem(int position) {
|
public void removeItem(int position) {
|
||||||
infoItems.remove(position);
|
List<TransactionInfo> newItems = new ArrayList<>(infoItems);
|
||||||
notifyItemRemoved(position);
|
if (newItems.size() > position)
|
||||||
|
newItems.remove(position);
|
||||||
|
setInfos(newItems); // in case the nodeinfo has changed
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransactionInfo getItem(int position) {
|
public TransactionInfo getItem(int position) {
|
||||||
@@ -139,7 +167,8 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
void bind(int position) {
|
void bind(int position) {
|
||||||
this.infoItem = infoItems.get(position);
|
infoItem = infoItems.get(position);
|
||||||
|
itemView.setTransitionName(context.getString(R.string.tx_item_transition_name, infoItem.hash));
|
||||||
|
|
||||||
UserNotes userNotes = new UserNotes(infoItem.notes);
|
UserNotes userNotes = new UserNotes(infoItem.notes);
|
||||||
if (userNotes.xmrtoKey != null) {
|
if (userNotes.xmrtoKey != null) {
|
||||||
|
@@ -17,8 +17,6 @@
|
|||||||
package com.m2049r.xmrwallet.layout;
|
package com.m2049r.xmrwallet.layout;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.appcompat.widget.PopupMenu;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -26,6 +24,11 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.widget.PopupMenu;
|
||||||
|
import androidx.recyclerview.widget.DiffUtil;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.model.WalletManager;
|
import com.m2049r.xmrwallet.model.WalletManager;
|
||||||
|
|
||||||
@@ -63,6 +66,24 @@ public class WalletInfoAdapter extends RecyclerView.Adapter<WalletInfoAdapter.Vi
|
|||||||
DATETIME_FORMATTER.setTimeZone(tz);
|
DATETIME_FORMATTER.setTimeZone(tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class WalletInfoDiff extends DiffCallback<WalletManager.WalletInfo> {
|
||||||
|
|
||||||
|
public WalletInfoDiff(List<WalletManager.WalletInfo> oldList, List<WalletManager.WalletInfo> newList) {
|
||||||
|
super(oldList, newList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
|
||||||
|
return mOldList.get(oldItemPosition).name.equals(mNewList.get(newItemPosition).name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
|
||||||
|
return mOldList.get(oldItemPosition).compareTo(mNewList.get(newItemPosition)) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
View view = LayoutInflater.from(parent.getContext())
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
@@ -84,18 +105,19 @@ public class WalletInfoAdapter extends RecyclerView.Adapter<WalletInfoAdapter.Vi
|
|||||||
return infoItems.get(position);
|
return infoItems.get(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInfos(List<WalletManager.WalletInfo> data) {
|
public void setInfos(List<WalletManager.WalletInfo> newItems) {
|
||||||
// TODO do stuff with data so we can really recycle elements (i.e. add only new tx)
|
if (newItems == null) {
|
||||||
// as the WalletInfo items are always recreated, we cannot recycle
|
newItems = new ArrayList<>();
|
||||||
infoItems.clear();
|
|
||||||
if (data != null) {
|
|
||||||
Timber.d("setInfos %s", data.size());
|
|
||||||
infoItems.addAll(data);
|
|
||||||
Collections.sort(infoItems);
|
|
||||||
} else {
|
|
||||||
Timber.d("setInfos null");
|
Timber.d("setInfos null");
|
||||||
|
} else {
|
||||||
|
Timber.d("setInfos %s", newItems.size());
|
||||||
}
|
}
|
||||||
notifyDataSetChanged();
|
Collections.sort(newItems);
|
||||||
|
final DiffCallback<WalletManager.WalletInfo> diffCallback = new WalletInfoAdapter.WalletInfoDiff(infoItems, newItems);
|
||||||
|
final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
|
||||||
|
infoItems.clear();
|
||||||
|
infoItems.addAll(newItems);
|
||||||
|
diffResult.dispatchUpdatesTo(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||||
@@ -110,9 +132,7 @@ public class WalletInfoAdapter extends RecyclerView.Adapter<WalletInfoAdapter.Vi
|
|||||||
tvName = itemView.findViewById(R.id.tvName);
|
tvName = itemView.findViewById(R.id.tvName);
|
||||||
tvAddress = itemView.findViewById(R.id.tvAddress);
|
tvAddress = itemView.findViewById(R.id.tvAddress);
|
||||||
ibOptions = itemView.findViewById(R.id.ibOptions);
|
ibOptions = itemView.findViewById(R.id.ibOptions);
|
||||||
ibOptions.setOnClickListener(new View.OnClickListener() {
|
ibOptions.setOnClickListener(view -> {
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
if (popupOpen) return;
|
if (popupOpen) return;
|
||||||
//creating a popup menu
|
//creating a popup menu
|
||||||
PopupMenu popup = new PopupMenu(context, ibOptions);
|
PopupMenu popup = new PopupMenu(context, ibOptions);
|
||||||
@@ -120,25 +140,16 @@ public class WalletInfoAdapter extends RecyclerView.Adapter<WalletInfoAdapter.Vi
|
|||||||
popup.inflate(R.menu.list_context_menu);
|
popup.inflate(R.menu.list_context_menu);
|
||||||
popupOpen = true;
|
popupOpen = true;
|
||||||
//adding click listener
|
//adding click listener
|
||||||
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
popup.setOnMenuItemClickListener(item -> {
|
||||||
@Override
|
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
return listener.onContextInteraction(item, infoItem);
|
return listener.onContextInteraction(item, infoItem);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
//displaying the popup
|
//displaying the popup
|
||||||
popup.show();
|
popup.show();
|
||||||
popup.setOnDismissListener(new PopupMenu.OnDismissListener() {
|
popup.setOnDismissListener(menu -> popupOpen = false);
|
||||||
@Override
|
|
||||||
public void onDismiss(PopupMenu menu) {
|
|
||||||
popupOpen = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
itemView.setOnClickListener(this);
|
itemView.setOnClickListener(this);
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,6 @@ import android.content.ClipData;
|
|||||||
import android.content.ClipDescription;
|
import android.content.ClipDescription;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
@@ -484,7 +483,6 @@ public class Helper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
etPassword.getEditText().addTextChangedListener(new TextWatcher() {
|
etPassword.getEditText().addTextChangedListener(new TextWatcher() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(Editable s) {
|
public void afterTextChanged(Editable s) {
|
||||||
if (etPassword.getError() != null) {
|
if (etPassword.getError() != null) {
|
||||||
@@ -508,8 +506,8 @@ public class Helper {
|
|||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.setPositiveButton(context.getString(R.string.label_ok), null)
|
.setPositiveButton(context.getString(R.string.label_ok), null)
|
||||||
.setNegativeButton(context.getString(R.string.label_cancel),
|
.setNegativeButton(context.getString(R.string.label_cancel),
|
||||||
new DialogInterface.OnClickListener() {
|
(dialog, id) -> {
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
action.fail(wallet);
|
||||||
Helper.hideKeyboardAlways((Activity) context);
|
Helper.hideKeyboardAlways((Activity) context);
|
||||||
cancelSignal.cancel();
|
cancelSignal.cancel();
|
||||||
if (passwordTask != null) {
|
if (passwordTask != null) {
|
||||||
@@ -518,7 +516,6 @@ public class Helper {
|
|||||||
}
|
}
|
||||||
dialog.cancel();
|
dialog.cancel();
|
||||||
openDialog = null;
|
openDialog = null;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
openDialog = alertDialogBuilder.create();
|
openDialog = alertDialogBuilder.create();
|
||||||
|
|
||||||
@@ -561,9 +558,7 @@ public class Helper {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
openDialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
openDialog.setOnShowListener(dialog -> {
|
||||||
@Override
|
|
||||||
public void onShow(DialogInterface dialog) {
|
|
||||||
if (fingerprintAuthAllowed && fingerprintAuthCallback != null) {
|
if (fingerprintAuthAllowed && fingerprintAuthCallback != null) {
|
||||||
tvOpenPrompt.setCompoundDrawablesRelativeWithIntrinsicBounds(icFingerprint, null, null, null);
|
tvOpenPrompt.setCompoundDrawablesRelativeWithIntrinsicBounds(icFingerprint, null, null, null);
|
||||||
tvOpenPrompt.setText(context.getText(R.string.prompt_fingerprint_auth));
|
tvOpenPrompt.setText(context.getText(R.string.prompt_fingerprint_auth));
|
||||||
@@ -573,22 +568,17 @@ public class Helper {
|
|||||||
etPassword.requestFocus();
|
etPassword.requestFocus();
|
||||||
}
|
}
|
||||||
Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
|
Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
|
||||||
button.setOnClickListener(new View.OnClickListener() {
|
button.setOnClickListener(view -> {
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
String pass = etPassword.getEditText().getText().toString();
|
String pass = etPassword.getEditText().getText().toString();
|
||||||
if (passwordTask == null) {
|
if (passwordTask == null) {
|
||||||
passwordTask = new PasswordTask(pass, false);
|
passwordTask = new PasswordTask(pass, false);
|
||||||
passwordTask.execute();
|
passwordTask.execute();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// accept keyboard "ok"
|
// accept keyboard "ok"
|
||||||
etPassword.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
etPassword.getEditText().setOnEditorActionListener((v, actionId, event) -> {
|
||||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
|
||||||
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN))
|
||||||
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
|
|| (actionId == EditorInfo.IME_ACTION_DONE)) {
|
||||||
String pass = etPassword.getEditText().getText().toString();
|
String pass = etPassword.getEditText().getText().toString();
|
||||||
@@ -599,7 +589,6 @@ public class Helper {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Helper.preventScreenshot()) {
|
if (Helper.preventScreenshot()) {
|
||||||
@@ -613,7 +602,7 @@ public class Helper {
|
|||||||
public interface PasswordAction {
|
public interface PasswordAction {
|
||||||
void act(String walletName, String password, boolean fingerprintUsed);
|
void act(String walletName, String password, boolean fingerprintUsed);
|
||||||
|
|
||||||
void fail(String walletName, String password, boolean fingerprintUsed);
|
void fail(String walletName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static private boolean processPasswordEntry(Context context, String walletName, String pass, boolean fingerprintUsed, PasswordAction action) {
|
static private boolean processPasswordEntry(Context context, String walletName, String pass, boolean fingerprintUsed, PasswordAction action) {
|
||||||
@@ -622,7 +611,7 @@ public class Helper {
|
|||||||
action.act(walletName, walletPassword, fingerprintUsed);
|
action.act(walletName, walletPassword, fingerprintUsed);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
action.fail(walletName, walletPassword, fingerprintUsed);
|
action.fail(walletName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -667,8 +656,8 @@ public class Helper {
|
|||||||
}
|
}
|
||||||
view.setText(msg);
|
view.setText(msg);
|
||||||
if (hours >= STALE_NODE_HOURS)
|
if (hours >= STALE_NODE_HOURS)
|
||||||
view.setTextColor(ColorHelper.getThemedColor(view.getContext(), R.attr.colorError));
|
view.setTextColor(ThemeHelper.getThemedColor(view.getContext(), R.attr.colorError));
|
||||||
else
|
else
|
||||||
view.setTextColor(ColorHelper.getThemedColor(view.getContext(), android.R.attr.textColorPrimary));
|
view.setTextColor(ThemeHelper.getThemedColor(view.getContext(), android.R.attr.textColorPrimary));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,19 +17,26 @@
|
|||||||
package com.m2049r.xmrwallet.util;
|
package com.m2049r.xmrwallet.util;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
|
||||||
import com.m2049r.xmrwallet.R;
|
import androidx.annotation.ColorInt;
|
||||||
|
|
||||||
public class ColorHelper {
|
public class ThemeHelper {
|
||||||
static public int getThemedResourceId(Context ctx, int attrId) {
|
static public int getThemedResourceId(Context ctx, int attrId) {
|
||||||
TypedArray styledAttributes = ctx.getTheme().obtainStyledAttributes(R.style.MyMaterialTheme, new int[]{attrId});
|
final TypedValue typedValue = new TypedValue();
|
||||||
return styledAttributes.getResourceId(0, 0);
|
if (ctx.getTheme().resolveAttribute(attrId, typedValue, true))
|
||||||
|
return typedValue.resourceId;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ColorInt
|
||||||
static public int getThemedColor(Context ctx, int attrId) {
|
static public int getThemedColor(Context ctx, int attrId) {
|
||||||
TypedArray styledAttributes = ctx.getTheme().obtainStyledAttributes(R.style.MyMaterialTheme, new int[]{attrId});
|
final TypedValue typedValue = new TypedValue();
|
||||||
return styledAttributes.getColor(0, Color.BLACK);
|
if (ctx.getTheme().resolveAttribute(attrId, typedValue, true))
|
||||||
|
return typedValue.data;
|
||||||
|
else
|
||||||
|
return Color.BLACK;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -42,7 +42,7 @@ import com.m2049r.xmrwallet.model.Wallet;
|
|||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
|
||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
|
||||||
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
|
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
|
||||||
import com.m2049r.xmrwallet.util.ColorHelper;
|
import com.m2049r.xmrwallet.util.ThemeHelper;
|
||||||
import com.m2049r.xmrwallet.util.Helper;
|
import com.m2049r.xmrwallet.util.Helper;
|
||||||
import com.m2049r.xmrwallet.util.ServiceHelper;
|
import com.m2049r.xmrwallet.util.ServiceHelper;
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ public class ExchangeView extends LinearLayout {
|
|||||||
|
|
||||||
// make progress circle gray
|
// make progress circle gray
|
||||||
pbExchange.getIndeterminateDrawable().
|
pbExchange.getIndeterminateDrawable().
|
||||||
setColorFilter(ColorHelper.getThemedColor(getContext(), R.attr.colorPrimaryVariant),
|
setColorFilter(ThemeHelper.getThemedColor(getContext(), R.attr.colorPrimaryVariant),
|
||||||
android.graphics.PorterDuff.Mode.MULTIPLY);
|
android.graphics.PorterDuff.Mode.MULTIPLY);
|
||||||
|
|
||||||
sCurrencyA.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
sCurrencyA.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||||
|
@@ -4,7 +4,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:fillViewport="true">
|
android:fillViewport="true"
|
||||||
|
android:transitionName="@string/tx_details_transition_name">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@@ -141,6 +141,7 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:paddingBottom="80dp"
|
android:paddingBottom="80dp"
|
||||||
|
android:transitionGroup="true"
|
||||||
app:layoutManager="LinearLayoutManager"
|
app:layoutManager="LinearLayoutManager"
|
||||||
tools:listitem="@layout/item_transaction" />
|
tools:listitem="@layout/item_transaction" />
|
||||||
|
|
||||||
|
@@ -1,2 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<integer name="tx_item_transition_duration">300</integer>
|
||||||
|
</resources>
|
||||||
|
@@ -471,4 +471,8 @@
|
|||||||
<item>Ethereum</item>
|
<item>Ethereum</item>
|
||||||
<item>Litecoin</item>
|
<item>Litecoin</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string name="tx_item_transition_name" translatable="false">tx_transition_%1$s</string>
|
||||||
|
<string name="tx_details_transition_name" translatable="false">tx_transition</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -36,7 +36,7 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="AppCard" parent="Widget.MaterialComponents.CardView">
|
<style name="AppCard" parent="Widget.MaterialComponents.CardView">
|
||||||
<item name="cardElevation">8dp</item>
|
<item name="cardElevation">4dp</item>
|
||||||
<item name="cardCornerRadius">1dp</item>
|
<item name="cardCornerRadius">1dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user