diff --git a/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java b/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java index 5bfc9f6..399ff1c 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java +++ b/app/src/main/java/com/m2049r/xmrwallet/LoginActivity.java @@ -151,6 +151,71 @@ 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); + LayoutInflater li = LayoutInflater.from(this); + View promptsView = li.inflate(R.layout.prompt_rename, null); + + AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); + alertDialogBuilder.setView(promptsView); + + final EditText etRename = (EditText) promptsView.findViewById(R.id.etRename); + final TextView tvRenameLabel = (TextView) promptsView.findViewById(R.id.tvRenameLabel); + + tvRenameLabel.setText(getString(R.string.prompt_rename) + " " + walletFile.getName()); + + // set dialog message + alertDialogBuilder + .setCancelable(false) + .setPositiveButton("OK", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + Helper.hideKeyboardAlways(LoginActivity.this); + String newName = etRename.getText().toString(); + renameWallet(walletFile, newName); //TODO error + reloadWalletList(); + } + }) + .setNegativeButton("Cancel", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + Helper.hideKeyboardAlways(LoginActivity.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)) || (actionId == EditorInfo.IME_ACTION_DONE)) { + Helper.hideKeyboardAlways(LoginActivity.this); + String newName = etRename.getText().toString(); + dialog.cancel(); + renameWallet(walletFile, newName); //TODO error + reloadWalletList(); + return false; + } + return false; + } + }); + + dialog.show(); + } + + void reloadWalletList() { + try { + LoginFragment loginFragment = (LoginFragment) + getSupportFragmentManager().findFragmentById(R.id.fragment_container); + loginFragment.loadList(); + } catch (ClassCastException ex) { + } + } + @Override public void onAddWallet() { startGenerateFragment(); @@ -464,18 +529,18 @@ public class LoginActivity extends AppCompatActivity @Override public void onAccept(final String name, final String password) { - final File newWalletFolder = new File(getStorageRoot(), ".new"); + final File newWalletFile = new File(new File(getStorageRoot(), ".new"), name); final File walletFolder = getStorageRoot(); - final String walletPath = new File(walletFolder, name).getAbsolutePath(); - final boolean rc = copyWallet(walletFolder, newWalletFolder, name) + final File walletFile = new File(walletFolder, name); + final boolean rc = copyWallet(newWalletFile, walletFile) && - (testWallet(walletPath, password) == Wallet.Status.Status_Ok); + (testWallet(walletFile.getAbsolutePath(), password) == Wallet.Status.Status_Ok); if (rc) { popFragmentStack(GENERATE_STACK); Toast.makeText(LoginActivity.this, getString(R.string.generate_wallet_created), Toast.LENGTH_SHORT).show(); } else { - Log.e(TAG, "Wallet store failed to " + walletPath); + Log.e(TAG, "Wallet store failed to " + walletFile.getAbsolutePath()); Toast.makeText(LoginActivity.this, getString(R.string.generate_wallet_create_failed_2), Toast.LENGTH_LONG).show(); } @@ -491,30 +556,54 @@ public class LoginActivity extends AppCompatActivity return status; } - boolean copyWallet(File dstDir, File srcDir, String name) { + boolean renameWallet(File walletFile, String newName) { + if (copyWallet(walletFile, new File(walletFile.getParentFile(), newName))) { + deleteWallet(walletFile); + return true; + } else { + return false; + } + } + + boolean copyWallet(File srcWallet, File dstWallet) { boolean success = false; + File srcDir = srcWallet.getParentFile(); + String srcName = srcWallet.getName(); + File dstDir = dstWallet.getParentFile(); + String dstName = dstWallet.getName(); try { - // the cache is corrupt if we recover (!!) - // the cache is ok if we immediately do a full refresh() - // recoveryheight is ignored but not on watchonly wallet ?! - find out why - // so we just ignore the cache file and rebuild it on first sync - //copyFile(dstDir, srcDir, name); - copyFile(dstDir, srcDir, name + ".keys"); - copyFile(dstDir, srcDir, name + ".address.txt"); + copyFile(new File(srcDir, srcName), new File(dstDir, dstName)); + copyFile(new File(srcDir, srcName + ".keys"), new File(dstDir, dstName + ".keys")); + copyFile(new File(srcDir, srcName + ".address.txt"), new File(dstDir, dstName + ".address.txt")); success = true; } catch (IOException ex) { Log.e(TAG, "wallet copy failed: " + ex.getMessage()); // try to rollback - new File(dstDir, name).delete(); - new File(dstDir, name + ".keys").delete(); - new File(dstDir, name + ".address.txt").delete(); + deleteWallet(dstWallet); } return success; } - void copyFile(File dstDir, File srcDir, String name) throws IOException { - FileChannel inChannel = new FileInputStream(new File(srcDir, name)).getChannel(); - FileChannel outChannel = new FileOutputStream(new File(dstDir, name)).getChannel(); + // do our best to delete as much as possible of the wallet files + boolean deleteWallet(File walletFile) { + if (!walletFile.isFile()) return false; + File dir = walletFile.getParentFile(); + String name = walletFile.getName(); + boolean success = new File(dir, name).delete(); + success = new File(dir, name + ".keys").delete() && success; + success = new File(dir, name + ".address.txt").delete() && success; + return success; + } + + 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 { inChannel.transferTo(0, inChannel.size(), outChannel); } finally { diff --git a/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java b/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java index 70c6055..4f5f19a 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java @@ -82,11 +82,13 @@ public class LoginFragment extends Fragment { File getStorageRoot(); - void onWalletSelected(final String wallet); + void onWalletSelected(String wallet); - void onWalletDetails(final String wallet); + void onWalletDetails(String wallet); - void onWalletReceive(final String wallet); + void onWalletReceive(String wallet); + + void onWalletRename(String name); void onAddWallet(); @@ -126,7 +128,7 @@ public class LoginFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - + Log.d(TAG, "onCreateView"); View view = inflater.inflate(R.layout.login_fragment, container, false); tbMainNet = (ToggleButton) view.findViewById(R.id.tbMainNet); @@ -224,31 +226,6 @@ public class LoginFragment extends Fragment { } }); -/* listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { - @Override - public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { - // Difference to opening wallet is that we don't need a daemon set - String itemValue = (String) listView.getItemAtPosition(position); - - if (itemValue.length() <= (WALLETNAME_PREAMBLE_LENGTH)) { - Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show(); - return true; - } - - String wallet = itemValue.substring(WALLETNAME_PREAMBLE_LENGTH); - String x = isMainNet() ? "4" : "9A"; - if (x.indexOf(itemValue.charAt(1)) < 0) { - Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show(); - return true; - } - - checkAndSetWalletDaemon("", !isMainNet()); // just set selected net - - activityCallback.onWalletDetails(wallet); - return true; - } - }); -*/ loadList(); return view; } @@ -262,7 +239,8 @@ public class LoginFragment extends Fragment { } } - private void loadList() { + public void loadList() { + Log.d(TAG, "loadList()"); WalletManager mgr = WalletManager.getInstance(); List walletInfos = mgr.findWallets(activityCallback.getStorageRoot()); @@ -413,31 +391,39 @@ public class LoginFragment extends Fragment { String listItem = (String) listView.getItemAtPosition(info.position); switch (item.getItemId()) { case R.id.action_info: - return showInfo(listItem); + showInfo(listItem); + break; case R.id.action_receive: - return showReceive(listItem); + showReceive(listItem); + break; + case R.id.action_rename: + String name = nameFromListItem(listItem, !isMainNet()); + if (name != null) { + activityCallback.onWalletRename(name); + } else { + // TODO do we say something here? + } + break; default: return super.onContextItemSelected(item); } + return true; } - private boolean showInfo(String listItem) { + private void showInfo(String listItem) { if (listItem.length() <= (WALLETNAME_PREAMBLE_LENGTH)) { Toast.makeText(getActivity(), getString(R.string.panic), Toast.LENGTH_LONG).show(); - return true; } 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(); - return true; } checkAndSetWalletDaemon("", !isMainNet()); // just set selected net activityCallback.onWalletDetails(wallet); - return true; } private boolean showReceive(String listItem) { @@ -446,9 +432,8 @@ public class LoginFragment extends Fragment { return true; } - String wallet = listItem.substring(WALLETNAME_PREAMBLE_LENGTH); - String x = isMainNet() ? "4" : "9A"; - if (x.indexOf(listItem.charAt(1)) < 0) { + String wallet = nameFromListItem(listItem, !isMainNet()); + if (wallet == null) { Toast.makeText(getActivity(), getString(R.string.prompt_wrong_net), Toast.LENGTH_LONG).show(); return true; } @@ -458,4 +443,13 @@ public class LoginFragment extends Fragment { activityCallback.onWalletReceive(wallet); return true; } + + private String nameFromListItem(String listItem, boolean testnet) { + String wallet = listItem.substring(WALLETNAME_PREAMBLE_LENGTH); + String x = testnet ? "9A" : "4"; + if (x.indexOf(listItem.charAt(1)) < 0) { + return null; + } + return wallet; + } } diff --git a/app/src/main/res/layout/prompt_password.xml b/app/src/main/res/layout/prompt_password.xml index 8bd5f7e..495d467 100644 --- a/app/src/main/res/layout/prompt_password.xml +++ b/app/src/main/res/layout/prompt_password.xml @@ -4,14 +4,14 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:padding="10dp" > + android:padding="10dp"> + android:inputType="textPassword"> diff --git a/app/src/main/res/layout/prompt_rename.xml b/app/src/main/res/layout/prompt_rename.xml new file mode 100644 index 0000000..5f47af1 --- /dev/null +++ b/app/src/main/res/layout/prompt_rename.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/receive_fragment.xml b/app/src/main/res/layout/receive_fragment.xml index 732cc78..45f28c8 100644 --- a/app/src/main/res/layout/receive_fragment.xml +++ b/app/src/main/res/layout/receive_fragment.xml @@ -18,6 +18,8 @@ android:layout_height="wrap_content" android:layout_marginBottom="4sp" android:layout_marginTop="4sp" + android:textIsSelectable="true" + android:selectAllOnFocus="true" android:hint="@string/send_address_hint" android:textAlignment="center" android:textSize="16sp" /> diff --git a/app/src/main/res/menu/list_menu.xml b/app/src/main/res/menu/list_menu.xml index ecc5457..4afeb50 100644 --- a/app/src/main/res/menu/list_menu.xml +++ b/app/src/main/res/menu/list_menu.xml @@ -9,4 +9,8 @@ android:id="@+id/action_receive" android:title="@string/menu_receive" /> + + \ 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 c6acb10..5a8273a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,6 +5,7 @@ Details Receive + Rename [<user>:<pass>@]<daemon>[:<port>] Net Selection @@ -25,6 +26,8 @@ I am still busy with your last wallet … + Rename + Password for Bad password! Wallet does not exists!