Browse Source

use 🎲 to produce mnemonic (#15)

* use 🎲 to produce mnemonic

* hash rolls bytes
dice
JunZhang 4 years ago
committed by GitHub
parent
commit
4db726563e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 20
      app/src/main/java/com/cobo/cold/ui/fragment/TabletQrcodeFragment.java
  2. 2
      app/src/main/java/com/cobo/cold/ui/fragment/setup/ConfirmMnemonicFragment.java
  3. 35
      app/src/main/java/com/cobo/cold/ui/fragment/setup/GenerateMnemonicFragment.java
  4. 327
      app/src/main/java/com/cobo/cold/ui/fragment/setup/RollingDiceFragment.java
  5. 43
      app/src/main/java/com/cobo/cold/ui/fragment/setup/RollingDiceGuideFragment.java
  6. 11
      app/src/main/java/com/cobo/cold/ui/modal/SecretModalDialog.java
  7. 11
      app/src/main/java/com/cobo/cold/util/HashUtil.java
  8. 18
      app/src/main/java/com/cobo/cold/viewmodel/SetupVaultViewModel.java
  9. BIN
      app/src/main/res/drawable-xhdpi/delete.png
  10. BIN
      app/src/main/res/drawable-xhdpi/dice.png
  11. 22
      app/src/main/res/drawable/dice_button_bg.xml
  12. 23
      app/src/main/res/drawable/dice_button_bg_normal.xml
  13. 23
      app/src/main/res/drawable/dice_button_bg_pressed.xml
  14. 22
      app/src/main/res/drawable/dice_delete_button_bg.xml
  15. 22
      app/src/main/res/drawable/dice_delete_button_bg_normal.xml
  16. 23
      app/src/main/res/drawable/dice_delete_button_bg_pressed.xml
  17. 21
      app/src/main/res/drawable/dice_rect.xml
  18. 66
      app/src/main/res/layout/dice_grid_item.xml
  19. 99
      app/src/main/res/layout/modal_with_two_button.xml
  20. 188
      app/src/main/res/layout/rolling_dice.xml
  21. 82
      app/src/main/res/layout/rolling_dice_guide.xml
  22. 27
      app/src/main/res/layout/tablet_qrcode.xml
  23. 33
      app/src/main/res/navigation/nav_graph_setup.xml
  24. 8
      app/src/main/res/values-zh-rCN/strings.xml
  25. 8
      app/src/main/res/values/strings.xml

20
app/src/main/java/com/cobo/cold/ui/fragment/TabletQrcodeFragment.java

@ -18,6 +18,7 @@
package com.cobo.cold.ui.fragment;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import com.cobo.cold.R;
@ -32,11 +33,24 @@ public class TabletQrcodeFragment extends BaseFragment<TabletQrcodeBinding> {
@Override
protected void init(View view) {
mBinding.toolbar.setNavigationOnClickListener(v -> navigateUp());
mBinding.qrcode.setData("https://d.cobowallet.cn/public/vault/The_Cobo_Tablet_SJ.mp4");
mBinding.next.setOnClickListener(this::next);
mBinding.next.setOnClickListener(v -> next());
mBinding.tablet.setOnClickListener(new View.OnClickListener() {
final int COUNTS = 3;
final long DURATION = 3000L;
long[] mHits = new long[COUNTS];
@Override
public void onClick(View v) {
System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1);
mHits[mHits.length - 1] = SystemClock.uptimeMillis();
if (mHits[0] >= (SystemClock.uptimeMillis() - DURATION)) {
navigate(R.id.action_to_rollingDiceGuideFragment);
}
}
});
}
private void next(View view) {
private void next() {
navigate(R.id.action_to_generateMnemonicFragment);
}

2
app/src/main/java/com/cobo/cold/ui/fragment/setup/ConfirmMnemonicFragment.java

@ -92,7 +92,7 @@ public class ConfirmMnemonicFragment extends MnemonicInputFragment {
.map(ObservableField::get)
.reduce((s1, s2) -> s1 + " " + s2)
.orElse("");
if (mnemonic.equals(viewModel.getRandomMnemonic().getValue())) {
if (mnemonic.equals(viewModel.getMnemonic().getValue())) {
viewModel.writeMnemonic(mnemonic);
mBinding.table.getWordsList().clear();
} else {

35
app/src/main/java/com/cobo/cold/ui/fragment/setup/GenerateMnemonicFragment.java

@ -17,11 +17,13 @@
package com.cobo.cold.ui.fragment.setup;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import androidx.databinding.DataBindingUtil;
import androidx.navigation.fragment.NavHostFragment;
import com.cobo.cold.R;
import com.cobo.cold.databinding.CommonModalBinding;
@ -33,6 +35,8 @@ import com.cobo.cold.ui.modal.SecretModalDialog;
public class GenerateMnemonicFragment extends SetupVaultBaseFragment<GenerateMnemonicBinding> {
private SecretModalDialog dialog;
private boolean useDice;
private byte[] diceRolls;
@Override
protected int setView() {
@ -42,15 +46,35 @@ public class GenerateMnemonicFragment extends SetupVaultBaseFragment<GenerateMne
@Override
protected void init(View view) {
super.init(view);
mBinding.toolbar.setNavigationOnClickListener(v -> navigateUp());
mBinding.toolbar.setNavigationOnClickListener(v -> onBackPress());
viewModel.setMnemonicCount(MnemonicInputTable.TWEENTYFOUR);
mBinding.table.setMnemonicNumber(MnemonicInputTable.TWEENTYFOUR);
mBinding.table.setEditable(false);
mBinding.confirmSaved.setOnClickListener(this::confirmInput);
mBinding.confirmSaved.setOnClickListener(v -> confirmInput());
Bundle bundle = getArguments();
if (bundle != null) {
useDice = bundle.getBoolean("use_dice");
diceRolls = bundle.getByteArray("dice_rolls");
}
if (useDice) {
viewModel.generateMnemonicFromDiceRolls(diceRolls);
} else {
viewModel.generateRandomMnemonic();
}
observeMnemonic();
}
private void confirmInput(View view) {
private void onBackPress() {
if (useDice) {
NavHostFragment.findNavController(this)
.popBackStack(R.id.rollingDiceGuideFragment,false);
} else {
super.navigateUp();
}
}
private void confirmInput() {
ModalDialog dialog = new ModalDialog();
CommonModalBinding binding = DataBindingUtil.inflate(LayoutInflater.from(mActivity),
R.layout.common_modal, null, false);
@ -67,7 +91,7 @@ public class GenerateMnemonicFragment extends SetupVaultBaseFragment<GenerateMne
}
private void observeMnemonic() {
viewModel.getRandomMnemonic().observe(this, s -> {
viewModel.getMnemonic().observe(this, s -> {
if (TextUtils.isEmpty(s)) {
return;
}
@ -89,12 +113,11 @@ public class GenerateMnemonicFragment extends SetupVaultBaseFragment<GenerateMne
}
mBinding.confirmSaved.setEnabled(true);
});
viewModel.generateRandomMnemonic();
}
@Override
public void onPause() {
super.onPause();
viewModel.getRandomMnemonic().removeObservers(this);
viewModel.getMnemonic().removeObservers(this);
}
}

327
app/src/main/java/com/cobo/cold/ui/fragment/setup/RollingDiceFragment.java

@ -0,0 +1,327 @@
/*
* Copyright (c) 2020 Cobo
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* in the file COPYING. If not, see <http://www.gnu.org/licenses/>.
*/
package com.cobo.cold.ui.fragment.setup;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.Adapter;
import com.cobo.cold.R;
import com.cobo.cold.databinding.CommonModalBinding;
import com.cobo.cold.databinding.ModalWithTwoButtonBinding;
import com.cobo.cold.databinding.RollingDiceBinding;
import com.cobo.cold.ui.fragment.BaseFragment;
import com.cobo.cold.ui.modal.ModalDialog;
import java.util.Arrays;
import java.util.List;
public class RollingDiceFragment extends BaseFragment<RollingDiceBinding> {
private DiceGridAdapter adapter;
private final int INIT_ROLLS = 100;
private byte[] rolls = new byte[INIT_ROLLS];
private int currentPos;
private final int numOfColumn = 10;
private OnClickListener onClickListener = v -> {
String tag = (String) v.getTag();
if (tag.equals("X")) {
if (currentPos != 0) {
currentPos--;
rolls[currentPos] = 0;
adapter.notifyItemRangeChanged(currentPos, 2, 1);
}
} else {
rolls[currentPos] = Byte.parseByte(tag);
currentPos++;
if (currentPos == rolls.length -1) {
enlarge();
adapter.notifyDataSetChanged();
} else {
adapter.notifyItemRangeChanged(currentPos - 1, 2, 1);
}
}
int first = ((GridLayoutManager)mBinding.diceGrid.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
int last = ((GridLayoutManager)mBinding.diceGrid.getLayoutManager()).findLastCompletelyVisibleItemPosition();
if (currentPos > last - numOfColumn) {
mBinding.diceGrid.smoothScrollToPosition(Math.min(currentPos + INIT_ROLLS / 2, rolls.length));
} else if(currentPos < first + numOfColumn) {
int scrollTo = (currentPos - INIT_ROLLS / 2);
if (scrollTo < 0) return;
mBinding.diceGrid.smoothScrollToPosition(currentPos - INIT_ROLLS / 2);
}
};
private void enlarge() {
byte[] enlarge = new byte[rolls.length + INIT_ROLLS];
System.arraycopy(rolls, 0, enlarge, 0, rolls.length);
rolls = enlarge;
}
@Override
protected int setView() {
return R.layout.rolling_dice;
}
@Override
protected void init(View view) {
mBinding.toolbar.setNavigationOnClickListener(v -> navigateUp());
mBinding.complete.setOnClickListener(v -> onCompleteClick());
mBinding.setOnDiceRoll(onClickListener);
setupDiceGrid();
}
private void onCompleteClick() {
if (currentPos < 50) {
ModalDialog dialog = new ModalDialog();
CommonModalBinding binding = DataBindingUtil.inflate(LayoutInflater.from(mActivity),R.layout.common_modal,
null,false);
binding.title.setText(R.string.rolling_not_enough);
binding.subTitle.setText(mActivity.getString(R.string.rolling_hint_less_than_50,currentPos));
binding.confirm.setText(R.string.know);
binding.close.setVisibility(View.GONE);
binding.confirm.setOnClickListener(v -> dialog.dismiss());
dialog.setBinding(binding);
dialog.show(mActivity.getSupportFragmentManager(),"");
} else if(currentPos < 99) {
ModalDialog dialog = new ModalDialog();
ModalWithTwoButtonBinding binding = DataBindingUtil.inflate(LayoutInflater.from(mActivity),R.layout.modal_with_two_button,
null,false);
binding.title.setText(R.string.keep_rolling);
binding.subTitle.setText(mActivity.getString(R.string.rolling_hint_less_than_99,currentPos));
binding.left.setText(R.string.confirm_rolling);
binding.left.setOnClickListener(v -> {
dialog.dismiss();
navigateToGenerateMnemonic();
});
binding.right.setText(R.string.keep_rolling);
binding.right.setOnClickListener(v -> dialog.dismiss());
dialog.setBinding(binding);
dialog.show(mActivity.getSupportFragmentManager(),"");
} else {
navigateToGenerateMnemonic();
}
}
private void navigateToGenerateMnemonic() {
Bundle data = new Bundle();
data.putByteArray("dice_rolls", Arrays.copyOfRange(rolls,0, currentPos));
data.putBoolean("use_dice", true);
navigate(R.id.action_to_generateMnemonicFragment, data);
}
private void setupDiceGrid() {
adapter = new DiceGridAdapter();
GridLayoutManager layoutManager = new GridLayoutManager(mActivity,21);
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (position % numOfColumn == 0) {
return 3;
}
return 2;
}
});
mBinding.diceGrid.setLayoutManager(layoutManager);
mBinding.diceGrid.setAdapter(adapter);
mBinding.diceGrid.addItemDecoration(new TableItemDecoration(mActivity) );
}
@Override
protected void initData(Bundle savedInstanceState) {
}
class DiceGridAdapter extends Adapter<DiceViewHolder> {
@NonNull
@Override
public DiceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mActivity).inflate(R.layout.dice_grid_item,parent,false);
return new DiceViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull DiceViewHolder holder, int position, @NonNull List<Object> payloads) {
if (payloads.isEmpty()) {
onBindViewHolder(holder, position);
} else {
int value = (int) payloads.get(0);
if (value != 0) {
if (rolls[position] != 0) {
holder.data.setText(rolls[position] + "");
} else {
holder.data.setText("");
}
}
if (currentPos == position && rolls[position] == 0) {
holder.data.setBackground(mActivity.getDrawable(R.drawable.dice_rect));
} else {
holder.data.setBackground(null);
}
}
}
@Override
public void onBindViewHolder(@NonNull DiceViewHolder holder, int position) {
holder.top.setText(String.valueOf(position + 1));
holder.left.setText(String.valueOf(position / numOfColumn + 1));
if (rolls[position] != 0) {
holder.data.setText(String.valueOf(rolls[position]));
} else {
holder.data.setText("");
}
if (position == 0) {
holder.top.setVisibility(View.VISIBLE);
holder.left.setVisibility(View.VISIBLE);
} else if(position < numOfColumn){
holder.top.setVisibility(View.VISIBLE);
holder.left.setVisibility(View.GONE);
} else if(position % numOfColumn == 0) {
holder.left.setVisibility(View.VISIBLE);
holder.top.setVisibility(View.GONE);
} else {
holder.left.setVisibility(View.GONE);
holder.top.setVisibility(View.GONE);
}
if (currentPos == position && rolls[position] == 0) {
holder.data.setBackground(mActivity.getDrawable(R.drawable.dice_rect));
} else {
holder.data.setBackground(null);
}
}
@Override
public int getItemCount() {
return rolls.length;
}
}
class DiceViewHolder extends RecyclerView.ViewHolder {
public TextView left;
public TextView top;
public TextView data;
DiceViewHolder(@NonNull View itemView) {
super(itemView);
left = itemView.findViewById(R.id.left);
top = itemView.findViewById(R.id.top);
data = itemView.findViewById(R.id.data);
}
}
class TableItemDecoration extends RecyclerView.ItemDecoration {
private final Paint mPaint;
private final int dividerWidth;
TableItemDecoration(Context context) {
mPaint = new Paint();
mPaint.setColor(context.getColor(R.color.white40));
dividerWidth = dp2px(context, 1);
mPaint.setStrokeWidth(dividerWidth);
}
@Override
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
drawHorizontal(c, parent);
drawVertical(c, parent);
}
void drawHorizontal(Canvas c, RecyclerView parent) {
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
int left = child.getLeft();
final int right = child.getRight();
final int top = child.getBottom();
if ( i % numOfColumn == 0) {
left += dp2px(mActivity,14);
}
if (i + numOfColumn >= childCount) {
c.drawLine(left, top - dividerWidth, right, top - dividerWidth, mPaint);
} else {
c.drawLine(left, top, right, top, mPaint);
}
//first row
if (i < numOfColumn) {
c.drawLine(left, child.getTop() + (dividerWidth >> 1) + dp2px(mActivity,14), right,
child.getTop() + (dividerWidth >> 1) + dp2px(mActivity,14), mPaint);
}
}
}
void drawVertical(Canvas c, RecyclerView parent) {
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
int top = child.getTop();
final int bottom = child.getBottom();
final int left = child.getRight();
if (i < numOfColumn) {
top += dp2px(mActivity,14);
}
//last column
if ((i + 1) % numOfColumn == 0) {
c.drawLine(left - dividerWidth, top,
left - dividerWidth, bottom, mPaint);
} else {
c.drawLine(left, top, left, bottom, mPaint);
}
//first column
if (i % numOfColumn == 0) {
c.drawLine(child.getLeft() + (dividerWidth >> 1) + dp2px(mActivity,14), top,
child.getLeft() + (dividerWidth >> 1) + dp2px(mActivity,14), bottom, mPaint);
}
}
}
private int dp2px(Context context, int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dp, context.getResources().getDisplayMetrics());
}
}
}

43
app/src/main/java/com/cobo/cold/ui/fragment/setup/RollingDiceGuideFragment.java

@ -0,0 +1,43 @@
/*
* Copyright (c) 2020 Cobo
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* in the file COPYING. If not, see <http://www.gnu.org/licenses/>.
*/
package com.cobo.cold.ui.fragment.setup;
import android.os.Bundle;
import android.view.View;
import com.cobo.cold.R;
import com.cobo.cold.databinding.RollingDiceGuideBinding;
import com.cobo.cold.ui.fragment.BaseFragment;
public class RollingDiceGuideFragment extends BaseFragment<RollingDiceGuideBinding> {
@Override
protected int setView() {
return R.layout.rolling_dice_guide;
}
@Override
protected void init(View view) {
mBinding.toolbar.setNavigationOnClickListener(v -> navigateUp());
mBinding.start.setOnClickListener(v -> navigate(R.id.action_to_rollingDiceFragment));
}
@Override
protected void initData(Bundle savedInstanceState) {
}
}

11
app/src/main/java/com/cobo/cold/ui/modal/SecretModalDialog.java

@ -26,6 +26,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentManager;
import com.cobo.cold.R;
import com.cobo.cold.databinding.SecretModalBinding;
@ -37,6 +38,16 @@ public class SecretModalDialog extends DialogFragment {
return new SecretModalDialog();
}
@Override
public void show(@NonNull FragmentManager manager, String tag) {
try {
manager.beginTransaction().remove(this).commit();
super.show(manager, tag);
} catch (Exception e) {
e.printStackTrace();
}
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {

11
app/src/main/java/com/cobo/cold/util/HashUtil.java

@ -66,6 +66,17 @@ public class HashUtil {
return null;
}
public static byte[] sha256(byte[] bytes) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(bytes);
return messageDigest.digest();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
public static byte[] twiceSha256(String s) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");

18
app/src/main/java/com/cobo/cold/viewmodel/SetupVaultViewModel.java

@ -40,6 +40,7 @@ import com.cobo.cold.callables.WebAuthCallable;
import com.cobo.cold.callables.WriteMnemonicCallable;
import com.cobo.cold.db.entity.AccountEntity;
import com.cobo.cold.db.entity.CoinEntity;
import com.cobo.cold.util.HashUtil;
import org.spongycastle.util.encoders.Hex;
@ -59,7 +60,7 @@ public class SetupVaultViewModel extends AndroidViewModel {
private final ObservableField<String> webAuthCode = new ObservableField<>("");
private final ObservableField<Integer> mnemonicCount = new ObservableField<>(24);
private final MutableLiveData<Integer> vaultCreateState = new MutableLiveData<>(VAULT_STATE_NOT_CREATE);
private final MutableLiveData<String> randomMnemonic = new MutableLiveData<>("");
private final MutableLiveData<String> mnemonic = new MutableLiveData<>("");
private String vaultId;
private final DataRepository mRepository;
@ -181,17 +182,22 @@ public class SetupVaultViewModel extends AndroidViewModel {
Runnable task = () -> {
String entropy = new GetRandomEntropyCallable().call();
if (!MnemonicUtils.isValidateEntropy(Hex.decode(entropy))) {
randomMnemonic.postValue("");
this.mnemonic.postValue("");
} else {
String mnemonic = Bip39.generateMnemonic(entropy);
randomMnemonic.postValue(mnemonic);
this.mnemonic.postValue(Bip39.generateMnemonic(entropy));
}
};
executor.execute(task);
}
public LiveData<String> getRandomMnemonic() {
return randomMnemonic;
public void generateMnemonicFromDiceRolls(byte[] diceRolls) {
String entropy = Hex.toHexString(Objects.requireNonNull(HashUtil.sha256(diceRolls)));
String mnemonic = Bip39.generateMnemonic(entropy);
this.mnemonic.postValue(mnemonic);
}
public LiveData<String> getMnemonic() {
return mnemonic;
}
public void presetData(List<CoinEntity> coins, final Runnable onComplete) {

BIN
app/src/main/res/drawable-xhdpi/delete.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
app/src/main/res/drawable-xhdpi/dice.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

22
app/src/main/res/drawable/dice_button_bg.xml

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2020 Cobo
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ in the file COPYING. If not, see <http://www.gnu.org/licenses/>.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/dice_button_bg_pressed" android:state_pressed="true"/>
<item android:drawable="@drawable/dice_button_bg_normal" android:state_enabled="true" />
</selector>

23
app/src/main/res/drawable/dice_button_bg_normal.xml

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2020 Cobo
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ in the file COPYING. If not, see <http://www.gnu.org/licenses/>.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ffffff" />
<corners android:radius="3dp" />
</shape>

23
app/src/main/res/drawable/dice_button_bg_pressed.xml

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2020 Cobo
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ in the file COPYING. If not, see <http://www.gnu.org/licenses/>.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#C7CDD5" />
<corners android:radius="3dp" />
</shape>

22
app/src/main/res/drawable/dice_delete_button_bg.xml

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2020 Cobo
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ in the file COPYING. If not, see <http://www.gnu.org/licenses/>.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/dice_delete_button_bg_pressed" android:state_pressed="true"/>
<item android:drawable="@drawable/dice_delete_button_bg_normal" android:state_enabled="true" />
</selector>

22
app/src/main/res/drawable/dice_delete_button_bg_normal.xml

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2020 Cobo
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ in the file COPYING. If not, see <http://www.gnu.org/licenses/>.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#92959F" />
<corners android:radius="3dp" />
</shape>

23
app/src/main/res/drawable/dice_delete_button_bg_pressed.xml

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2020 Cobo
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ in the file COPYING. If not, see <http://www.gnu.org/licenses/>.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#5C606E" />
<corners android:radius="3dp" />
</shape>

21
app/src/main/res/drawable/dice_rect.xml

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2020 Cobo
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ in the file COPYING. If not, see <http://www.gnu.org/licenses/>.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:width="1dp" android:color="@color/white"/>
</shape>

66
app/src/main/res/layout/dice_grid_item.xml

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2020 Cobo
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ in the file COPYING. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/left"
android:layout_width="14dp"
android:layout_height="28dp"
android:gravity="center"
android:textStyle="bold"
android:textSize="12sp"
android:textColor="@color/white40"
android:layout_gravity="bottom"
android:visibility="gone"
tools:text="2"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/top"
android:layout_width="28dp"
android:layout_height="14dp"
android:gravity="top|center_horizontal"
android:textStyle="bold"
android:textSize="12sp"
android:textColor="@color/white40"
android:layout_gravity="bottom"
android:visibility="gone"
tools:text="2"/>
<TextView
android:id="@+id/data"
android:layout_width="28dp"
android:layout_height="28dp"
android:gravity="center"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/white"
android:layout_gravity="bottom"
tools:text="2"/>
</LinearLayout>
</LinearLayout>

99
app/src/main/res/layout/modal_with_two_button.xml

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2020 Cobo
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ in the file COPYING. If not, see <http://www.gnu.org/licenses/>.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<RelativeLayout
android:layout_width="288dp"
android:layout_height="wrap_content"
android:background="@drawable/modal_bg">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="12dp"
android:textColor="@color/black"
android:textSize="15sp"
android:textStyle="bold" />
<TextView
android:id="@+id/sub_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_centerHorizontal="true"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="12dp"
android:gravity="center_horizontal"
android:textSize="13sp"
android:visibility="visible" />
<TextView
android:id="@+id/action_hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/sub_title"
android:layout_centerHorizontal="true"
android:layout_marginHorizontal="16dp"
android:gravity="center_horizontal"
android:textSize="13sp"
android:visibility="visible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/action_hint"
android:orientation="horizontal">
<Button
android:id="@+id/left"
style="@style/AcceptButton"
android:layout_width="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="20dp"
android:layout_weight="1"
android:background="#EBF0F5"
android:textColor="#8F95AA"
android:textStyle="bold" />
<Button
android:id="@+id/right"
style="@style/AcceptButton"
android:layout_width="0dp"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="20dp"
android:layout_weight="1"
android:textStyle="bold" />
</LinearLayout>
</RelativeLayout>
</FrameLayout>
</layout>

188
app/src/main/res/layout/rolling_dice.xml

@ -0,0 +1,188 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2020 Cobo
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ in the file COPYING. If not, see <http://www.gnu.org/licenses/>.
-->
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="onDiceRoll"
type="android.view.View.OnClickListener" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:navigationIcon="@drawable/arrow_left"
app:popupTheme="@style/AppTheme.PopupOverlay">
<TextView
android:id="@+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/dice_rolls"
android:textColor="@android:color/white"
android:textSize="15sp" />
</androidx.appcompat.widget.Toolbar>
<include layout="@layout/divider" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/dice_grid"
android:layout_gravity="center"
android:layout_width="294dp"
android:layout_height="294dp"
tools:itemCount="100"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="10"
tools:listitem="@layout/dice_grid_item"/>
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginHorizontal="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_weight="1"
android:text="1"
android:tag="1"
android:gravity="center"
android:onClick="@{onDiceRoll}"
android:layout_marginHorizontal="6dp"
android:background="@drawable/dice_button_bg"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/black"/>
<TextView
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_weight="1"
android:text="2"
android:tag="2"
android:gravity="center"
android:onClick="@{onDiceRoll}"
android:layout_marginHorizontal="6dp"
android:background="@drawable/dice_button_bg"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/black"/>
<TextView
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_weight="1"
android:text="3"
android:tag="3"
android:gravity="center"
android:onClick="@{onDiceRoll}"
android:layout_marginHorizontal="6dp"
android:background="@drawable/dice_button_bg"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/black"/>
<ImageButton
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_weight="1"
android:tag="X"
android:gravity="center"
android:onClick="@{onDiceRoll}"
android:layout_marginHorizontal="6dp"
android:src="@drawable/delete"
android:background="@drawable/dice_delete_button_bg"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/black"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="12dp"
android:layout_marginBottom="50dp"
android:layout_marginHorizontal="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_weight="1"
android:text="4"
android:tag="4"
android:gravity="center"
android:onClick="@{onDiceRoll}"
android:layout_marginHorizontal="6dp"
android:background="@drawable/dice_button_bg"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/black"/>
<TextView
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_weight="1"
android:text="5"
android:tag="5"
android:gravity="center"
android:onClick="@{onDiceRoll}"
android:layout_marginHorizontal="6dp"
android:background="@drawable/dice_button_bg"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/black"/>
<TextView
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_weight="1"
android:text="6"
android:tag="6"
android:gravity="center"
android:onClick="@{onDiceRoll}"
android:layout_marginHorizontal="6dp"
android:background="@drawable/dice_button_bg"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/black"/>
<TextView
android:id="@+id/complete"
android:layout_width="0dp"
android:layout_height="46dp"
android:layout_weight="1"
android:text="@string/complete"
android:gravity="center"
android:layout_marginHorizontal="6dp"
android:background="@drawable/accept_button_bg"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/white"/>
</LinearLayout>
</LinearLayout>
</layout>

82
app/src/main/res/layout/rolling_dice_guide.xml

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2020 Cobo
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ in the file COPYING. If not, see <http://www.gnu.org/licenses/>.
-->
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:navigationIcon="@drawable/arrow_left"
app:popupTheme="@style/AppTheme.PopupOverlay">
<TextView
android:id="@+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/dice_rolls"
android:textColor="@android:color/white"
android:textSize="15sp" />
</androidx.appcompat.widget.Toolbar>
<include layout="@layout/divider" />
<com.cobo.cold.ui.views.SpanedTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="10dp"
android:text="@string/dice_roll_guide"
android:textColor="@color/white" />
<ImageView
android:id="@+id/tablet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:layout_gravity="center_horizontal"
android:src="@drawable/dice"
tools:ignore="ContentDescription" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<Button
android:id="@+id/start"
style="@style/AcceptButton"
android:layout_width="match_parent"
android:layout_marginHorizontal="16dp"
android:layout_marginBottom="18dp"
android:text="@string/start" />
</LinearLayout>
</layout>

27
app/src/main/res/layout/tablet_qrcode.xml

@ -57,33 +57,8 @@
android:text="@string/mnemonic_hint"
android:textColor="@color/white" />
<com.cobo.cold.ui.views.qrcode.QrCodeView
android:id="@+id/qrcode"
android:layout_width="176dp"
android:layout_height="176dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="48dp"
android:background="@color/white"
android:padding="5dp"
android:visibility="gone"
android:keepScreenOn="true">
<ImageView
android:id="@+id/img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/generate_mnemonic"
android:visibility="visible" />
<ProgressBar
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="visible" />
</com.cobo.cold.ui.views.qrcode.QrCodeView>
<ImageView
android:id="@+id/tablet"
android:layout_width="264dp"
android:layout_height="152dp"
android:layout_marginTop="10dp"

33
app/src/main/res/navigation/nav_graph_setup.xml

@ -99,6 +99,13 @@
<action
android:id="@+id/action_to_generateMnemonicFragment"
app:destination="@id/generateMnemonicFragment" />
<action
android:id="@+id/action_to_rollingDiceGuideFragment"
app:destination="@id/rollingDiceGuideFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@android:anim/slide_in_left"
app:popExitAnim="@android:anim/slide_out_right"/>
</fragment>
<fragment
android:id="@+id/generateMnemonicFragment"
@ -187,5 +194,31 @@
app:popEnterAnim="@android:anim/slide_in_left"
app:popExitAnim="@android:anim/slide_out_right" />
</fragment>
<fragment
android:id="@+id/rollingDiceGuideFragment"
android:name="com.cobo.cold.ui.fragment.setup.RollingDiceGuideFragment"
android:label="RollingDiceGuideFragment"
tools:layout="@layout/rolling_dice_guide">
<action
android:id="@+id/action_to_rollingDiceFragment"
app:destination="@id/rollingDiceFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@android:anim/slide_in_left"
app:popExitAnim="@android:anim/slide_out_right"/>
</fragment>
<fragment
android:id="@+id/rollingDiceFragment"
android:name="com.cobo.cold.ui.fragment.setup.RollingDiceFragment"
android:label="RollingDiceFragment"
tools:layout="@layout/rolling_dice">
<action
android:id="@id/action_to_generateMnemonicFragment"
app:destination="@id/generateMnemonicFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@android:anim/slide_in_left"
app:popExitAnim="@android:anim/slide_out_right"/>
</fragment>
</navigation>

8
app/src/main/res/values-zh-rCN/strings.xml

@ -310,4 +310,12 @@
<string name="from_electrum">来自Electrum</string>
<string name="update_failed">升级失败</string>
<string name="contact_cobo_service">您可邮件联系客服:support@cobo.com\n 状态码:%s</string>
<string name="keep_rolling">继续投掷</string>
<string name="confirm_rolling">确认生成</string>
<string name="rolling_hint_less_than_99">您当前投掷的次数为%d;建议您最少投掷99次,获得256位的随机熵值。</string>
<string name="rolling_hint_less_than_50">您当前投掷的次数为%d;至少投掷50次,才能生成助记词。</string>
<string name="rolling_not_enough">投掷次数不足</string>
<string name="dice_rolls">骰子生成助记词</string>
<string name="dice_roll_guide"><![CDATA[请注意:<br><br> 1. 至少投掷50次,才能生成助记词;建议您最少投掷99次,获得256位的随机熵值;Cobo 金库不限制您的最大投掷次数。<br>2. 建议您使用<font color="#00cdc3">赌场级骰子<font/>(六个面向上的概率相同),操作过程中确保骰子在空中得到足够的翻转,且避免总是从骰子特定面朝上进行投掷。]]></string>
<string name="start">开始</string>
</resources>

8
app/src/main/res/values/strings.xml

@ -334,4 +334,12 @@
<string name="from_electrum">From Electrum</string>
<string name="update_failed">Update failed</string>
<string name="contact_cobo_service">contact us: support@cobo.com\n Status Code:%s</string>
<string name="keep_rolling">Keep it Rolling</string>
<string name="confirm_rolling">Generate</string>
<string name="rolling_hint_less_than_99">You have rolled %d times. We recommend you roll 99 times for 256-bit <entropy class=""></entropy></string>
<string name="rolling_hint_less_than_50">You have rolled %d times. You need at least 50 rolls to generate a recovery phrase.</string>
<string name="rolling_not_enough">Keep it Rolling</string>
<string name="dice_rolls">Dice Rolls</string>
<string name="dice_roll_guide"><![CDATA[How to use dice to generate keys:<br><br> 1. Roll the dice at least 50 times. Roll 99 times to obtain 256-bit entropy (recommended). There is no limit to the number of rolls you can use.<br>2. We recommend you use <font color="#00cdc3">casino dice<font/> to increase the entropy of each dice throw.]]></string>
<string name="start">Start</string>
</resources>

Loading…
Cancel
Save