You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
247 lines
8.1 KiB
247 lines
8.1 KiB
/*
|
|
* Copyright (c) 2017 m2049r
|
|
*
|
|
* 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;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.content.Context;
|
|
import android.os.AsyncTask;
|
|
import android.os.Bundle;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.widget.Toast;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.fragment.app.Fragment;
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
|
|
import com.google.android.material.transition.MaterialElevationScale;
|
|
import com.m2049r.xmrwallet.data.Subaddress;
|
|
import com.m2049r.xmrwallet.layout.SubaddressInfoAdapter;
|
|
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
|
|
import com.m2049r.xmrwallet.model.TransactionInfo;
|
|
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.widget.Toolbar;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
import timber.log.Timber;
|
|
|
|
public class SubaddressFragment extends Fragment implements SubaddressInfoAdapter.OnInteractionListener,
|
|
View.OnClickListener {
|
|
static public final String KEY_MODE = "mode";
|
|
static public final String MODE_MANAGER = "manager";
|
|
|
|
private SubaddressInfoAdapter adapter;
|
|
|
|
private Listener activityCallback;
|
|
|
|
private Wallet wallet;
|
|
|
|
// Container Activity must implement this interface
|
|
public interface Listener {
|
|
void onSubaddressSelected(Subaddress subaddress);
|
|
|
|
void setSubtitle(String title);
|
|
|
|
void setToolbarButton(int type);
|
|
|
|
void showSubaddress(View view, final int subaddressIndex);
|
|
}
|
|
|
|
public interface ProgressListener {
|
|
void showProgressDialog(int msgId);
|
|
|
|
void showLedgerProgressDialog(int mode);
|
|
|
|
void dismissProgressDialog();
|
|
}
|
|
|
|
private ProgressListener progressCallback = null;
|
|
|
|
@Override
|
|
public void onAttach(@NonNull Context context) {
|
|
super.onAttach(context);
|
|
if (context instanceof ProgressListener) {
|
|
progressCallback = (ProgressListener) context;
|
|
}
|
|
if (context instanceof Listener) {
|
|
activityCallback = (Listener) context;
|
|
} else {
|
|
throw new ClassCastException(context.toString()
|
|
+ " must implement Listener");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onPause() {
|
|
Timber.d("onPause()");
|
|
super.onPause();
|
|
}
|
|
|
|
@Override
|
|
public void onResume() {
|
|
super.onResume();
|
|
activityCallback.setSubtitle(getString(R.string.subbaddress_title));
|
|
activityCallback.setToolbarButton(Toolbar.BUTTON_BACK);
|
|
}
|
|
|
|
@Override
|
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
Bundle savedInstanceState) {
|
|
Timber.d("onCreateView");
|
|
|
|
final Bundle b = getArguments();
|
|
managerMode = ((b != null) && (MODE_MANAGER.equals(b.getString(KEY_MODE))));
|
|
|
|
View view = inflater.inflate(R.layout.fragment_subaddress, 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);
|
|
|
|
view.findViewById(R.id.fab).setOnClickListener(this);
|
|
|
|
if (managerMode) {
|
|
view.findViewById(R.id.tvInstruction).setVisibility(View.GONE);
|
|
view.findViewById(R.id.tvHint).setVisibility(View.GONE);
|
|
}
|
|
|
|
final RecyclerView list = view.findViewById(R.id.list);
|
|
adapter = new SubaddressInfoAdapter(getActivity(), this);
|
|
list.setAdapter(adapter);
|
|
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
|
@Override
|
|
public void onItemRangeInserted(int positionStart, int itemCount) {
|
|
list.scrollToPosition(positionStart);
|
|
}
|
|
});
|
|
|
|
Helper.hideKeyboard(getActivity());
|
|
|
|
wallet = WalletManager.getInstance().getWallet();
|
|
|
|
loadList();
|
|
|
|
return view;
|
|
}
|
|
|
|
@Override
|
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
|
super.onViewCreated(view, savedInstanceState);
|
|
postponeEnterTransition();
|
|
view.getViewTreeObserver().addOnPreDrawListener(() -> {
|
|
startPostponedEnterTransition();
|
|
return true;
|
|
});
|
|
}
|
|
|
|
public void loadList() {
|
|
Timber.d("loadList()");
|
|
final int numSubaddresses = wallet.getNumSubaddresses();
|
|
final List<Subaddress> list = new ArrayList<>();
|
|
for (int i = 0; i < numSubaddresses; i++) {
|
|
list.add(wallet.getSubaddressObject(i));
|
|
}
|
|
adapter.setInfos(list);
|
|
}
|
|
|
|
@Override
|
|
public void onClick(View v) {
|
|
int id = v.getId();
|
|
if (id == R.id.fab) {
|
|
getNewSubaddress();
|
|
}
|
|
}
|
|
|
|
private int lastUsedSubaddress() {
|
|
int lastUsedSubaddress = 0;
|
|
for (TransactionInfo info : wallet.getHistory().getAll()) {
|
|
if (info.addressIndex > lastUsedSubaddress)
|
|
lastUsedSubaddress = info.addressIndex;
|
|
}
|
|
return lastUsedSubaddress;
|
|
}
|
|
|
|
private void getNewSubaddress() {
|
|
final int maxSubaddresses = lastUsedSubaddress() + wallet.getDeviceType().getSubaddressLookahead();
|
|
if (wallet.getNumSubaddresses() < maxSubaddresses)
|
|
new AsyncSubaddress().executeOnExecutor(MoneroThreadPoolExecutor.MONERO_THREAD_POOL_EXECUTOR);
|
|
else
|
|
Toast.makeText(getActivity(), getString(R.string.max_subaddress_warning), Toast.LENGTH_LONG).show();
|
|
}
|
|
|
|
@SuppressLint("StaticFieldLeak")
|
|
@RequiredArgsConstructor
|
|
private class AsyncSubaddress extends AsyncTask<Void, Void, Boolean> {
|
|
boolean dialogOpened = false;
|
|
|
|
@Override
|
|
protected void onPreExecute() {
|
|
super.onPreExecute();
|
|
if ((wallet.getDeviceType() == Wallet.Device.Device_Ledger) && (progressCallback != null)) {
|
|
progressCallback.showLedgerProgressDialog(LedgerProgressDialog.TYPE_SUBADDRESS);
|
|
dialogOpened = true;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected Boolean doInBackground(Void... params) {
|
|
if (params.length != 0) return false;
|
|
wallet.getNewSubaddress();
|
|
wallet.store();
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
protected void onPostExecute(Boolean result) {
|
|
super.onPostExecute(result);
|
|
if (dialogOpened)
|
|
progressCallback.dismissProgressDialog();
|
|
if (!isAdded()) // never mind then
|
|
return;
|
|
loadList();
|
|
}
|
|
}
|
|
|
|
boolean managerMode = false;
|
|
|
|
// Callbacks from SubaddressInfoAdapter
|
|
@Override
|
|
public void onInteraction(final View view, final Subaddress subaddress) {
|
|
if (managerMode)
|
|
activityCallback.showSubaddress(view, subaddress.getAddressIndex());
|
|
else
|
|
activityCallback.onSubaddressSelected(subaddress); // also closes the fragment with onBackpressed()
|
|
}
|
|
|
|
@Override
|
|
public boolean onLongInteraction(View view, Subaddress subaddress) {
|
|
activityCallback.showSubaddress(view, subaddress.getAddressIndex());
|
|
return false;
|
|
}
|
|
}
|