From 1817b5bb8679a229a2403ac19ce11253a299a190 Mon Sep 17 00:00:00 2001 From: JunZhang Date: Tue, 26 May 2020 12:52:37 +0800 Subject: [PATCH] Btc only dev (#16) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix navigation issue * use 🎲 to produce mnemonic --- .../ui/fragment/TabletQrcodeFragment.java | 20 +- .../setup/ConfirmMnemonicFragment.java | 2 +- .../setup/GenerateMnemonicFragment.java | 35 +- .../fragment/setup/RollingDiceFragment.java | 327 ++++++++++++++++++ .../setup/RollingDiceGuideFragment.java | 43 +++ .../cobo/cold/ui/modal/SecretModalDialog.java | 11 + .../java/com/cobo/cold/util/HashUtil.java | 11 + .../cold/viewmodel/SetupVaultViewModel.java | 18 +- app/src/main/res/drawable-xhdpi/delete.png | Bin 0 -> 1195 bytes app/src/main/res/drawable-xhdpi/dice.png | Bin 0 -> 19583 bytes app/src/main/res/drawable/dice_button_bg.xml | 22 ++ .../res/drawable/dice_button_bg_normal.xml | 23 ++ .../res/drawable/dice_button_bg_pressed.xml | 23 ++ .../res/drawable/dice_delete_button_bg.xml | 22 ++ .../drawable/dice_delete_button_bg_normal.xml | 22 ++ .../dice_delete_button_bg_pressed.xml | 23 ++ app/src/main/res/drawable/dice_rect.xml | 21 ++ app/src/main/res/layout/dice_grid_item.xml | 66 ++++ .../main/res/layout/modal_with_two_button.xml | 99 ++++++ app/src/main/res/layout/rolling_dice.xml | 188 ++++++++++ .../main/res/layout/rolling_dice_guide.xml | 82 +++++ app/src/main/res/layout/tablet_qrcode.xml | 27 +- .../main/res/navigation/nav_graph_setup.xml | 33 ++ app/src/main/res/values-zh-rCN/strings.xml | 8 + app/src/main/res/values/strings.xml | 9 + 25 files changed, 1093 insertions(+), 42 deletions(-) create mode 100644 app/src/main/java/com/cobo/cold/ui/fragment/setup/RollingDiceFragment.java create mode 100644 app/src/main/java/com/cobo/cold/ui/fragment/setup/RollingDiceGuideFragment.java create mode 100644 app/src/main/res/drawable-xhdpi/delete.png create mode 100644 app/src/main/res/drawable-xhdpi/dice.png create mode 100644 app/src/main/res/drawable/dice_button_bg.xml create mode 100644 app/src/main/res/drawable/dice_button_bg_normal.xml create mode 100644 app/src/main/res/drawable/dice_button_bg_pressed.xml create mode 100644 app/src/main/res/drawable/dice_delete_button_bg.xml create mode 100644 app/src/main/res/drawable/dice_delete_button_bg_normal.xml create mode 100644 app/src/main/res/drawable/dice_delete_button_bg_pressed.xml create mode 100644 app/src/main/res/drawable/dice_rect.xml create mode 100644 app/src/main/res/layout/dice_grid_item.xml create mode 100644 app/src/main/res/layout/modal_with_two_button.xml create mode 100644 app/src/main/res/layout/rolling_dice.xml create mode 100644 app/src/main/res/layout/rolling_dice_guide.xml diff --git a/app/src/main/java/com/cobo/cold/ui/fragment/TabletQrcodeFragment.java b/app/src/main/java/com/cobo/cold/ui/fragment/TabletQrcodeFragment.java index c3df5cd..8afcce4 100644 --- a/app/src/main/java/com/cobo/cold/ui/fragment/TabletQrcodeFragment.java +++ b/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 { @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); } diff --git a/app/src/main/java/com/cobo/cold/ui/fragment/setup/ConfirmMnemonicFragment.java b/app/src/main/java/com/cobo/cold/ui/fragment/setup/ConfirmMnemonicFragment.java index 0c5dff6..e5ce895 100644 --- a/app/src/main/java/com/cobo/cold/ui/fragment/setup/ConfirmMnemonicFragment.java +++ b/app/src/main/java/com/cobo/cold/ui/fragment/setup/ConfirmMnemonicFragment.java @@ -53,7 +53,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 { diff --git a/app/src/main/java/com/cobo/cold/ui/fragment/setup/GenerateMnemonicFragment.java b/app/src/main/java/com/cobo/cold/ui/fragment/setup/GenerateMnemonicFragment.java index 0163af2..e2be368 100644 --- a/app/src/main/java/com/cobo/cold/ui/fragment/setup/GenerateMnemonicFragment.java +++ b/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 { private SecretModalDialog dialog; + private boolean useDice; + private byte[] diceRolls; @Override protected int setView() { @@ -42,15 +46,35 @@ public class GenerateMnemonicFragment extends SetupVaultBaseFragment 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 { + viewModel.getMnemonic().observe(this, s -> { if (TextUtils.isEmpty(s)) { return; } @@ -89,12 +113,11 @@ public class GenerateMnemonicFragment extends SetupVaultBaseFragment. + */ + +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 { + + 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 { + + @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 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()); + } + } +} diff --git a/app/src/main/java/com/cobo/cold/ui/fragment/setup/RollingDiceGuideFragment.java b/app/src/main/java/com/cobo/cold/ui/fragment/setup/RollingDiceGuideFragment.java new file mode 100644 index 0000000..703f713 --- /dev/null +++ b/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 . + */ + +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 { + @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) { + + } +} diff --git a/app/src/main/java/com/cobo/cold/ui/modal/SecretModalDialog.java b/app/src/main/java/com/cobo/cold/ui/modal/SecretModalDialog.java index 39202a2..293d173 100644 --- a/app/src/main/java/com/cobo/cold/ui/modal/SecretModalDialog.java +++ b/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) { diff --git a/app/src/main/java/com/cobo/cold/util/HashUtil.java b/app/src/main/java/com/cobo/cold/util/HashUtil.java index 867ed6e..44109be 100644 --- a/app/src/main/java/com/cobo/cold/util/HashUtil.java +++ b/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"); diff --git a/app/src/main/java/com/cobo/cold/viewmodel/SetupVaultViewModel.java b/app/src/main/java/com/cobo/cold/viewmodel/SetupVaultViewModel.java index 00381bb..7e069ae 100644 --- a/app/src/main/java/com/cobo/cold/viewmodel/SetupVaultViewModel.java +++ b/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 webAuthCode = new ObservableField<>(""); private final ObservableField mnemonicCount = new ObservableField<>(24); private final MutableLiveData vaultCreateState = new MutableLiveData<>(VAULT_STATE_NOT_CREATE); - private final MutableLiveData randomMnemonic = new MutableLiveData<>(""); + private final MutableLiveData 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 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 getMnemonic() { + return mnemonic; } public void presetData(List coins, final Runnable onComplete) { diff --git a/app/src/main/res/drawable-xhdpi/delete.png b/app/src/main/res/drawable-xhdpi/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..9d02487c9f685de963699beff645576e45db0fcf GIT binary patch literal 1195 zcmV;c1XTNpP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91K%fHv1ONa40RR91EC2ui02-6n`~Uz16-h)vRA>d=T04#tK@jx<5djh* z$ibe3jX3}!ASNK-A{>E(5UjKrNL&Dk6L0}U25agy^P1|O>Q8xkMz&kBtGj;hRn33w zt6e${=`vlJ#)p#+j8|&@UFP4W^-R1LjhSuc2?f*ASdDxtUU1N#w~Pd?H9|(qNT?vW zU2uE8!UWfv_aBU<6uEmoI zZ>zD>Ar{h80P!U3KX_Oi@uh)r)c1^p00ML+Jqh50Rx=Sh*PDlNGpybOvp}aJ5YT5L z#^a2{6AYX{XtiMxAlN2Ec>X1*CF%1+jOfV7@!XT_gE;?^4|kp=@~h+to0;3XMFji7 z@C%IOtnC7klRhdQNA0r7CkaOf(TVEN;8n*XjNF99&^5sUS|zYHc$L5w;6(yna9nb6 zJ;(plT?4#tKx9#x<~uxIGYFy;jB$rA}Yk-)g{pijP< zgr|szc{36Cd;~Z{a1+9WdUMcjN%{vH7rntcA=~aHLClcrm3&j-Awh6%bG9ArI8#+RA|E6JB)7zN5a&36MOGBrJj^7frTrzlbUvsxiu8+H?(l~1wY5~uE6 zu+$K%a5Mt?Qye__*^sW2fK|x36|QSw@s!%uoS$>yERKa!QeTyqP&f-@;gr;y@{$T? zfh?So`b2I~IBu6oqIKfT`Lu4elVY+3F)0%>9!&DfS&Lkfz_GvsOA9M69HbG`df2Ja zVBwU}_f}?95(os=9#)Zfyws1FBl+kWF%RQLzO`Y=1NxNGEzpR(XmEmV;;%^1`6XU4A7K~^hZt}3j@g6W1{uk@R>A(7j9dQ5v002ov JPDHLkV1k;42$}!@ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/dice.png b/app/src/main/res/drawable-xhdpi/dice.png new file mode 100644 index 0000000000000000000000000000000000000000..56c4cf58885757218b32a587fb32f8635708521b GIT binary patch literal 19583 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 + + + + + + diff --git a/app/src/main/res/drawable/dice_button_bg_normal.xml b/app/src/main/res/drawable/dice_button_bg_normal.xml new file mode 100644 index 0000000..f25c4a0 --- /dev/null +++ b/app/src/main/res/drawable/dice_button_bg_normal.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dice_button_bg_pressed.xml b/app/src/main/res/drawable/dice_button_bg_pressed.xml new file mode 100644 index 0000000..6b185a4 --- /dev/null +++ b/app/src/main/res/drawable/dice_button_bg_pressed.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dice_delete_button_bg.xml b/app/src/main/res/drawable/dice_delete_button_bg.xml new file mode 100644 index 0000000..c70184c --- /dev/null +++ b/app/src/main/res/drawable/dice_delete_button_bg.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/app/src/main/res/drawable/dice_delete_button_bg_normal.xml b/app/src/main/res/drawable/dice_delete_button_bg_normal.xml new file mode 100644 index 0000000..6991a21 --- /dev/null +++ b/app/src/main/res/drawable/dice_delete_button_bg_normal.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dice_delete_button_bg_pressed.xml b/app/src/main/res/drawable/dice_delete_button_bg_pressed.xml new file mode 100644 index 0000000..e4bd25b --- /dev/null +++ b/app/src/main/res/drawable/dice_delete_button_bg_pressed.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dice_rect.xml b/app/src/main/res/drawable/dice_rect.xml new file mode 100644 index 0000000..0c0f300 --- /dev/null +++ b/app/src/main/res/drawable/dice_rect.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/app/src/main/res/layout/dice_grid_item.xml b/app/src/main/res/layout/dice_grid_item.xml new file mode 100644 index 0000000..944126d --- /dev/null +++ b/app/src/main/res/layout/dice_grid_item.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/modal_with_two_button.xml b/app/src/main/res/layout/modal_with_two_button.xml new file mode 100644 index 0000000..b73cc7a --- /dev/null +++ b/app/src/main/res/layout/modal_with_two_button.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + +