diff --git a/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java b/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java index 399ff1c..0f06bba 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java +++ b/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java @@ -154,7 +154,7 @@ public class LoginActivity extends AppCompatActivity @Override public void onWalletRename(String walletName) { Log.d(TAG, "rename for wallet ." + walletName + "."); - final File walletFile = Helper.getWalletFile(LoginActivity.this, walletName); + final File walletFile = Helper.getWalletFile(this, walletName); LayoutInflater li = LayoutInflater.from(this); View promptsView = li.inflate(R.layout.prompt_rename, null); @@ -174,7 +174,9 @@ public class LoginActivity extends AppCompatActivity public void onClick(DialogInterface dialog, int id) { Helper.hideKeyboardAlways(LoginActivity.this); String newName = etRename.getText().toString(); - renameWallet(walletFile, newName); //TODO error + if (!renameWallet(walletFile, newName)) { + Toast.makeText(LoginActivity.this, getString(R.string.rename_failed), Toast.LENGTH_LONG).show(); + } reloadWalletList(); } }) @@ -196,7 +198,9 @@ public class LoginActivity extends AppCompatActivity Helper.hideKeyboardAlways(LoginActivity.this); String newName = etRename.getText().toString(); dialog.cancel(); - renameWallet(walletFile, newName); //TODO error + if (!renameWallet(walletFile, newName)) { + Toast.makeText(LoginActivity.this, getString(R.string.rename_failed), Toast.LENGTH_LONG).show(); + } reloadWalletList(); return false; } @@ -207,6 +211,63 @@ public class LoginActivity extends AppCompatActivity dialog.show(); } + @Override + public boolean onWalletBackup(String walletName) { + Log.d(TAG, "backup for wallet ." + walletName + "."); + File backupFolder = new File(getStorageRoot(), ".backups"); + if (!backupFolder.exists()) { + if (!backupFolder.mkdir()) { + Log.e(TAG, "Cannot create backup dir " + backupFolder.getAbsolutePath()); + return false; + } + } + File walletFile = Helper.getWalletFile(this, walletName); + File backupFile = new File(backupFolder, walletName); + Log.d(TAG, "backup " + walletFile.getAbsolutePath() + " to " + backupFile.getAbsolutePath()); + if (copyWallet(walletFile, backupFile, true)) { + Toast.makeText(this, getString(R.string.backup_success), Toast.LENGTH_SHORT).show(); + return true; + } else { + Toast.makeText(this, getString(R.string.backup_failed), Toast.LENGTH_LONG).show(); + return false; + } + } + + @Override + public void onWalletArchive(final String walletName) { + Log.d(TAG, "archive for wallet ." + walletName + "."); + + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + if (onWalletBackup(walletName)) { + if (deleteWallet(Helper.getWalletFile(LoginActivity.this, walletName))) { + Toast.makeText(LoginActivity.this, getString(R.string.archive_success), Toast.LENGTH_SHORT).show(); + reloadWalletList(); + } else { + Toast.makeText(LoginActivity.this, getString(R.string.delete_failed), Toast.LENGTH_LONG).show(); + } + } else { + Toast.makeText(LoginActivity.this, getString(R.string.backup_failed), Toast.LENGTH_LONG).show(); + } + break; + case DialogInterface.BUTTON_NEGATIVE: + // do nothing + break; + } + } + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(getString(R.string.archive_alert_message)) + .setTitle(walletName) + .setPositiveButton(getString(R.string.archive_alert_yes), dialogClickListener) + .setNegativeButton(getString(R.string.archive_alert_no), dialogClickListener) + .show(); + } + void reloadWalletList() { try { LoginFragment loginFragment = (LoginFragment) @@ -532,7 +593,7 @@ public class LoginActivity extends AppCompatActivity final File newWalletFile = new File(new File(getStorageRoot(), ".new"), name); final File walletFolder = getStorageRoot(); final File walletFile = new File(walletFolder, name); - final boolean rc = copyWallet(newWalletFile, walletFile) + final boolean rc = copyWallet(newWalletFile, walletFile, false) && (testWallet(walletFile.getAbsolutePath(), password) == Wallet.Status.Status_Ok); if (rc) { @@ -557,7 +618,7 @@ public class LoginActivity extends AppCompatActivity } boolean renameWallet(File walletFile, String newName) { - if (copyWallet(walletFile, new File(walletFile.getParentFile(), newName))) { + if (copyWallet(walletFile, new File(walletFile.getParentFile(), newName), false)) { deleteWallet(walletFile); return true; } else { @@ -565,7 +626,20 @@ public class LoginActivity extends AppCompatActivity } } - boolean copyWallet(File srcWallet, File dstWallet) { + boolean walletExists(File walletFile) { + File dir = walletFile.getParentFile(); + String name = walletFile.getName(); + boolean exists = new File(dir, name).exists(); + exists = new File(dir, name + ".keys").exists() && exists; + exists = new File(dir, name + ".address.txt").exists() && exists; + return exists; + } + + boolean copyWallet(File srcWallet, File dstWallet, boolean overwrite) { + Log.d(TAG, "src=" + srcWallet.exists() + " dst=" + dstWallet.exists()); + if (walletExists(dstWallet) && !overwrite) return false; + if (!walletExists(srcWallet)) return false; + boolean success = false; File srcDir = srcWallet.getParentFile(); String srcName = srcWallet.getName(); @@ -586,6 +660,7 @@ public class LoginActivity extends AppCompatActivity // do our best to delete as much as possible of the wallet files boolean deleteWallet(File walletFile) { + Log.d(TAG, "deleteWallet " + walletFile.getAbsolutePath()); if (!walletFile.isFile()) return false; File dir = walletFile.getParentFile(); String name = walletFile.getName(); @@ -596,12 +671,6 @@ public class LoginActivity extends AppCompatActivity } void copyFile(File src, File dst) throws IOException { - if (dst.exists()) { - throw new IOException("Destination exists!"); - } - if (!src.exists()) { - throw new IOException("Source does not exist!"); - } FileChannel inChannel = new FileInputStream(src).getChannel(); FileChannel outChannel = new FileOutputStream(dst).getChannel(); try { diff --git a/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java b/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java index 4f5f19a..80e75a3 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.os.StrictMode; +import android.support.annotation.NonNull; import android.support.design.widget.FloatingActionButton; import android.support.v4.app.Fragment; import android.util.Log; @@ -90,6 +91,10 @@ public class LoginFragment extends Fragment { void onWalletRename(String name); + boolean onWalletBackup(String name); + + void onWalletArchive(String walletName); + void onAddWallet(); void setTitle(String title); @@ -389,20 +394,25 @@ public class LoginFragment extends Fragment { public boolean onContextItemSelected(MenuItem item) { AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); String listItem = (String) listView.getItemAtPosition(info.position); + String name = nameFromListItem(listItem, !isMainNet()); + if (name == null) { + Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show(); + } switch (item.getItemId()) { case R.id.action_info: - showInfo(listItem); + showInfo(name); break; case R.id.action_receive: - showReceive(listItem); + showReceive(name); break; case R.id.action_rename: - String name = nameFromListItem(listItem, !isMainNet()); - if (name != null) { - activityCallback.onWalletRename(name); - } else { - // TODO do we say something here? - } + activityCallback.onWalletRename(name); + break; + case R.id.action_backup: + activityCallback.onWalletBackup(name); + break; + case R.id.action_archive: + activityCallback.onWalletArchive(name); break; default: return super.onContextItemSelected(item); @@ -410,37 +420,16 @@ public class LoginFragment extends Fragment { return true; } - private void showInfo(String listItem) { - if (listItem.length() <= (WALLETNAME_PREAMBLE_LENGTH)) { - Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show(); - } - - String wallet = listItem.substring(WALLETNAME_PREAMBLE_LENGTH); - String x = isMainNet() ? "4" : "9A"; - if (x.indexOf(listItem.charAt(1)) < 0) { - Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show(); - } - + private void showInfo(@NonNull String name) { checkAndSetWalletDaemon("", !isMainNet()); // just set selected net - activityCallback.onWalletDetails(wallet); + activityCallback.onWalletDetails(name); } - private boolean showReceive(String listItem) { - if (listItem.length() <= (WALLETNAME_PREAMBLE_LENGTH)) { - Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show(); - return true; - } - - String wallet = nameFromListItem(listItem, !isMainNet()); - if (wallet == null) { - Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show(); - return true; - } - + private boolean showReceive(@NonNull String name) { checkAndSetWalletDaemon("", !isMainNet()); // just set selected net - activityCallback.onWalletReceive(wallet); + activityCallback.onWalletReceive(name); return true; } diff --git a/app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java b/app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java index 49f255b..fe13852 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/ReceiveFragment.java @@ -79,8 +79,6 @@ public class ReceiveFragment extends Fragment { etPaymentId.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); - Helper.showKeyboard(getActivity()); - etPaymentId.requestFocus(); etPaymentId.setOnEditorActionListener(new TextView.OnEditorActionListener() { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) { @@ -114,7 +112,7 @@ public class ReceiveFragment extends Fragment { etAmount.setOnEditorActionListener(new TextView.OnEditorActionListener() { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) { + if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) { if (paymentIdOk() && amountOk()) { Helper.hideKeyboard(getActivity()); generateQr(); @@ -189,15 +187,18 @@ public class ReceiveFragment extends Fragment { } } - - private void show(String address) { - tvAddress.setText(address); - etPaymentId.setEnabled(true); - etAmount.setEnabled(true); - bPaymentId.setEnabled(true); - bGenerate.setEnabled(true); - hideProgress(); - generateQr(); + private void show(final String address) { + getActivity().runOnUiThread(new Runnable() { + public void run() { + tvAddress.setText(address); + etPaymentId.setEnabled(true); + etAmount.setEnabled(true); + bPaymentId.setEnabled(true); + bGenerate.setEnabled(true); + hideProgress(); + generateQr(); + } + }); } private void show(final String walletPath, final String password) { @@ -208,8 +209,9 @@ public class ReceiveFragment extends Fragment { final Wallet wallet = WalletManager.getInstance().openWallet(walletPath, password); getActivity().runOnUiThread(new Runnable() { public void run() { - show(wallet.getAddress()); + String address = wallet.getAddress(); wallet.close(); + show(address); } }); } @@ -259,6 +261,7 @@ public class ReceiveFragment extends Fragment { etAmount.setText(amount); qrCode.setImageBitmap(qr); etDummy.requestFocus(); + bGenerate.setEnabled(false); } } diff --git a/app/src/main/res/layout/gen_review_fragment.xml b/app/src/main/res/layout/gen_review_fragment.xml index 56891ac..35fc2b8 100644 --- a/app/src/main/res/layout/gen_review_fragment.xml +++ b/app/src/main/res/layout/gen_review_fragment.xml @@ -137,7 +137,6 @@ android:id="@+id/tvWalletSpendKey" android:layout_width="match_parent" android:layout_height="wrap_content" - android:selectAllOnFocus="true" android:textAlignment="center" android:textColor="@color/colorPrimaryDark" android:textIsSelectable="true" diff --git a/app/src/main/res/layout/receive_fragment.xml b/app/src/main/res/layout/receive_fragment.xml index 45f28c8..46b4c3f 100644 --- a/app/src/main/res/layout/receive_fragment.xml +++ b/app/src/main/res/layout/receive_fragment.xml @@ -90,7 +90,7 @@ android:layout_weight="7" android:enabled="false" android:hint="@string/receive_amount_hint" - android:imeOptions="actionNext" + android:imeOptions="actionDone" android:inputType="numberDecimal" android:textAlignment="textStart" android:textSize="24sp" /> diff --git a/app/src/main/res/menu/list_menu.xml b/app/src/main/res/menu/list_menu.xml index 4afeb50..d52b7a9 100644 --- a/app/src/main/res/menu/list_menu.xml +++ b/app/src/main/res/menu/list_menu.xml @@ -3,14 +3,24 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5a8273a..7bad371 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4,8 +4,16 @@ Wallet Details - Receive + QR Receive Rename + Archive + Backup + + Backup successful + Backup failed! + Archive successful + Delete failed! + Rename failed! [<user>:<pass>@]<daemon>[:<port>] Net Selection @@ -166,6 +174,10 @@ I\'m safe Take me back! + The wallet will be backuped up and then deleted! + Yes, do that! + No thanks! + 999999.999999999999